Добавить Автора
Публичный аккаунт WeChat:Python数据科学
Знаю почти:Аналитик данных Python
Мы не знаем, когда WeChat стал неотъемлемой частью нас, нашего круга общения, новостей или публичных аккаунтов, за которыми мы следим, а также личной информации или конфиденциальности — все это связано друг с другом. Поскольку это так важно, если мы можем использовать сканеры для имитации входа в систему, значит ли это, что мы можем получить эту информацию и даже эффективно просматривать и управлять ею по мере необходимости. Да, все верно, все в порядке. Этот блоггер расскажет вам, как模拟登录网页版的微信
, и отобразить полученный после имитации входа в систему好友列表信息
.
Процесс входа в симуляцию WeChat более сложен.Конечно, каким бы ни был метод, то же самое верно.Мы по-прежнему используемfiddler
Инструмент захвата пакетов для имитации процесса входа в систему.
Что ж, давайте подробно объясним шаг за шагом, как добиться этого сложного процесса.
Имитация запроса на вход с помощью скрипача
Сначала мы открываем веб-версию WeChat в браузере (fiddler
Он был открыт ранее), и тогда мы увидим интерфейс QR-кода.
Затем мы используем мобильный телефон WeChat для сканирования и подтверждения, а затем выполняется вход в веб-версию WeChat.
ок, пойдем посмотримfiddler
Сообщите нам, какие пакеты захвачены. Поскольку в процессе выдается много запросов, здесь захват пакетов разбит по операциям и анализируется один за другим.
1. Откройте веб-страницу WeChat.
Захват пакета на этом шаге подобен этому, и обнаружено, чтоlogin.wx.qq.com
Две ссылки — это все, что нам нужно.
Так что нажмите, чтобы проанализировать подробно.
Первая ссылка выглядит следующим образом:get请求
, вы можете видеть, что некоторые параметры передаются в uriappid、redirect_uri、fun、lang、_
.
GET /jslogin?appid=wx782c26e4 c19acffb&redirect_uri=https%3A%2F%2Fwx.qq.com%2Fcgi-bin%2Fmmwebwx-bin%2Fwebwxnewloginpage&fun=new&lang=zh_CN&_=1520350213674 HTTP/1.1
Найден после многих царапинappid、redirect_uri、fun、lang
параметры фиксированы, а_
Это серия меняющихся чисел.Как мы упоминали в предыдущей статье о моделировании торгового центра Jingdong, на самом деле это时间戳
, если вам непонятно, вы можете просмотреть [боевой поисковый робот Python (4) | Имитация входа в торговый центр Jingdong] [1]
Зная эти параметры, можно имитировать получение и отправку.Так почему же мы моделируем этот шаг?
Это потому, что доступ к этой ссылке будет иметь следующий ответ, который содержит важную информацию, которая нам понадобится позжеuuid
(будет упомянуто в следующих шагах).
window.QRLogin.code = 200; window.QRLogin.uuid = "Idf_QdW1OQ==";
2. Смоделируйте получение QR-кода
Метод входа, предоставляемый веб-страницей WeChat, заключается в сканировании кода, и мы не можем избежать этого даже с помощью симуляции, поэтому нам также необходимо сканировать код для проверки. Вернувшись в браузер, ссылку на QR-код можно легко найти с помощью инструментов разработчика.
https://login.weixin.qq.com/qrcode/AdgAWNry-w==
Мы обнаружили, что последняя строка изменена. подожди, это иuuid
Точно так же. Да это такuuid
, используемый для обеспечения уникальности QR-кода.
Поэтому мы будем извлекать вышеuuid
После соединения с обратной стороной вы можете получить изображение QR-кода, а затем отсканировать код, чтобы подтвердить операцию.
3. Определите статус входа
Чтобы определить, успешен ли код сканирования, нам нужно использовать вторую ссылку, упомянутую выше на этом шаге.
GET /cgi-bin/mmwebwx-bin/login?loginicon=true&uuid=Idf_QdW8OQ==&tip=1&r=68288473&_=1520050213675 HTTP/1.1
Эта ссылка такжеget请求
, который также содержит некоторые параметры.
Фактически, в процессе захвата пакета обнаруживается, что пока мы не сканируем QR-код, ссылка будет отправляться повторно, пока QR-код не будет отсканирован или не истечет время ожидания.
Итак, как мы можем определить, был ли QR-код отсканирован или авторизован?
Об этом также судят по ответным данным. После анализа выясняется, что если QR-код не был отсканирован, ответ выглядит следующим образом:
window.code=408;
Но если QR-код сканируется, ответ такой:
window.code=201;window.userAvatar = .....
window.code=200;
window.redirect_uri="https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket=AaL_Xd5muLPKNVY_Hzt_uoBs@qrticket_0&uuid=gbJqPdkNSQ==&lang=zh_CN&scan=1520353803";
code=201
Указывает, что QR-код был успешно отсканирован.code=200
Указывает, что вход в систему прошел успешно.
4. Войти
После сканирования QR-кода,fiddler
Будет еще несколько новых запросов.
Возможно, вы нашли, что в предыдущем шаге есть перенаправленные URI.
GET https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket=AaL_Xd5muLPKNVY_Hzt_udBs@qrticket_0&uuid=gbJqPdfNSQ==&lang=zh_CN&scan=1520353803&fun=new&version=v2 HTTP/1.1
Определив успешный ответ на вход на предыдущем шаге, мы можем получить все параметры в ответе. Да, эти параметры можно использовать в официальном логине (即跳转链接
) запрос. Поэтому мы используем эти параметры, чтобы сделать еще один запрос на получение. Параметры переноски следующие:
Конечно, этот запрос на вход также вернет некоторые коды ответов. Коды ответов следующие:
<error>
<ret>0</ret>
<message>OK</message>
<skey>xxx</skey>
<wxsid>xxx</wxsid>
<wxuin>xxx</wxuin>
<pass_ticket>xxx</pass_ticket>
<isgrayscale>1</isgrayscale>
</error>
Еще куча параметров, это почти бесконечно. Не волнуйтесь, мы почти у цели. Чтобы получить этот ответ, нам также нужно извлечь все параметры для следующего запроса.
5. Инициализируйте синхронизацию
Ну и, наконец, последний шаг — это запрос инициализации и синхронизации WeChat.Информация об инициализации связана следующим образом:
POST https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=64629109&pass_ticket=4dU5IS9EqtXt5cIV2Gni1tKG7m2V56PXk5XI%252BdjdrIk%253D HTTP/1.1
contact
Контактные ссылки следующие:
GET https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact?pass_ticket=4dU5IS9EqtXt5cIV2Gni1tKG7m2V56PXk5XI%252BdjdrIk%253D&r=1520353806102&seq=0&skey=@crypt_a82dd73a_3885c878ae2f4590f7b2b5ee949dd1bd HTTP/1.1
Параметры в uripass_ticket,skey
Он был получен в ответе на предыдущем шаге, и его можно выполнить, отправив запрос напрямую. Из ответов по этим двум ссылкам мы можем получить реальную и полезную информацию.
Также есть ссылка на синхронный запрос, и необходимые параметры можно извлечь из ответов по двум ссылкам выше. Но пока мы можем получить нужную информацию по двум указанным выше ссылкам, поэтому нам не нужно запрашивать эту синхронную ссылку.
GEThttps://webpush.wx.qq.com/cgi-bin/mmwebwx-bin/synccheck?r=1520353806125&skey=%40crypt_a82dd73a_3885c878ae2f4590f7b2b5ee949dd1bd&sid=O2Se5s2LJzPebME2&uin=254891255&deviceid=e289448639092966&synckey=1_694936977%7C2_694936979%7C3_694936982%7C1000_1520324882&_=1520353793581 HTTP/1.1
Базовый процесс входа в систему немного сложен, поэтому блоггер обобщил блок-схему для справки.
Код
запросить фиктивное использованиеrequests
Модуль завершен, разобран с помощьюre
. Здесь следует отметить, что если операция продолжает сообщатьssl
Это неправильно, вы можете добавить это в запросverify=False
Решено путем пропуска проверки подлинности сертификата.
1. Параметры инициализации
def __init__(self):
self.session = requests.session()
self.headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 5.1; rv:33.0) Gecko/20100101 Firefox/33.0'}
self.QRImgPath = os.path.split(os.path.realpath(__file__))[0] + os.sep + 'webWeixinQr.jpg'
self.uuid = ''
self.tip = 0
self.base_uri = ''
self.redirect_uri = ''
self.skey = ''
self.wxsid = ''
self.wxuin = ''
self.pass_ticket = ''
self.deviceId = 'e000000000000000'
self.BaseRequest = {}
self.ContactList = []
self.My = []
self.SyncKey = ''
Определите класс, инициализируйте все параметры запроса экземпляра и определите путь QR-кода.
2. Запросить UUID
def getUUID(self):
url = 'https://login.weixin.qq.com/jslogin'
params = {
'appid': 'wx782c26e4c19acffb',
'redirect_uri': 'https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage',
'fun': 'new',
'lang': 'zh_CN',
'_': int(time.time() * 1000), # 时间戳
}
response = self.session.get(url, params=params)
target = response.content.decode('utf-8')
pattern = r'window.QRLogin.code = (\d+); window.QRLogin.uuid = "(\S+?)"'
ob = re.search(pattern, target) # 正则提取uuid
code = ob.group(1)
self.uuid = ob.group(2)
if code == '200': # 判断请求是否成功
return True
return False
Используйте обычный, чтобы извлечь соответствующийuuid
,пройти черезcode
Чтобы определить, успешен ли запрос, ответ выглядит следующим образом:
window.QRLogin.code = 200; window.QRLogin.uuid = "Idf_QdW1OQ==";
3. Смоделируйте получение QR-кода
def showQRImage(self):
url = 'https://login.weixin.qq.com/qrcode/' + self.uuid
response = self.session.get(url)
self.tip = 1
with open(self.QRImgPath, 'wb') as f:
f.write(response.content)
f.close()
# 打开二维码
if sys.platform.find('darwin') >= 0:
subprocess.call(['open', self.QRImgPath]) # 苹果系统
elif sys.platform.find('linux') >= 0:
subprocess.call(['xdg-open', self.QRImgPath]) # linux系统
else:
os.startfile(self.QRImgPath) # windows系统
print('请使用微信扫描二维码登录')
использоватьuuid
Запросите изображение QR-кода и автоматически откройте его в соответствии с операционной системой.
4. Определить зарегистрированные
def checkLogin(self):
url = 'https://login.weixin.qq.com/cgi-bin/mmwebwx-bin/login?tip=%s&uuid=%s&_=%s' % (
self.tip, self.uuid, int(time.time() * 1000))
response = self.session.get(url)
target = response.content.decode('utf-8')
pattern = r'window.code=(\d+);'
ob = re.search(pattern, target)
code = ob.group(1)
if code == '201': # 已扫描
print('成功扫描,请在手机上点击确认登录')
self.tip = 0
elif code == '200': # 已登录
print('正在登录中...')
regx = r'window.redirect_uri="(\S+?)";'
ob = re.search(regx, target)
self.redirect_uri = ob.group(1) + '&fun=new'
self.base_uri = self.redirect_uri[:self.redirect_uri.rfind('/')]
elif code == '408': # 超时
pass
return code
Ответ выглядит следующим образом:
window.code=200;
window.redirect_uri="https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket=AaL_Xd5muLPKNVY_Hzt_uoBs@qrticket_0&
Определите статус входа в систему на основе кода в ответе.408
: тайм-аут201
: отсканировано200
:Вошел в систему
5. Войти
def login(self):
response = self.session.get(self.redirect_uri, verify=False)
data = response.content.decode('utf-8')
doc = xml.dom.minidom.parseString(data)
root = doc.documentElement
# 提取响应中的参数
for node in root.childNodes:
if node.nodeName == 'skey':
self.skey = node.childNodes[0].data
elif node.nodeName == 'wxsid':
self.wxsid = node.childNodes[0].data
elif node.nodeName == 'wxuin':
self.wxuin = node.childNodes[0].data
elif node.nodeName == 'pass_ticket':
self.pass_ticket = node.childNodes[0].data
if not all((self.skey, self.wxsid, self.wxuin, self.pass_ticket)):
return False
self.BaseRequest = {
'Uin': int(self.wxuin),
'Sid': self.wxsid,
'Skey': self.skey,
'DeviceID': self.deviceId,
}
return True
Ссылка для входа в запрос скачка извлекается, и параметр кода ответа извлекается.Ответ выглядит следующим образом:
<error>
<ret>0</ret>
<message>OK</message>
<skey>xxx</skey>
<wxsid>xxx</wxsid>
<wxuin>xxx</wxuin>
<pass_ticket>xxx</pass_ticket>
<isgrayscale>1</isgrayscale>
</error>
6. Инициализируйте доступ к информации
def webwxinit(self):
url = self.base_uri + \
'/webwxinit?pass_ticket=%s&skey=%s&r=%s' % (
self.pass_ticket, self.skey, int(time.time() * 1000))
params = {
'BaseRequest': self.BaseRequest
}
h = self.headers
h['ContentType'] = 'application/json; charset=UTF-8'
response = self.session.post(url, data=json.dumps(params), headers=h, verify=False)
data = response.content.decode('utf-8')
print(data)
dic = json.loads(data)
self.ContactList = dic['ContactList']
self.My = dic['User']
SyncKeyList = []
for item in dic['SyncKey']['List']:
SyncKeyList.append('%s_%s' % (item['Key'], item['Val']))
self.SyncKey = '|'.join(SyncKeyList)
ErrMsg = dic['BaseResponse']['ErrMsg']
Ret = dic['BaseResponse']['Ret']
if Ret != 0:
return False
return True
Ссылка на запрос инициализации, получение данных ответа инициализации.
def webwxgetcontact(self):
url = self.base_uri + \
'/webwxgetcontact?pass_ticket=%s&skey=%s&r=%s' % (
self.pass_ticket, self.skey, int(time.time()))
h = self.headers
h['ContentType'] = 'application/json; charset=UTF-8'
response = self.session.get(url, headers=h, verify=False)
data = response.content.decode('utf-8')
# print(data)
dic = json.loads(data)
MemberList = dic['MemberList']
# 倒序遍历,不然删除的时候出问题..
SpecialUsers = ["newsapp", "fmessage", "filehelper", "weibo", "qqmail", "tmessage", "qmessage", "qqsync",
"floatbottle", "lbsapp", "shakeapp", "medianote", "qqfriend", "readerapp", "blogapp",
"facebookapp", "masssendapp",
"meishiapp", "feedsapp", "voip", "blogappweixin", "weixin", "brandsessionholder",
"weixinreminder", "wxid_novlwrv3lqwv11", "gh_22b87fa7cb3c", "officialaccounts",
"notification_messages", "wxitil", "userexperience_alarm"]
for i in range(len(MemberList) - 1, -1, -1):
Member = MemberList[i]
if Member['VerifyFlag'] & 8 != 0: # 公众号/服务号
MemberList.remove(Member)
elif Member['UserName'] in SpecialUsers: # 特殊账号
MemberList.remove(Member)
elif Member['UserName'].find('@@') != -1: # 群聊
MemberList.remove(Member)
elif Member['UserName'] == self.My['UserName']: # 自己
MemberList.remove(Member)
return MemberList
проситьcontact
ссылка для получения контактов, официальных аккаунтов, групповых чатов и личной информации. Код ответаjson
формате следующим образом:
{
"BaseResponse": {
"Ret": 0,
"ErrMsg": ""
}
,
"Count": 11,
"ContactList": [{
"Uin": 0,
"UserName": "filehelper",
"NickName": "文件传输助手",
"HeadImgUrl": "/cgi-bin/mmwebwx-bin/webwxgeticon?seq=621637626&username=filehelper&skey=@crypt_a82dd73a_7e8e1054c011e8d71d0b542f39c7db85",
"ContactFlag": 3,
"MemberCount": 0,
"MemberList": [],
"RemarkName": "",
"HideInputBarFlag": 0,
"Sex": 0,
"Signature": "",
"VerifyFlag": 0,
"OwnerUin": 0,
"PYInitial": "WJCSZS",
"PYQuanPin": "wenjianchuanshuzhushou",
"RemarkPYInitial": "",
"RemarkPYQuanPin": "",
"StarFriend": 0,
"AppAccountFlag": 0,
"Statues": 0,
"AttrStatus": 0,
"Province": "",
"City": "",
"Alias": "",
"SnsFlag": 0,
"UniFriend": 0,
"DisplayName": "",
"ChatRoomId": 0,
"KeyWord": "fil",
"EncryChatRoomId": "",
"IsOwner": 0
}
,{...}
...
В соответствии с ответной информацией в полевых операциях здесь нужно получить список друзей, поэтому количество других полей, таких как общедоступный, групповой чат, сами удаляются, оставляя только информацию о друзьях.
7. Основная функция запуска
def main(self):
if not self.getUUID():
print('获取uuid失败')
return
self.showQRImage()
time.sleep(1)
while self.checkLogin() != '200':
pass
os.remove(self.QRImgPath)
if not self.login():
print('登录失败')
return
# 登录完成, 下面查询好友
if not self.webwxinit():
print('初始化失败')
return
MemberList = self.webwxgetcontact()
print('通讯录共%s位好友' % len(MemberList))
for x in MemberList:
sex = '未知' if x['Sex'] == 0 else '男' if x['Sex'] == 1 else '女'
print('昵称:%s, 性别:%s, 备注:%s, 签名:%s' % (x['NickName'], sex, x['RemarkName'], x['Signature']))
Имитация результата входа
Список друзей выглядит следующим образом:
Конечно, список друзей — это всего лишь пример, и мы также можем просматривать и управлять другой информацией или анализировать данные.
Суммировать
В этой статье мы поделимся с вами смоделированным процессом входа в веб-версию WeChat. Хотя запрос немного сложен в процессе, пока мы его тщательно анализируем, его можно реализовать шаг за шагом. Надеюсь, это будет полезно для всех. Код был загружен на github:Связь
полный.
Обратите внимание на публичный аккаунт WeChatPythonНаука о данных,Получать120G
Учебные материалы по искусственному интеллекту.