This action will force synchronization from Zhao/wxBot, which will overwrite any changes that you have made since you forked the repository, and can not be recovered!!!
Synchronous operation will process in the background and will refresh the page when finishing processing. Please be patient.
当时的我刚刚接触Python,急需要一个既不是太复杂,也不太难理解的项目练手,然后一个偶然的机会,在github上找到了类似的项目,所有就想着自己试试看,毕竟有比较成熟的项目作为参考,遇到问题也不会太卡项目进度,然而并没有那么顺利,貌似写代码都这样,一次次的修改最后成型,所以这是一个初学者的实践项目,所以不对的地方尽可以指出,所以不喜勿喷!
r
参数的理解更多的是随机整数,网上将r
和_
都做时间戳处理,但是13位时间戳还真不多见,可能是我见识短吧_
参数,我的理解是首次是用的时间戳,后面的请求是依次加一,并不是每次的时间戳 +--------------+ +---------------+ +---------------+
| | | | | |
| Get UUID | | Get Contact | | Status Notify |
| | | | | |
+-------+------+ +-------^-------+ +-------^-------+
| | |
| +-------+ +--------+
| | |
+-------v------+ +-----+--+------+ +--------------+
| | | | | |
| Get QRCode | | Weixin Init +------> Sync Check <----+
| | | | | | |
+-------+------+ +-------^-------+ +-------+------+ |
| | | |
| | +-----------+
| | |
+-------v------+ +-------+--------+ +-------v-------+
| | Confirm Login | | | |
+------> Login +---------------> New Login Page | | Weixin Sync |
| | | | | | |
| +------+-------+ +----------------+ +---------------+
| |
|QRCode Scaned|
+-------------+
API | 获取 UUID |
---|---|
url | https://login.weixin.qq.com/jslogin |
method | POST |
data | URL Encode |
params |
appid: 应用ID fun: new 应用类型 lang: zh_CN 语言 _: 时间戳
|
返回数据(String):
window.QRLogin.code = 200; window.QRLogin.uuid = "xxx"
注:这里的appid就是在微信开放平台注册的应用的AppID。网页版微信有两个AppID,早期的是
wx782c26e4c19acffb
,在微信客户端上显示为应用名称为Web微信
;现在用的是wxeb7ec651dd0aefa9
,显示名称为微信网页版
。
API | 显示二维码 |
---|---|
url | https://login.weixin.qq.com/qrcode/{uuid} |
method | POST |
params |
t : webwx _ : 时间戳 |
API | 二维码扫描登录 |
---|---|
url | https://login.weixin.qq.com/cgi-bin/mmwebwx-bin/login |
method | GET |
params |
tip :网上解释=》【1:未扫描 0:已扫描】据我观察=》第一次tip为1,后面不管有没有扫描都变为0 uuid : 获取到的uuid _ : 时间戳(13位整型) |
返回数据(String):
window.code=xxx;
xxx:
408 登陆超时
201 扫描成功
200 确认登录
当返回200时,还会有
window.redirect_uri="https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket=xxx&uuid=xxx&lang=xxx&scan=xxx";
API | webwxnewloginpage |
---|---|
url | https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage |
method | GET |
params |
ticket : xxx uuid : xxx lang : zh_CN scan : xxx fun : new |
返回数据(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>
**核心数据点:**在这一步获取xml中的 skey
, wxsid
, wxuin
, pass_ticket
API | webwxinit |
---|---|
url | https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxinit?pass_ticket=xxx&skey=xxx&r=xxx |
method | POST |
data | JSON |
header | Content-Type: application/json; charset=UTF-8 |
params | { BaseRequest: { Uin: xxx, Sid: xxx, Skey: xxx, DeviceID: xxx, } } |
返回数据(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
后面的消息监听用。
API | webwxstatusnotify |
---|---|
url | https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxstatusnotify?lang=zh_CN&pass_ticket=xxx |
method | POST |
data | JSON |
header | ContentType: application/json; charset=UTF-8 |
params | { BaseRequest: { Uin: xxx, Sid: xxx, Skey: xxx, DeviceID: xxx }, Code: 3, FromUserName: 自己ID , ToUserName: 自己ID , ClientMsgId: 时间戳 } |
返回数据(JSON):
{
"BaseResponse": {
"Ret": 0,
"ErrMsg": ""
},
...
}
API | webwxgetcontact |
---|---|
url | https://wx.qq.com/cgi-bin/mmwebwx-bin//webwxgetcontact?pass_ticket=xxx&skey=xxx&r=xxx |
method | POST |
data | JSON |
header | ContentType: application/json; charset=UTF-8 |
返回数据(JSON):
{
"BaseResponse": {
"Ret": 0,
"ErrMsg": ""
},
"MemberCount": 334,
"MemberList": [
{
"Uin": 0,
"UserName": xxx,
"NickName": "Urinx",
"HeadImgUrl": xxx,
"ContactFlag": 3,
"MemberCount": 0,
"MemberList": [],
"RemarkName": "",
"HideInputBarFlag": 0,
"Sex": 0,
"Signature": "我是二蛋",
"VerifyFlag": 8,
"OwnerUin": 0,
"PYInitial": "URINX",
"PYQuanPin": "Urinx",
"RemarkPYInitial": "",
"RemarkPYQuanPin": "",
"StarFriend": 0,
"AppAccountFlag": 0,
"Statues": 0,
"AttrStatus": 0,
"Province": "",
"City": "",
"Alias": "Urinxs",
"SnsFlag": 0,
"UniFriend": 0,
"DisplayName": "",
"ChatRoomId": 0,
"KeyWord": "gh_",
"EncryChatRoomId": ""
},
...
],
"Seq": 0
}
API | synccheck |
---|---|
url | https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxbatchgetcontact?type=ex&r=xxx&pass_ticket=xxx |
method | POST |
data | JSON |
header | ContentType: application/json; charset=UTF-8 |
params | { BaseRequest: { Uin: xxx, Sid: xxx, Skey: xxx, DeviceID: xxx }, Count: 群数量 , List: [ { UserName: 群ID , EncryChatRoomId: "" }, ... ], } |
返回数据(String):
window.synccheck={retcode:"xxx",selector:"xxx"}
retcode:
0 正常
1100 失败/登出微信
1101 在其他地方登录了微信
selector:
0 正常
2 新的消息
7 进入/离开聊天界面
API | webwxsync |
---|---|
url | https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsync?sid=xxx&skey=xxx&pass_ticket=xxx |
method | POST |
data | JSON |
header | ContentType: application/json; charset=UTF-8 |
params | { BaseRequest: { Uin: xxx, Sid: xxx, Skey: xxx, DeviceID: xxx }, SyncKey: xxx, rr: 时间戳取反 } |
返回数据(JSON):
{
'BaseResponse': {'ErrMsg': '', 'Ret': 0},
'SyncKey': {
'Count': 7,
'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,
...
}
API | webwxsendmsg |
---|---|
url | https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?pass_ticket=xxx |
method | POST |
data | JSON |
header | ContentType: application/json; charset=UTF-8 |
params | { BaseRequest: { Uin: xxx, Sid: xxx, Skey: xxx, DeviceID: xxx }, Msg: { Type: 1 文字消息 , Content: 要发送的消息 , FromUserName: 自己ID , ToUserName: 好友ID , LocalID: 与clientMsgId相同 , ClientMsgId: 时间戳左移4位随后补上4位随机数 } } |
返回数据(JSON):
{
"BaseResponse": {
"Ret": 0,
"ErrMsg": ""
},
...
}
API | webwxsendmsgemotion |
---|---|
url | https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsendemoticon?fun=sys&f=json&pass_ticket=xxx |
method | POST |
data | JSON |
header | ContentType: application/json; charset=UTF-8 |
params | { BaseRequest: { Uin: xxx, Sid: xxx, Skey: xxx, DeviceID: xxx }, Msg: { Type: 47 emoji消息 , EmojiFlag: 2, MediaId: 表情上传后的媒体ID , FromUserName: 自己ID , ToUserName: 好友ID , LocalID: 与clientMsgId相同 , ClientMsgId: 时间戳左移4位随后补上4位随机数 } } |
API | webwxgeticon |
---|---|
url | https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxgeticon |
method | GET |
params |
seq: 数字,可为空 username: ID skey: xxx |
API | webwxgetheadimg |
---|---|
url | https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxgetheadimg |
method | GET |
params |
seq: 数字,可为空 username: 群ID skey: xxx |
API | webwxgetmsgimg |
---|---|
url | https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxgetmsgimg |
method | GET |
params |
MsgID: 消息ID type: slave 略缩图 or 为空时加载原图 skey: xxx |
API | webwxgetvideo |
---|---|
url | https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxgetvideo |
method | GET |
params |
msgid: 消息ID skey: xxx |
API | webwxgetvoice |
---|---|
url | https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxgetvoice |
method | GET |
params |
msgid: 消息ID skey: xxx |
类型 | 说明 |
---|---|
个人账号 | 以@ 开头,例如:@xxx
|
群聊 | 以@@ 开头,例如:@@xxx
|
公众号/服务号 | 以@ 开头,但其VerifyFlag & 8 != 0 VerifyFlag : 一般公众号/服务号:8 微信自家的服务号:24 微信官方账号 微信团队 :56 |
特殊账号 | 像文件传输助手之类的账号,有特殊的ID,目前已知的有:filehelper , newsapp , fmessage , weibo , qqmail , fmessage , tmessage , qmessage , qqsync , floatbottle , lbsapp , shakeapp , medianote , qqfriend , readerapp , blogapp , facebookapp , masssendapp , meishiapp , feedsapp , voip , blogappweixin , weixin , brandsessionholder , weixinreminder , officialaccounts , notification_messages , wxitil , userexperience_alarm , notification_messages
|
消息一般格式:
{
"FromUserName": "",
"ToUserName": "",
"Content": "",
"StatusNotifyUserName": "",
"ImgWidth": 0,
"PlayLength": 0,
"RecommendInfo": {...},
"StatusNotifyCode": 4,
"NewMsgId": "",
"Status": 3,
"VoiceLength": 0,
"ForwardFlag": 0,
"AppMsgType": 0,
"Ticket": "",
"AppInfo": {...},
"Url": "",
"ImgStatus": 1,
"MsgType": 1,
"ImgHeight": 0,
"MediaId": "",
"MsgId": "",
"FileName": "",
"HasProductId": 0,
"FileSize": "",
"CreateTime": 1454602196,
"SubMsgType": 0
}
MsgType | 说明 |
---|---|
1 | 文本消息 |
3 | 图片消息 |
34 | 语音消息 |
37 | VERIFYMSG |
40 | POSSIBLEFRIEND_MSG |
42 | 共享名片 |
43 | 视频通话消息 |
47 | 动画表情 |
48 | 位置消息 |
49 | 分享链接 |
50 | VOIPMSG |
51 | 微信初始化消息 |
52 | VOIPNOTIFY |
53 | VOIPINVITE |
62 | 小视频 |
9999 | SYSNOTICE |
10000 | 系统消息 |
10002 | 撤回消息 |
微信初始化消息
MsgType: 51
FromUserName: 自己ID
ToUserName: 自己ID
StatusNotifyUserName: 最近联系的联系人ID
Content:
<msg>
<op id='4'>
<username>
// 最近联系的联系人
filehelper,xxx@chatroom,wxid_xxx,xxx,...
</username>
<unreadchatlist>
<chat>
<username>
// 朋友圈
MomentsUnreadMsgStatus
</username>
<lastreadtime>
1454502365
</lastreadtime>
</chat>
</unreadchatlist>
<unreadfunctionlist>
// 未读的功能账号消息,群发助手,漂流瓶等
</unreadfunctionlist>
</op>
</msg>
文本消息
MsgType: 1
FromUserName: 发送方ID
ToUserName: 接收方ID
Content: 消息内容
图片消息
MsgType: 3
FromUserName: 发送方ID
ToUserName: 接收方ID
MsgId: 用于获取图片
Content:
<msg>
<img length="6503" hdlength="0" />
<commenturl></commenturl>
</msg>
小视频消息
MsgType: 62
FromUserName: 发送方ID
ToUserName: 接收方ID
MsgId: 用于获取小视频
Content:
<msg>
<img length="6503" hdlength="0" />
<commenturl></commenturl>
</msg>
地理位置消息
MsgType: 1
FromUserName: 发送方ID
ToUserName: 接收方ID
Content: http://weixin.qq.com/cgi-bin/redirectforward?args=xxx
// 属于文本消息,只不过内容是一个跳转到地图的链接
名片消息
MsgType: 42
FromUserName: 发送方ID
ToUserName: 接收方ID
Content:
<?xml version="1.0"?>
<msg bigheadimgurl="" smallheadimgurl="" username="" nickname="" shortpy="" alias="" imagestatus="3" scene="17" province="" city="" sign="" sex="1" certflag="0" certinfo="" brandIconUrl="" brandHomeUrl="" brandSubscriptConfigUrl="" brandFlags="0" regionCode="" />
RecommendInfo:
{
"UserName": "xxx", // ID
"Province": "xxx",
"City": "xxx",
"Scene": 17,
"QQNum": 0,
"Content": "",
"Alias": "xxx", // 微信号
"OpCode": 0,
"Signature": "",
"Ticket": "",
"Sex": 0, // 1:男, 2:女
"NickName": "xxx", // 昵称
"AttrStatus": 4293221,
"VerifyFlag": 0
}
语音消息
MsgType: 34
FromUserName: 发送方ID
ToUserName: 接收方ID
MsgId: 用于获取语音
Content:
<msg>
<voicemsg endflag="1" cancelflag="0" forwardflag="0" voiceformat="4" voicelength="1580" length="2026" bufid="216825389722501519" clientmsgid="49efec63a9774a65a932a4e5fcd4e923filehelper174_1454602489" fromusername="" />
</msg>
动画表情
MsgType: 47
FromUserName: 发送方ID
ToUserName: 接收方ID
Content:
<msg>
<emoji fromusername = "" tousername = "" type="2" idbuffer="media:0_0" md5="e68363487d8f0519c4e1047de403b2e7" len = "86235" productid="com.tencent.xin.emoticon.bilibili" androidmd5="e68363487d8f0519c4e1047de403b2e7" androidlen="86235" s60v3md5 = "e68363487d8f0519c4e1047de403b2e7" s60v3len="86235" s60v5md5 = "e68363487d8f0519c4e1047de403b2e7" s60v5len="86235" cdnurl = "http://emoji.qpic.cn/wx_emoji/eFygWtxcoMF8M0oCCsksMA0gplXAFQNpiaqsmOicbXl1OC4Tyx18SGsQ/" designerid = "" thumburl = "http://mmbiz.qpic.cn/mmemoticon/dx4Y70y9XctRJf6tKsy7FwWosxd4DAtItSfhKS0Czr56A70p8U5O8g/0" encrypturl = "http://emoji.qpic.cn/wx_emoji/UyYVK8GMlq5VnJ56a4GkKHAiaC266Y0me0KtW6JN2FAZcXiaFKccRevA/" aeskey= "a911cc2ec96ddb781b5ca85d24143642" ></emoji>
<gameext type="0" content="0" ></gameext>
</msg>
普通链接或应用分享消息
MsgType: 49
AppMsgType: 5
FromUserName: 发送方ID
ToUserName: 接收方ID
Url: 链接地址
FileName: 链接标题
Content:
<msg>
<appmsg appid="" sdkver="0">
<title></title>
<des></des>
<type>5</type>
<content></content>
<url></url>
<thumburl></thumburl>
...
</appmsg>
<appinfo>
<version></version>
<appname></appname>
</appinfo>
</msg>
音乐链接消息
MsgType: 49
AppMsgType: 3
FromUserName: 发送方ID
ToUserName: 接收方ID
Url: 链接地址
FileName: 音乐名
AppInfo: // 分享链接的应用
{
Type: 0,
AppID: wx485a97c844086dc9
}
Content:
<msg>
<appmsg appid="wx485a97c844086dc9" sdkver="0">
<title></title>
<des></des>
<action></action>
<type>3</type>
<showtype>0</showtype>
<mediatagname></mediatagname>
<messageext></messageext>
<messageaction></messageaction>
<content></content>
<contentattr>0</contentattr>
<url></url>
<lowurl></lowurl>
<dataurl>
http://ws.stream.qqmusic.qq.com/C100003i9hMt1bgui0.m4a?vkey=6867EF99F3684&guid=ffffffffc104ea2964a111cf3ff3edaf&fromtag=46
</dataurl>
<lowdataurl>
http://ws.stream.qqmusic.qq.com/C100003i9hMt1bgui0.m4a?vkey=6867EF99F3684&guid=ffffffffc104ea2964a111cf3ff3edaf&fromtag=46
</lowdataurl>
<appattach>
<totallen>0</totallen>
<attachid></attachid>
<emoticonmd5></emoticonmd5>
<fileext></fileext>
</appattach>
<extinfo></extinfo>
<sourceusername></sourceusername>
<sourcedisplayname></sourcedisplayname>
<commenturl></commenturl>
<thumburl>
http://imgcache.qq.com/music/photo/album/63/180_albumpic_143163_0.jpg
</thumburl>
<md5></md5>
</appmsg>
<fromusername></fromusername>
<scene>0</scene>
<appinfo>
<version>29</version>
<appname>摇一摇搜歌</appname>
</appinfo>
<commenturl></commenturl>
</msg>
群消息
MsgType: 1
FromUserName: @@xxx
ToUserName: @xxx
Content:
@xxx:<br/>xxx
红包消息
MsgType: 49
AppMsgType: 2001
FromUserName: 发送方ID
ToUserName: 接收方ID
Content: 未知
注:根据网页版的代码可以看到未来可能支持查看红包消息,但目前走的是系统消息,见下。
系统消息
MsgType: 10000
FromUserName: 发送方ID
ToUserName: 自己ID
Content:
"你已添加了 xxx ,现在可以开始聊天了。"
"如果陌生人主动添加你为朋友,请谨慎核实对方身份。"
"收到红包,请在手机上查看"
本项目受到以下项目的启发:
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。