工做之餘忽然對微信的網頁版的協議通訊感興趣能夠搞一波瞭解下。畢竟網頁版容易抓,靠一個瀏覽器的開發者工具的Network就開始抓包解析了。
這是我2019年03月寫的文檔。由於微信的協議可能隨時存在變更,如下內容能夠參考一波。本人爬蟲的方法很簡單,就是盡一切方法模仿被爬蟲者的行爲。
該文檔目前只寫到獲取最新消息。先記錄一波。有空更新javascript
項目地址: 楠尼瑪大帝 / wxWebR(Java版)
(這裏只說到成功登陸到微信並獲取最新消息,由於只是模仿到這裏,其餘的所有都已經清清楚楚只是看你調不調用而已了。該拿到的參數都有了)java
(這裏也只說到成功登陸到微信並獲取最新消息。其餘能夠自行去抓包或者參考其餘文檔好比碼雲參考->python版(老版本)python
API | 獲取 UUID |
---|---|
url | https://login.wx.qq.com/jslogin |
method | POST |
data | URL Encode(text/javascript) |
params | appid: 應用ID 參考:wx782c26e4c19acffb redirect_uri 轉發地址 參考:https://wx.qq.com/cgi-bin/mmw...fun: 應用類型 參考:new lang: 語言 參考:zh_CN _: 時間戳 參考:當前時間毫秒級13位數的時間戳 |
返回數據(String):git
window.QRLogin.code = 200; window.QRLogin.uuid = "xxx"
注:目前看來參數除了 _當前時間毫秒級13位數的時間戳
其餘都是固定的值。在微信給的js裏面 index_ad43596.js裏搜索API_jsLogin能夠獲得這些參數。並且大部分不理解參數均可以從這個js文件獲得答案。
顯示二維碼就不浪費時間直接就是拿第一步拿到的uuid拼接就是二維碼地址:https://login.weixin.qq.com/q...{uuid}web
API | 獲取二維碼掃描登陸狀態 |
---|---|
url | https://login.wx.qq.com/cgi-b... |
method | GET(text/javascript) |
params | tip :這個東西根據瀏覽器走的話就是第一次爲1,後面都是爲0,網上說是掃碼狀態 loginicon 參考:true uuid : 獲取到的uuid _ : 當前時間毫秒級13位數的時間戳 |
返回數據(String):json
window.code=xxx; xxx: 【未掃碼的話】 -> window.code=408; 【手機掃碼可是未登陸】 -> window.code = 201; 【手機取消登陸】 -> window.code=400; 【手機受權登陸】 -> window.code=200; 當返回200時: wechatLoginStatus:window.code=200; window.redirect_uri= "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket=XXX&uuid=XXX&lang=XXX&scan=XXX"; 當返回201時能夠獲取掃碼用戶頭像的base64數據哦(好像沒啥用)
注: 像這種成功的話獲得這種參數本身必定存起來,下一步確定要用即ticket
,lang
,uuid
,scan
API | 獲取登陸憑據 |
---|---|
url | https://wx2.qq.com/cgi-bin/mm... |
method | GET(text/plain;charset=utf-8) |
params | ticket : ticket uuid : uuid lang : lang scan : scan fun : 參考:new version 參考:v2 |
返回數據(XML):瀏覽器
<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>
核心數據點: skey
, wxsid
, wxuin
, pass_ticket
服務器
注: 切記,第三步會返回cookie,存下來,這裏這個接口會獲得cookie的。
cookie
哪裏用到我會說明的。
API | 微信初始化 |
---|---|
url | https://wx2.qq.com/cgi-bin/mm...lang &pass_ticket=pass_ticket |
method | POST |
data | JSON(application/json; charset=UTF-8) |
header | Content-Type: application/json; charset=UTF-8 |
params | { BaseRequest: { Uin: wxuin , Sid: wxsid , Skey: skey , DeviceID: xxx, } } |
注:r
這個參數是經過js的一個 ~new Date 這是一個相似二進制反轉的一個,可自行百度或者打開控制檯輸出一下就知道了。
DeviceID
這個參數是一個簡單js拼接出來的參數 "e"+(Math.random().toFixed(15)).substring(2, 17)
返回數據(JSON):微信
{ "BaseResponse": { "Ret": 0, "ErrMsg": "" }, "Count": 11, "ContactList": [...], "SyncKey": { "Count": 4, "List": [ { "Key": 1, "Val": 635705559 }, ... ] }, "User": { "Uin": xxx, "UserName": xxx, "NickName": xxx, "HeadImgUrl": xxx, "RemarkName": "", "PYInitial": "", "PYQuanPin": "", "RemarkPYInitial": "", "RemarkPYQuanPin": "", "HideInputBarFlag": 0, "StarFriend": 0, "Sex": 1, "Signature": "Apt-get install B", "AppAccountFlag": 0, "VerifyFlag": 0, "ContactFlag": 0, "WebWxPluginSwitch": 0, "HeadImgFlag": 1, "SnsFlag": 17 }, "ChatSet": xxx, "SKey": xxx, "ClientVersion": 369297683, "SystemTime": 1453124908, "GrayScale": 1, "InviteStartCount": 40, "MPSubscribeMsgCount": 2, "MPSubscribeMsgList": [...], "ClickReportInterval": 600000 }
第四步中獲取 SyncKey
, User
後面的消息監聽用。cookie
API | synccheck |
---|---|
url | https://webpush.wx2.qq.com/cg...skey &sid=wxsid &uin=wxuin &deviceid=xxx&synckey=Synckey &_=xxx |
method | POST |
data | JSON(text/javascript) |
header | ContentType: application/json; charset=UTF-8 |
params |
返回數據(String):
window.synccheck={retcode:"xxx",selector:"xxx"} retcode: 0 正常 1100 失敗/登出微信 1101 在其餘地方登陸了微信 1102 無憑據或者憑據已失效 selector: 0 正常 2 新的消息 7 進入/離開聊天界面
注: deviceid 和上面的DeviceID
這個參數是同樣的:一個簡單js拼接出來的參數 "e"+(Math.random().toFixed(15)).substring(2, 17)
咱們叫他時間戳取反
吧
_是一個當前時間毫秒級13位數的時間戳
API | webwxsync |
---|---|
url | https://wx2.qq.com/cgi-bin/mm...wxsid &skey=Skey |
method | POST |
data | JSON(text/plain) |
header | ContentType: application/json; charset=UTF-8 |
params | { BaseRequest: { Uin: User下的Uin , Sid: wxsid , Skey: skey , DeviceID: DeviceID }, SyncKey: syncKey , rr: 時間戳取反 } |
返回數據(JSON):
{ 'BaseResponse': {'ErrMsg': '', 'Ret': 0}, 'SyncKey': { 'Count': 不肯定個數, 'List': [ {'Val': 636214192, 'Key': 1}, ... ] }, 'ContinueFlag': 0, 'AddMsgCount': 1, 'AddMsgList': [ { 'FromUserName': '', 'PlayLength': 0, 'RecommendInfo': {...}, 'Content': "", 'StatusNotifyUserName': '', 'StatusNotifyCode': 5, 'Status': 3, 'VoiceLength': 0, 'ToUserName': '', 'ForwardFlag': 0, 'AppMsgType': 0, 'AppInfo': {'Type': 0, 'AppID': ''}, 'Url': '', 'ImgStatus': 1, 'MsgType': 51, 'ImgHeight': 0, 'MediaId': '', 'FileName': '', 'FileSize': '', ... }, ... ], 'ModChatRoomMemberCount': 0, 'ModContactList': [], 'DelContactList': [], 'ModChatRoomMemberList': [], 'DelContactCount': 0, ... }
注 這一塊比較要特別注意,獲得消息後發現返回的信息也是有SyncKey
這個要更新一波直接拿下來替換本身的舊的,否則第五步檢查消息是會出現問題就是刷的特別快,並且消息是不正確的。由於真正成功訪問的到是微信的請求不會當即返回,一個請求會跑的比較久至少幾十秒,由於防止瘋狂遍歷,不用擔憂由於一旦有數據返回微信服務器會馬上返回數據給你進入下一階段的循環。這一步也是比較坑的就是SyncKey
要記得更新就好了。還有一個很騷的點就是_
這個參數雖然是毫秒級的13位時間戳,可是在微信第一次獲取後他不會再去new了,就是一直+1+1;
本項目受到如下項目的啓發: