分享

【Python之路】特别篇

 highoo 2019-03-20

  文章所使用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

我们只需要改变最后一个变量 _值即可获得新的字符串序列: (这个值是当前距离林威治标准时间的毫秒)可以自行构造!

通过分割,我们就可以获得随机字符串,自己在前端页面上构造一个二维码出来.

HomeHandle
前端二维码页面

3.轮询手机端是否已经扫描二维码并确认在Web端登录

当我们还没进行扫码登录时,发现微信web网页会自动向服务器 轮询手机端是否已经扫码并且确认登录!!

每一分钟发送一次,如果没有登录,请求会返回

1
window.code=408;

扫码后为

1
window.code=201;

确认登陆后为:

1
2
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为时间戳

View Code

这一步的发送请求,使用了urllib.requests来发送,注意格式转换!

此时我们已经获得了服务端返回的部分数据.如果需要进一步获取全部信息,......如下

6.获得所有的好友列表

该请求返回了全部的用户信息.

https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact?
pass_ticket=YK57xcgn4qT0n0qoGtxvtLvsV6XXzTDka7Z9DOFAIcGDK0wtZ6GrNpGdHGIHKiiu
&r=1492592546748
&seq=0
&skey=@crypt_8226323c_fd634988b8e43769cb3b7b9fc99ca549

构造请求并发送:

获得所有信息的handler

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 

合成synckey

| 被URL编码成%7C,通过对上面的地址发送请求:,

1
res_sync = requests.get(synccheck_url,params=payloads,cookies = ALL_COOKIE_DICT)

会返回如下的字符串:

1
window.synccheck={retcode:"0",selector:"0"}

当有人发送信息给你时, :

1
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数据

View Code

9.向用户发送消息

用户主动发送消息,通过以下的URL地址:

https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg
?pass_ticket=mRfzOKMZdUAfqrZVaT7VZeroYNX6SgTtO7WzDwDXmiZvwWC0iWlln2fBuGa8oeld

上面的pass_ticket参数不再解释了,访问该URL采用POST方式,payload如以下的格式:

View Code

  BaseRequest都是授权相关的值,与上面的步骤中的值对应,Msg是对消息的描述,包括了发送人与接收人,消息内容,消息的类型(1为文本),ClientMsgId和LocalID由本地生成。rr可用当前的时间。在返回JSON结果中BaseResponse描述了发送情况,Ret为0表示发送成功。

 

 

注意:

该流程在py3环境下,使用了Tornado框架 和 requests 包 和 urllib.requests 包

urllib.requests 包 具体用法参考如下示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 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)

  

完整参考代码:

app.py
Handler
index.html
contact_list.html

 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约