简单的模拟:借用微信网页版,写个扫码页面,登录页面,实现简单的登录、联系人列表、发消息,收消息。

以下是笔记:

#!/usr/bin/env python
# coding:utf-8 from flask import Flask, render_template, request, session, jsonify,redirect,url_for
import time, re, requests, json
from bs4 import BeautifulSoup app = Flask(__name__)
app.debug = True
app.secret_key = "LSHM" # 使用session必须要有key # xml转变字典函数
def xml_parser(text):
dic = {}
soup = BeautifulSoup(text, 'html.parser')
div = soup.find(name='error') # for item in div.children(recursive=False): # 不使用children, 因为它会找文本, find_all则只找标签
for item in div.find_all(recursive=False): # 不使用递归,也就是只找儿子
dic[item.name] = item.text
return dic @app.route('/')
def home():
return redirect(url_for('login')) @app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == "GET":
ctime = str(int(time.time() * 1000))
qrcode_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&_={}".format(
ctime) ret = requests.get(qrcode_url)
# print(ret.text)
qrcode = re.findall('uuid = "(.*)";', ret.text)[0]
# print(qrcode)
session['qrcode'] = qrcode
return render_template("login.html", qr=qrcode)
else:
pass @app.route('/check_login')
def check_login():
'''
发送GET请求,检测是否已经扫码、登录
https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid=IY02Sx7eyQ==&tip=0&r=-1908176756&_=1530916511143
:return:
'''
response = {"code": 408}
qrcode = session.get("qrcode")
ctime = str(int(time.time() * 1000))
check_url = "https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid={0}&tip=0&r=-1908176756&_={1}".format(
qrcode, ctime)
# time.sleep(10)
ret = requests.get(check_url)
# print(ret.text) if "window.code=201" in ret.text: # 扫码成功
src = re.findall("window.userAvatar = '(.*)';", ret.text)[0]
response["code"] = 201
response["src"] = src
elif "window.code=200" in ret.text: # 确认登录
redirect_uri = re.findall('window.redirect_uri="(.*)";', ret.text)[0] # 获取重定向地址 # 向上面的地址发送请求, 添加2个必要的参数
redirect_uri = redirect_uri + "&fun=new&version=v2" ticket_ret = requests.get(redirect_uri) # 获取凭证
ticket_dict = xml_parser(ticket_ret.text) # 拿到字典
# print(ticket_dict)
session["ticket_dict"] = ticket_dict # 存入session
session["ticket_cookie"] = ticket_ret.cookies.get_dict() # 保存cookie 给后面使用 response["code"] = 200
return jsonify(response) @app.route("/index")
def index():
'''
用户数据初始化
https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=-1912609442&pass_ticket=v8tvMrwfudoYLl0dyHNIX5QtJe4BtO%252FGoffihP5Ion0oScWCAU%252F18Avj6ZL1rj%252B6
:return:
'''
ticket_dict = session.get("ticket_dict")
init_url = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=-1912609442&pass_ticket={0}".format(
ticket_dict.get("pass_ticket")) data_dict = {
"BaseRequest": {
"DeviceID": "e261019482970229",
"Sid": ticket_dict.get("wxsid"),
"Uin": ticket_dict.get("wxuin"),
"Skey": ticket_dict.get("skey"),
}
} init_ret = requests.post(
url=init_url,
json=data_dict, # Payload 对应传json
# data=json_dumps(data_dict), # 使用这种方式,必须要带上headers
# headers={
# 'Content-Type':'application/json'
# }
)
init_ret.encoding = "utf-8"
# print(init_ret.text)
# print(init_ret.json()) # print(json.loads(init_ret.text))
user_dict = init_ret.json()
# print(user_dict) # for user in user_dict['ContactList']: # 最近 联系人列表
# print(user.get('NickName')) session["current_user"] = user_dict['User']
# print(user_dict['SyncKey'])
session["SyncKey"] = user_dict['SyncKey'] # return "用户首页"
return render_template('index.html', user_dict=user_dict) @app.route("/get_img")
def get_img():
# 获取头像
current_user = session.get("current_user")
ticket_cookie = session.get("ticket_cookie") head_url = "https://wx.qq.com" + current_user["HeadImgUrl"]
img_ret = requests.get(head_url, cookies=ticket_cookie, headers={"Content-Type": "image/jpeg"})
return img_ret.content # 直接返回字节 @app.route("/user_list")
def user_list():
ticket_dict = session.get("ticket_dict")
ticket_cookie = session.get("ticket_cookie")
ctime = int(time.time() * 1000)
skey = ticket_dict.get('skey')
user_list_url = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact?lang=zh_CN&r={0}&seq=0&skey={1}".format(
ctime, skey) r1 = requests.get(user_list_url, cookies=ticket_cookie)
r1.encoding = "utf-8"
wx_user_dict = r1.json()
print(wx_user_dict['MemberCount'])
for item in wx_user_dict['MemberList']:
print(item) return render_template("user_list.html", wx_user_dict=wx_user_dict) ## 发消息的话:需要自己的UserName和对方的UserName
@app.route("/send", methods=["GET", "POST"])
def send():
if request.method == "GET":
return render_template('send.html') ticket_dict = session.get("ticket_dict") current_user = session["current_user"]
from_user = current_user['UserName']
to = request.form.get('to')
content = request.form.get('content')
ctime = str(time.time() * 1000)
msg_url = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?lang=zh_CN&pass_ticket={}".format(
ticket_dict['pass_ticket']) data_dict = {
"BaseRequest": {
"DeviceID": "e261019482970229",
"Sid": ticket_dict.get("wxsid"),
"Uin": ticket_dict.get("wxuin"),
"Skey": ticket_dict.get("skey"),
},
"Msg": {
"ClientMsgId": ctime,
"FromUserName": from_user,
"LocalID": ctime,
"ToUserName": to,
"Content": content,
"Type": 1
},
"Scene": 0
} ret = requests.post(
url=msg_url,
data=bytes(json.dumps(data_dict, ensure_ascii=False), encoding="utf-8")
)
print(ret.text)
response ={}
response['to'] = to
response['content'] = content
response['status'] = "成功"
return jsonify(response) @app.route("/recv", methods=["GET", "POST"])
def recv():
# https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsync?sid={0}&skey={1}&pass_ticket={2} sync_url = "https://webpush.weixin.qq.com/cgi-bin/mmwebwx-bin/synccheck" synckey = session.get("SyncKey")
# print(synckey['List'])
ticket_dict = session.get("ticket_dict")
ticket_cookie = session.get("ticket_cookie")
ctime = str(int(time.time() * 1000)) sync_data_list = []
for item in synckey['List']:
temp = "%s_%s" % (item['Key'], item['Val'])
sync_data_list.append(temp)
sync_data_str = "|".join(sync_data_list) sync_dict = {
"r": ctime,
"skey": ticket_dict['skey'],
"sid": ticket_dict['wxsid'],
"uin": ticket_dict['wxuin'],
"deviceid": "e261019482970229",
"synckey": sync_data_str,
} response_sync = requests.get(sync_url, params=sync_dict, cookies=ticket_cookie)
# print(response_sync.text)
if 'selector:"2"' in response_sync.text:
# https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsync?sid={}&skey={}&lang=zh_CN&pass_ticket={}
fetch_msg_url = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsync?sid={0}&skey={1}&lang=zh_CN&pass_ticket={2}".format(
ticket_dict['wxsid'], ticket_dict['skey'], ticket_dict['pass_ticket']) form_data = {
'BaseRequest': {
'DeviceID': 'e261019482970229',
'Sid': ticket_dict['wxsid'],
'Skey': ticket_dict['skey'],
'Uin': ticket_dict['wxuin']
},
'SyncKey': synckey,
'rr': ctime
}
response_fetch_msg = requests.post(
fetch_msg_url,
json=form_data,
headers={
'Connection':'keep-alive',
'Accept-Encoding':'gzip, deflate, br',
'X-Requested-With':'XMLHttpRequest',
'user-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'
},
cookies=ticket_cookie,
)
response_fetch_msg.encoding = 'utf-8'
res_fetch_msg_dict = response_fetch_msg.json() session["SyncKey"] = res_fetch_msg_dict['SyncKey'] response={}
if res_fetch_msg_dict:
for item in res_fetch_msg_dict['AddMsgList']: response['content'] = item['Content']
response['FromUserName'] = item['FromUserName']
response['ToUserName'] = item['ToUserName'] return jsonify(response)
# return render_template("send.html", res_fetch_msg_dict=res_fetch_msg_dict)
else:
return "ok" if __name__ == '__main__':
app.run()

运行项目(manage.py)后,将自动跳转到login页面,
扫码登录后,会获得个人信息,可以点击 查看所有联系人 ,然后可以在此页面点击 发消息
进入发消息页面,目前只能按UserName来发,未实现按昵称发送。

如果有消息来,可以在收到消息部分看到对方的UserName和消息内容

已知问题:
收消息经常会卡住,
或者报错: requests.exceptions.ConnectionError: ('Connection aborted.', BadStatusLine('HTTP/1.1 0 -\r\n',))

找不出原因。

提交作业后,指导老师给予回复:

感觉自己还差得远呢。

1.我觉得你第26行代码没有必要存在的,你可以在27行代码哪里@app.route('/')加一个就好了

2.我觉得你第33行代码那里还是有问题的,因为这么写字符串太长了不符合pep8规范不说也不好阅读,我觉得你可以定义成下面字典的格式,

{
'loginicon': 'true',
'uuid': session['qrcode'],
'tip': 0,
'r': '-2034746127', # 时间戳取反
'_': int(time.time() * 1000)
} response = requests.get(url=check_login_url, params=‘这个字典’) 这样代码是不是会很舒服 3.还有你第53行代码是不是应该也是int(time.time()*1000)这样去写的? 4.你的第72行代码是不是应该join一下去拼接。 5.你的try处理还是没有 6.你在@app.route("/recv")里是能够写更多的。比如图片语音消息的判断对不对,还有你在这里提交消息格式应该严格安装微信的来。 7.代码的优化这里不多说什么了,有问题和我沟通。

python爬虫基础_webwechat的更多相关文章

  1. Python爬虫基础

    前言 Python非常适合用来开发网页爬虫,理由如下: 1.抓取网页本身的接口 相比与其他静态编程语言,如java,c#,c++,python抓取网页文档的接口更简洁:相比其他动态脚本语言,如perl ...

  2. python爬虫-基础入门-python爬虫突破封锁

    python爬虫-基础入门-python爬虫突破封锁 >> 相关概念 >> request概念:是从客户端向服务器发出请求,包括用户提交的信息及客户端的一些信息.客户端可通过H ...

  3. python爬虫-基础入门-爬取整个网站《3》

    python爬虫-基础入门-爬取整个网站<3> 描述: 前两章粗略的讲述了python2.python3爬取整个网站,这章节简单的记录一下python2.python3的区别 python ...

  4. python爬虫-基础入门-爬取整个网站《2》

    python爬虫-基础入门-爬取整个网站<2> 描述: 开场白已在<python爬虫-基础入门-爬取整个网站<1>>中描述过了,这里不在描述,只附上 python3 ...

  5. python爬虫-基础入门-爬取整个网站《1》

    python爬虫-基础入门-爬取整个网站<1> 描述: 使用环境:python2.7.15 ,开发工具:pycharm,现爬取一个网站页面(http://www.baidu.com)所有数 ...

  6. Python爬虫基础之认识爬虫

    一.前言 爬虫Spider什么的,老早就听别人说过,感觉挺高大上的东西,爬网页,爬链接~~~dos黑屏的数据刷刷刷不断地往上冒,看着就爽,漂亮的校花照片,音乐网站的歌曲,笑话.段子应有尽有,全部都过来 ...

  7. python 爬虫基础知识一

    网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动的抓取万维网信息的程序或者脚本. 网络爬虫必备知识点 1. Python基础知识2. P ...

  8. Python爬虫基础(一)——HTTP

    前言 因特网联系的是世界各地的计算机(通过电缆),万维网联系的是网上的各种各样资源(通过超文本链接),如静态的HTML文件,动态的软件程序······.由于万维网的存在,处于因特网中的每台计算机可以很 ...

  9. 【学习笔记】第二章 python安全编程基础---python爬虫基础(urllib)

    一.爬虫基础 1.爬虫概念 网络爬虫(又称为网页蜘蛛),是一种按照一定的规则,自动地抓取万维网信息的程序或脚本.用爬虫最大的好出是批量且自动化得获取和处理信息.对于宏观或微观的情况都可以多一个侧面去了 ...

随机推荐

  1. React子组件和父组件通信

    React子组件和父组件通信包括以下几个方面: 子组件获取父组件属性:props或者state 子组件调用父组件的方法 父组件获取子组件的属性:props或者state 父组件调用子组件的方法 我们从 ...

  2. Batchnorm

    Internal Covariate Shift:每一次参数迭代更新后,上一层网络的输出数据经过这一层网络计算后,数据的分布会发生变化,为下一层网络的学习带来困难(神经网络本来就是要学习数据的分布,要 ...

  3. jmeter系列-如何实现像loadrunner一样,多个并发用户先通过登录初始化,然后做并发的接口性能压测

    自动转开发后,就很少关注性能测试方面的东西,最近在帮朋友做一个性能压测,由于朋友那边的公司比较小,环境比较简单,而且是对http服务进行的压测,所以最终 选用了jmeter来实现这个压测. 如下就是我 ...

  4. 多个vlan之间路由

    通过这节课,我们学习到了如何利用两个交换机,创建多个vlan口,将多台Pc之间互通今天学习到了新的指令:interface vlan-interfacee ?                     ...

  5. ansible如果兼容Centos5

    基本安装 安装gcc,用于编译python源码 yum install gcc 更新python版本 centos自带python2.6版本,由于centos已对python深度依赖,所以更新pyth ...

  6. 使用 Laragon 在 Windows 中快速搭建 Laravel 本地开发环境 (转)

    laravel学院 简介 对于那些使用 Windows 操作系统的同学来说,Homestead 和 LaraDock 虽说支持 Windows 系统,但是对初学者来说,安装配置起来还是有一定复杂度的, ...

  7. MVC架构模式详细说明

    一.简介: 架构模式是一个通用的.可重用的解决方案,用于在给定上下文中的软件体系结构中经常出现的问题.架构模式与软件设计模式类似,但具有更广泛的范围. 模型-视图-控制器模式,也称为MVC模式(Mod ...

  8. 九度1456胜利大逃亡【BFS】

    时间限制:1 秒 内存限制:128 兆 特殊判题:否 提交:4432 解决:1616 题目描述: Ignatius被魔王抓走了,有一天魔王出差去了,这可是Ignatius逃亡的好机会.魔王住在一个城堡 ...

  9. Vue打包npm run build 打包后空白怎么解决?

    问题一:路径报错并且页面空白 解决:buld/index.js      assetsPublicPath: '/'修改为 assetsPublicPath: './' 问题二:没报错页面空白  ro ...

  10. 学习笔记(一)HTML基础

    HTML 基础 HTML 简介 HTML (Hyper textmarkup language) 中文译名为"超文本标记语言",主要是通过 HTML 标记对网页中的文本.图片.声音 ...