文章所使用Python版本为py3.5
1.微信服务器返回一个会话ID
微信Web版本不使用用户名和密码直接登录,而是采用二维码登录,所以服务器需要首先分配一个唯一的会话ID,用来标识当前的一次登录。
通过查看网络请求我们找到了这个 二维码图片代表的随机字符串,(IcelandB9Entig==),
2.通过会话ID获得二维码
然后找到该随机字符串的来源请求
请求方式为 GET形式 , 具体连接为:
https://login.wx.qq.com/jslogin?
appid=wx782c26e4c19acffb
&redirect_uri=https%3A%2F%2Fwx.qq.com%2Fcgi-bin%2Fmmwebwx-bin%2Fwebwxnewloginpage
&fun=new&lang=zh_CN
&_=1492591577859
我们只需要改变最后一个变量 _值即可获得新的字符串序列: (这个值是当前距离林威治标准时间的毫秒)可以自行构造!
通过分割,我们就可以获得随机字符串,自己在前端页面上构造一个二维码出来.
import tornado.ioloop import tornado.web import requests import time import re import json import urllib.request,urllib.parse import random WECHAT_SESSION_ID = None WECHAT_TIMESPAN = None SESSION_ID_URL = \'https://login.wx.qq.com/jslogin?appid=wx782c26e4c19acffb&redirect_uri=https%3A%2F%2Fwx.qq.com%2Fcgi-bin%2Fmmwebwx-bin%2Fwebwxnewloginpage&fun=new&lang=zh_CN&_={0}\' class HomeHandler(tornado.web.RequestHandler): def get(self): print(\'\n--------------------\') global WECHAT_SESSION_ID global WECHAT_TIMESPAN WECHAT_TIMESPAN = str(time.time()) sesssion_url = SESSION_ID_URL.format(WECHAT_TIMESPAN) response = requests.get(sesssion_url) # 获取验证码,随机字段 WECHAT_SESSION_ID = re.split(\'=\', response.text, 2)[-1].strip().replace(\'"\', \'\').replace(\';\', \'\') print(\'Session_id : \',WECHAT_SESSION_ID) self.render(\'index.html\',session_id = WECHAT_SESSION_ID)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> body{ margin: 0; padding: 0; } .login_alt{ margin: 42px auto; text-align: center; } .image{ display: block; width: 270px; height: 270px; margin: 42px auto; } </style> </head> <body> <div class="login_alt"><h1>二维码登陆</h1></div> <img src="https://login.weixin.qq.com/qrcode/{{session_id}}" class="image"> <script src="{{ static_url(\'js/jquery-2.1.4.min.js\')}}" ></script> <script> $(function () { acquire_image(); }); function acquire_image() { $.ajax({ url:\'/login\', type:\'POST\', success:function (data) { if(data == \'200\'){ window.location.href = "/index"; } else{ acquire_image(); } }, error:function (data) { console.log(\'error\'); } }) } </script> </body> </html>
3.轮询手机端是否已经扫描二维码并确认在Web端登录
当我们还没进行扫码登录时,发现微信web网页会自动向服务器 轮询手机端是否已经扫码并且确认登录!!
每一分钟发送一次,如果没有登录,请求会返回
window.code=408;
扫码后为
window.code=201;
确认登陆后为:
window.code=200; window.redirect_uri="https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket=A_ToQqd_AFXpsrLMH6RNgi3W@qrticket_0&uuid=we6XJEZYDg==&lang=zh_CN&scan=1492592531";
需要获得其中的跳转url,对rensponse进行分割后取得。
redirect_url = re.split(\'=\', http_res_code.text, 2)[-1].strip().replace(\'"\', \'\').replace(\';\', \'\')
4.访问登录地址,获得uin和sid
在接下来的连接中,我们发现服务器发给了我们skey,sid,pass_ticket 的重要信息, 分析发现该请求的发送地址为: GET方式,
https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket=A_ToQqd_AFXpsrLMH6RNgi3W@qrticket_0&uuid=we6XJEZYDg==&lang=zh_CN&scan=1492592531
&fun=new&version=v2
发现,该请求地址为 跳转url + &fun=new&version=v2 构造而成!
直接GET发送请求,我们就拿到返回信息,发现是 xml 格式的数据!
构造一个方法方便获取我们的连接信息
def auth_analysis(self,str_xml): \'\'\' xml中取出数据,返回字典 :param http_res_ticket: :return: \'\'\' from xml.etree import ElementTree as ET root = ET.XML(str_xml) ret = {} for child in root: ret[child.tag] = child.text return ret
我们还需要获得该请求下的cookies参数,直接通过requests模块的 requests.cookies.get_dict()
# 获取xml 登录信息 user_ticket_url = redirect_url+ \'&fun=new&version=v2\' user_xml_ticket = requests.get(user_ticket_url) TICKET_COOKIR = user_xml_ticket.cookies.get_dict() ALL_COOKIE_DICT.update(TICKET_COOKIR) #记录cookies # 获取xml中信息 user_ticket_dic = self.auth_analysis(user_xml_ticket.text) USER_RESULT_DICT.update(user_ticket_dic) #记录xml中的具体信息
5.初使化微信信息
# 初始化Url : USER_INIT_URL = \'https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxinit?pass_ticket={0}&skey={1}&r={2}\'
pass_ticket,skey为上一步骤获得的xml信息树中,r为时间戳
# 初始化准备 user_init_payload = { \'BaseRequest\': { \'DeviceID\': \'e\' + repr(random.random())[2:17], \'Sid\': USER_RESULT_DICT[\'wxsid\'], \'Skey\': USER_RESULT_DICT[\'skey\'], \'Uin\': int(USER_RESULT_DICT[\'wxuin\']), } } # 初始化url user_init_url = USER_INIT_URL.format(USER_RESULT_DICT[\'pass_ticket\'],USER_RESULT_DICT[\'skey\'],int(time.time())) # payload 转换成bytes data = (json.dumps(user_init_payload)).encode() request = urllib.request.Request(url=user_init_url, data=data) request.add_header( \'ContentType\', \'application/json; charset=UTF-8\') response = urllib.request.urlopen(request) data = response.read() # 获得初始化用户数据.. obj = json.loads(data.decode(\'utf-8\')) INIT_RESULT_DICT.update(obj)
这一步的发送请求,使用了urllib.requests来发送,注意格式转换!
此时我们已经获得了服务端返回的部分数据.如果需要进一步获取全部信息,......如下
6.获得所有的好友列表
该请求返回了全部的用户信息.
https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact?
pass_ticket=YK57xcgn4qT0n0qoGtxvtLvsV6XXzTDka7Z9DOFAIcGDK0wtZ6GrNpGdHGIHKiiu
&r=1492592546748
&seq=0
&skey=@crypt_8226323c_fd634988b8e43769cb3b7b9fc99ca549
构造请求并发送:
class ContactHandler(tornado.web.RequestHandler): def get(self, *args, **kwargs): try: user_list_url = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact?pass_ticket={0}&r={1}&seq=0&skey={2}" user_list_url = user_list_url.format(USER_RESULT_DICT[\'pass_ticket\'],USER_RESULT_DICT[\'skey\'],int(time.time())) conn = requests.get(url = user_list_url , data={} , cookies=ALL_COOKIE_DICT , headers={\'contentType\':\'application/json; charset=UTF-8\',\'Referer\':\'https://wx.qq.com/?&lang=zh_CN\'}) # print(conn.encoding) # ISO-8859-1 conn.encoding = \'utf-8\' USER_LIST_DICT.update(json.loads(conn.text)) # print(USER_LIST_DICT) self.render(\'contact_list.html\', user_list_dict=USER_LIST_DICT, user=CURRENT_USER) except Exception: self.redirect(\'/login\')
7.保持与服务器的信息同步
与服务器保持同步需要在客户端做轮询,该轮询的URL如下:
https://webpush.wx2.qq.com/cgi-bin/mmwebwx-bin/synccheck?
r=1492594498787
&skey=%40crypt_8226323c_fd634988b8e43769cb3b7b9fc99ca549
&sid=mM%2BFZGbHxGcO3x93
&uin=976834800
&deviceid=e738560216565557
&synckey=1_661566297%7C2_661566394%7C3_661565574%7C11_661566180%7C13_661374753%7C201_1492594315%7C203_1492582669%7C1000_1492594202%7C1001_1492563271
&_=1492592515065
skey,sid,uin,与上面步骤的值相对应此处的synkey是上步步骤获得的同步键值,但需要按一定的规则组合成以下的字符串:
1_124125|2_452346345|3_65476547|1000_5643635
sync_data_list = [] for item in INIT_RESULT_DICT[\'SyncKey\'][\'List\']: temp = "%s_%s" % (item[\'Key\'], item[\'Val\']) sync_data_list.append(temp) sync_data_str = "|".join(sync_data_list)
| 被URL编码成%7C,通过对上面的地址发送请求:,
res_sync = requests.get(synccheck_url,params=payloads,cookies = ALL_COOKIE_DICT)
会返回如下的字符串:
window.synccheck={retcode:"0",selector:"0"}
当有人发送信息给你时, :
window.synccheck={retcode:"0",selector:"2"}
8.获得别人发来的消息
我们通过该URL地址获取发送给我们的消息:
https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsync? sid=XQvf1MmZ7W8O2BU2 &skey=@crypt_75efaa00_3afa77c01d45461eef7eac88da37f70d &pass_ticket=YArFw%252BDpJHCpRtKCTTabpe2ytETBDmYsp%252BB7ywe%252BtplmzxQZ6ohX7d14sJgjgk6T
制造相应的payload 发送GET请求,获得返回response数据
if \'selector:"2"\' in res_sync.text: fetch_msg_url = \'https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsync?sid={0}&skey={1}&pass_ticket={2}\' fetch_msg_url = fetch_msg_url.format(USER_RESULT_DICT[\'wxsid\'],USER_RESULT_DICT[\'skey\'],USER_RESULT_DICT[\'pass_ticket\']) payloads = { \'BaseRequest\': { \'DeviceID\': \'e\' + repr(random.random())[2:17], \'Sid\': USER_RESULT_DICT[\'wxsid\'], \'Skey\': USER_RESULT_DICT[\'skey\'], \'Uin\': int(USER_RESULT_DICT[\'wxuin\']), }, \'SyncKey\' : INIT_RESULT_DICT[\'SyncKey\'], \'rr\' : int(time.time()) } # payload 转换成bytes data = (json.dumps(payloads)).encode() request = urllib.request.Request(url=fetch_msg_url, data=data) request.add_header( \'ContentType\', \'application/json; charset=UTF-8\') response = urllib.request.urlopen(request) data = response.read() # 获得初始化用户数据.. res_fetch_msg_dict = json.loads(data.decode(\'utf-8\')) INIT_RESULT_DICT[\'SyncKey\'] = res_fetch_msg_dict[\'SyncKey\'] for item in res_fetch_msg_dict[\'AddMsgList\']: print(item[\'FromUserName\'], "---->", item[\'ToUserName\'], ":::::", item[\'Content\'])
9.向用户发送消息
用户主动发送消息,通过以下的URL地址:
https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg
?pass_ticket=mRfzOKMZdUAfqrZVaT7VZeroYNX6SgTtO7WzDwDXmiZvwWC0iWlln2fBuGa8oeld
上面的pass_ticket参数不再解释了,访问该URL采用POST方式,payload如以下的格式:
message = self.get_argument(\'message\') # 需要发送的信息 to_username = self.get_argument(\'username\') # 接收人的id 好友列表中获取 print(message,to_username) # send_url = \'https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?pass_ticket={0}\' send_url = send_url.format(USER_RESULT_DICT[\'pass_ticket\']) time_str = str(int(time.time())) payloads = { \'BaseRequest\': { \'DeviceID\': \'e\' + repr(random.random())[2:17], \'Sid\': USER_RESULT_DICT[\'wxsid\'], \'Skey\': USER_RESULT_DICT[\'skey\'], \'Uin\': int(USER_RESULT_DICT[\'wxuin\']), }, \'Msg\': { \'ClientMsgId\': time_str, \'Content\': message, \'FromUserName\': CURRENT_USER[\'UserName\'], # 自己的用户信息,在微信初始化时获得! \'LocalID\': time_str, \'ToUserName\': to_username, \'Type\': 1, }, \'Scene\': 0, } # payload 转换成bytes data = (json.dumps(payloads)).encode() request = urllib.request.Request(url=send_url, data=data) request.add_header( \'ContentType\', \'application/json; charset=UTF-8\') response = urllib.request.urlopen(request) data = response.read() # 获得初始化用户数据.. res_fetch_msg_dict = json.loads(data.decode(\'utf-8\')) print(res_fetch_msg_dict)
BaseRequest都是授权相关的值,与上面的步骤中的值对应,Msg是对消息的描述,包括了发送人与接收人,消息内容,消息的类型(1为文本),ClientMsgId和LocalID由本地生成。rr可用当前的时间。在返回JSON结果中BaseResponse描述了发送情况,Ret为0表示发送成功。
注意:
该流程在py3环境下,使用了Tornado框架 和 requests 包 和 urllib.requests 包
urllib.requests 包 具体用法参考如下示例:
# payload 转换成bytes
data = (json.dumps(payload)).encode()
request = urllib.request.Request(url=user_init_url, data=data)
request.add_header(
\'ContentType\', \'application/json; charset=UTF-8\')
response = urllib.request.urlopen(request)
# 获得数据
data = response.read()
obj = json.loads(data.decode(\'utf-8\'))
# 保存数据
INIT_RESULT_DICT.update(obj)
完整参考代码:
#!/usr/bin/env python # -*-coding:utf-8 -*- import tornado.ioloop import tornado.web from controllers import index settings = { \'template_path\': \'views\', # 模版路径的配置 \'static_path\' : \'static\', # 静态文件路径 } application = tornado.web.Application([ (r"/home", index.HomeHandler), (r"/login", index.LoginHandler), (r"/index", index.IndexHandler), (r"/contact_list", index.ContactHandler), (r"/msg", index.MessageGetHandler), (r"/test", index.TestHandler), ],**settings) if __name__ == "__main__": print(\'http://localhost:8888/home\') application.listen(8888) tornado.ioloop.IOLoop.instance().start()
#!/usr/bin/env python # -*-coding:utf-8 -*- import tornado.ioloop import tornado.web import requests import time import re import json import urllib.request import random import copy WECHAT_SESSION_ID = None WECHAT_TIMESPAN = None SESSION_ID_URL = \'https://login.wx.qq.com/jslogin?appid=wx782c26e4c19acffb&redirect_uri=https%3A%2F%2Fwx.qq.com%2Fcgi-bin%2Fmmwebwx-bin%2Fwebwxnewloginpage&fun=new&lang=zh_CN&_={0}\' LOGIN_URL = \'https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid={0}&tip=1&r=-1910008125&_={1}\' # 登录信息 : USER_INFO_URL = \'https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket={0}&uuid={1}&lang=zh_CN&scan=1492317317&fun=new&version=v2\' # \'https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket=A_efO6sZQDqimyL-Cybhd6G8@qrticket_0&uuid=AanPHT1H9w==&lang=zh_CN&scan=1492317317&fun=new&version=v2\' # 初始化 : USER_INIT_URL = \'https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxinit?pass_ticket={0}&skey={1}&r={2}\' # https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=-1964927750&pass_ticket=u%252BqG9nArZmFOEieyz9dA0i7f4kSKwRxnM9O5KgBtOp8Z5FSVKGKrNmTrKOBTl0Ml BASE_REQUEST_DICT = {} INIT_RESULT_DICT = {} USER_RESULT_DICT = {} CURRENT_USER = {} USER_LIST_DICT = {} ALL_COOKIE_DICT = {} class HomeHandler(tornado.web.RequestHandler): def get(self): print(\'\n--------------------\') global WECHAT_SESSION_ID global WECHAT_TIMESPAN WECHAT_TIMESPAN = str(time.time()) sesssion_url = SESSION_ID_URL.format(WECHAT_TIMESPAN) response = requests.get(sesssion_url) # 获取验证码,随机字段 WECHAT_SESSION_ID = re.split(\'=\', response.text, 2)[-1].strip().replace(\'"\', \'\').replace(\';\', \'\') print(\'Session_id : \',WECHAT_SESSION_ID) self.render(\'index.html\',session_id = WECHAT_SESSION_ID) class LoginHandler(tornado.web.RequestHandler): def auth_analysis(self,str_xml): \'\'\' xml中取出数据,返回字典 :param http_res_ticket: :return: \'\'\' from xml.etree import ElementTree as ET root = ET.XML(str_xml) ret = {} for child in root: ret[child.tag] = child.text return ret def post(self): ret_code = "201" login_url = LOGIN_URL.format(WECHAT_SESSION_ID,str(time.time())) http_res_code = requests.get(login_url) if "window.code=408" in http_res_code.text: ret_code = "408" if "window.code=200" in http_res_code.text: ret_code = "200" # 登录跳转URL redirect_url = re.split(\'=\', http_res_code.text, 2)[-1].strip().replace(\'"\', \'\').replace(\';\', \'\') print(\'200 : 跳转url\',redirect_url) code_cookie = http_res_code.cookies.get_dict() ALL_COOKIE_DICT.update(code_cookie) print(\'cookies 1 login:\', ALL_COOKIE_DICT) # 获取xml 登录信息 user_ticket_url = redirect_url+ \'&fun=new&version=v2\' user_xml_ticket = requests.get(user_ticket_url) TICKET_COOKIR = user_xml_ticket.cookies.get_dict() ALL_COOKIE_DICT.update(TICKET_COOKIR) print(\'cookies 2 xml:\',ALL_COOKIE_DICT) xml_str = user_xml_ticket.text # 获取xml中信息 user_ticket_dic = self.auth_analysis(xml_str) USER_RESULT_DICT.update(user_ticket_dic) # 初始化准备 # __init__ payload : user_init_payload = { \'BaseRequest\': { \'DeviceID\': \'e\' + repr(random.random())[2:17], \'Sid\': USER_RESULT_DICT[\'wxsid\'], \'Skey\': USER_RESULT_DICT[\'skey\'], \'Uin\': int(USER_RESULT_DICT[\'wxuin\']), } } BASE_REQUEST_DICT.update(user_init_payload) # 初始化url user_init_url = USER_INIT_URL.format(USER_RESULT_DICT[\'pass_ticket\'],USER_RESULT_DICT[\'skey\'],int(time.time())) # payload 转换成bytes data = (json.dumps(user_init_payload)).encode() request = urllib.request.Request(url=user_init_url, data=data) request.add_header( \'ContentType\', \'application/json; charset=UTF-8\') response = urllib.request.urlopen(request) data = response.read() # 获得初始化用户数据.. obj = json.loads(data.decode(\'utf-8\')) INIT_RESULT_DICT.update(obj) # print(\'response : \' ,type(obj)) # print(\'--\',INIT_RESULT_DICT) print(ret_code) self.write(ret_code) class IndexHandler(tornado.web.RequestHandler): def get(self): print(INIT_RESULT_DICT) print(\'--------------\') print(INIT_RESULT_DICT[\'SyncKey\']) try: count = INIT_RESULT_DICT[\'Count\'] sync_key = INIT_RESULT_DICT[\'SyncKey\'] system_time = INIT_RESULT_DICT[\'SystemTime\'] skey = INIT_RESULT_DICT[\'SKey\'] client_version = INIT_RESULT_DICT[\'ClientVersion\'] base_response = INIT_RESULT_DICT[\'BaseResponse\'] MPSubscribeMsgCount = INIT_RESULT_DICT[\'MPSubscribeMsgCount\'] GrayScale = INIT_RESULT_DICT[\'GrayScale\'] InviteStartCount = INIT_RESULT_DICT[\'InviteStartCount\'] MPSubscribeMsgList = INIT_RESULT_DICT[\'MPSubscribeMsgList\'] ClickReportInterval = INIT_RESULT_DICT[\'ClickReportInterval\'] contact_list = INIT_RESULT_DICT[\'ContactList\'] user = INIT_RESULT_DICT[\'User\'] CURRENT_USER.update(user) self.render(\'main.html\', user=user, contact_list=contact_list, MPSubscribeMsgList=MPSubscribeMsgList) except Exception as e: print(e) self.redirect(\'/login\') class ContactHandler(tornado.web.RequestHandler): def get(self, *args, **kwargs): try: user_list_url = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact?pass_ticket={0}&r={1}&seq=0&skey={2}" user_list_url = user_list_url.format(USER_RESULT_DICT[\'pass_ticket\'],USER_RESULT_DICT[\'skey\'],int(time.time())) # print(user_list_url) conn = requests.get(url = user_list_url , data={} , cookies=ALL_COOKIE_DICT , headers={\'contentType\':\'application/json; charset=UTF-8\',\'Referer\':\'https://wx.qq.com/?&lang=zh_CN\'}) # print(conn.encoding) # ISO-8859-1 conn.encoding = \'utf-8\' USER_LIST_DICT.update(json.loads(conn.text)) # print(USER_LIST_DICT) self.render(\'contact_list.html\', user_list_dict=USER_LIST_DICT, user=CURRENT_USER) except Exception: self.redirect(\'/login\') class MessageGetHandler(tornado.web.RequestHandler): def get(self): global INIT_RESULT_DICT synccheck_url = \'https://webpush.wx2.qq.com/cgi-bin/mmwebwx-bin/synccheck\' sync_data_list = [] for item in INIT_RESULT_DICT[\'SyncKey\'][\'List\']: temp = "%s_%s" % (item[\'Key\'], item[\'Val\']) sync_data_list.append(temp) sync_data_str = "|".join(sync_data_list) payloads = { "r" : int(time.time()), "skey" : USER_RESULT_DICT[\'skey\'], "sid" : USER_RESULT_DICT[\'wxsid\'], "uin" : USER_RESULT_DICT[\'wxuin\'], "devicedid" : \'e\' + repr(random.random())[2:17], "synckey" : sync_data_str, } res_sync = requests.get(synccheck_url,params=payloads,cookies = ALL_COOKIE_DICT) print(\'Status: \', res_sync.text) if \'selector:"2"\' in res_sync.text: fetch_msg_url = \'https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsync?sid={0}&skey={1}&pass_ticket={2}\' fetch_msg_url = fetch_msg_url.format(USER_RESULT_DICT[\'wxsid\'],USER_RESULT_DICT[\'skey\'],USER_RESULT_DICT[\'pass_ticket\']) payloads = { \'BaseRequest\': { \'DeviceID\': \'e\' + repr(random.random())[2:17], \'Sid\': USER_RESULT_DICT[\'wxsid\'], \'Skey\': USER_RESULT_DICT[\'skey\'], \'Uin\': int(USER_RESULT_DICT[\'wxuin\']), }, \'SyncKey\' : INIT_RESULT_DICT[\'SyncKey\'], \'rr\' : int(time.time()) } # payload 转换成bytes data = (json.dumps(payloads)).encode() # fetch_msg_data = copy.deepcopy(BASE_REQUEST_DICT) # fetch_msg_data[\'SyncKey\'] = INIT_RESULT_DICT[\'SyncKey\'] # fetch_msg_data[\'rr\'] = int(time.time()) request = urllib.request.Request(url=fetch_msg_url, data=data) request.add_header( \'ContentType\', \'application/json; charset=UTF-8\') response = urllib.request.urlopen(request) data = response.read() # 获得初始化用户数据.. res_fetch_msg_dict = json.loads(data.decode(\'utf-8\')) INIT_RESULT_DICT[\'SyncKey\'] = res_fetch_msg_dict[\'SyncKey\'] for item in res_fetch_msg_dict[\'AddMsgList\']: print(item[\'FromUserName\'], "---->", item[\'ToUserName\'], ":::::", item[\'Content\']) self.write("ok") def post(self, *args, **kwargs): message = self.get_argument(\'message\') to_username = self.get_argument(\'username\') print(message,to_username) # send_url = \'https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?pass_ticket={0}\' send_url = send_url.format(USER_RESULT_DICT[\'pass_ticket\']) time_str = str(int(time.time())) payloads = { \'BaseRequest\': { \'DeviceID\': \'e\' + repr(random.random())[2:17], \'Sid\': USER_RESULT_DICT[\'wxsid\'], \'Skey\': USER_RESULT_DICT[\'skey\'], \'Uin\': int(USER_RESULT_DICT[\'wxuin\']), }, \'Msg\': { \'ClientMsgId\': time_str, \'Content\': message, \'FromUserName\': CURRENT_USER[\'UserName\'], \'LocalID\': time_str, \'ToUserName\': to_username, \'Type\': 1, }, \'Scene\': 0, } # payload 转换成bytes data = (json.dumps(payloads)).encode() request = urllib.request.Request(url=send_url, data=data) request.add_header( \'ContentType\', \'application/json; charset=UTF-8\') response = urllib.request.urlopen(request) data = response.read() # 获得初始化用户数据.. res_fetch_msg_dict = json.loads(data.decode(\'utf-8\')) print(res_fetch_msg_dict) self.write(data) # self.write(\'ok\') class TestHandler(tornado.web.RequestHandler): def get(self): self.write("Hello, world 1 ") time.sleep(10) self.write("Hello, world 2 ")
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> body{ margin: 0; padding: 0; } .login_alt{ margin: 42px auto; text-align: center; } .image{ display: block; width: 270px; height: 270px; margin: 42px auto; } </style> </head> <body> <div class="login_alt"><h1>二维码登陆</h1></div> <img src="https://login.weixin.qq.com/qrcode/{{session_id}}" class="image"> <script src="{{ static_url(\'js/jquery-2.1.4.min.js\')}}" ></script> <script> $(function () { acquire_image(); }); function acquire_image() { $.ajax({ url:\'/login\', type:\'POST\', success:function (data) { if(data == \'200\'){ window.location.href = "/index"; } else{ acquire_image(); } }, error:function (data) { console.log(\'error\'); } }) } </script> </body> </html>
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <style> .pg-header{ height: 48px; background-color: #337ab7; color: white; line-height: 48px; } .container{} .menu{ float: left; width: 250px; position: absolute; top:48px; bottom: 0; left: 0; overflow: auto; background-color: black; color: white; } .menu .item{ padding: 10px 5px; } .menu .item:hover{ background-color: #337ab7; } .content{ float: left; position: absolute; left: 259px; top: 28px; right: 0; bottom: 0; overflow: auto; } .hide{ display: none; } .chat-panel{ position: relative; } .chat-panel .title{ background-color: black; height: 50px; color: white; } .chat-panel .body{ border: 1px solid black; height: 300px; } .chat-panel .footer{ height: 200px; } </style> </head> <body style="margin: 0 auto;"> <div class="pg-header"> <span>登陆用户:{{user[\'NickName\']}}</span> <img class="hide" src="https://wx.qq.com{{user[\'HeadImgUrl\']}}"> <span class="hide">{{user[\'UserName\']}}</span> </div> <div class="container"> <div class="menu"> {% for member in user_list_dict[\'MemberList\'] %} <div class="item" user-name="{{member[\'UserName\']}}" nick-name="{{member[\'NickName\']}}">{{member[\'NickName\']}}</div> {% end %} </div> <div class="content"> <div class="chat-panel hide"> <div class="title"></div> <div class="body"></div> <div class="footer"> <textarea id="message" class="msg"></textarea> <input class="send" type="button" value="发送" onclick="SendMsg();"/> <input class="send" type="button" value="sync" onclick="GetMsg();"/> </div> </div> </div> </div> <script src="{{ static_url(\'js/jquery-2.1.4.min.js\')}}" ></script> <script> $(function(){ // BindSendEvent(); GetMsg(); BindSendEvent2(); }); // USERNAME = ""; // function BindSendEvent(){ // $(".menu").delegate(\'.item\', "dblclick", function(){ // nickname = $(this).attr(\'nick-name\'); // USERNAME = $(this).attr(\'user-name\'); // $(\'.chat-panel .title\').text(nickname); // $(\'.chat-panel\').removeClass(\'hide\'); // }) // } USERNAME = ""; function BindSendEvent2() { $(".menu div").on(\'click\',function () { USERNAME = $(this).attr(\'user-name\'); var nickname = $(this).attr(\'nick-name\'); $(\'.chat-panel\').removeClass(\'hide\'); $(\'.chat-panel .title\').text(nickname); }) } function GetMsg(){ $.ajax({ url: "/msg", type: "GET", success: function (arg) { GetMsg(); } }) } function SendMsg(){ var sendMsg = $(\'#message\').val(); console.log({"username": window.USERNAME, "message": sendMsg}); $.ajax({ url: "/msg", data: {"username": window.USERNAME, "message": sendMsg}, type: "POST", success: function (arg) { console.log(arg); $(\'#message\').val(""); } }) } </script> </body> </html>