1 Star 0 Fork 121

jealous / wxBot

forked from Zhao / wxBot 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
MIT

WxBot

python DUB

当时的我刚刚接触Python,急需要一个既不是太复杂,也不太难理解的项目练手,然后一个偶然的机会,在github上找到了类似的项目,所有就想着自己试试看,毕竟有比较成熟的项目作为参考,遇到问题也不会太卡项目进度,然而并没有那么顺利,貌似写代码都这样,一次次的修改最后成型,所以这是一个初学者的实践项目,所以不对的地方尽可以指出,所以不喜勿喷!

特别提醒

  1. 在所有需要发送json的地方,请注意使用『json.dumps()』将字典转换成Json字符串,不然接口会返回空
  2. 看源代码的朋友可能会发现,我对于r参数的理解更多的是随机整数,网上将r_都做时间戳处理,但是13位时间戳还真不多见,可能是我见识短吧
  3. 对于等待扫描接口中的_参数,我的理解是首次是用的时间戳,后面的请求是依次加一,并不是每次的时间戳

执行流程

  1. 打开首页,分配一个随机uuid,
  2. 根据该uuid获取二维码图片。
  3. 微信客户端扫描该图片,在客户端确认登录。
  4. 浏览器不停的调用一个接口,如果返回登录成功,则调用登录接口
  5. 此时可以获取联系人列表,可以发送消息。然后不断调用同步接口。
  6. 如果同步接口有返回,则可以获取新消息,然后继续调用同步接口。
       +--------------+     +---------------+   +---------------+
       |              |     |               |   |               |
       |   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|
+-------------+

WebWechat API

获取UUID(参考方法 getUUID)

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,显示名称为微信网页版

显示二维码(参考方法 showQrCode)

API 显示二维码
url https://login.weixin.qq.com/qrcode/{uuid}
method POST
params t : webwx
_ : 时间戳

**注:**在代码中我们的二维码内容并不是`https://login.weixin.qq.com/qrcode/{uuid}`而是`https://login.weixin.qq.com/l/{uuid}`

等待登录(参考方法 waitForLogin)这里是微信确认登录

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";

登录获取Cookie(参考方法 login)

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 后面的消息监听用。

开启微信状态通知(参考方法 wxStatusNotify)

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": ""
	},
	...
}

获取联系人列表(参考方法 getContact)

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
}

消息检查(参考方法 syncCheck)

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 进入/离开聊天界面

获取最新消息(参考方法 webwxsync)

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&amp;guid=ffffffffc104ea2964a111cf3ff3edaf&amp;fromtag=46
			</dataurl>
			<lowdataurl>
				http://ws.stream.qqmusic.qq.com/C100003i9hMt1bgui0.m4a?vkey=6867EF99F3684&amp;guid=ffffffffc104ea2964a111cf3ff3edaf&amp;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 ,现在可以开始聊天了。"
	"如果陌生人主动添加你为朋友,请谨慎核实对方身份。"
	"收到红包,请在手机上查看"

致谢

本项目受到以下项目的启发:

The MIT License (MIT) Copyright (c) 2016 Zhao Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

简介

Python实现微信机器人 展开 收起
Python
MIT
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
Python
1
https://gitee.com/LiuJiaLuo/wxBot.git
git@gitee.com:LiuJiaLuo/wxBot.git
LiuJiaLuo
wxBot
wxBot
master

搜索帮助

14c37bed 8189591 565d56ea 8189591