爬虫概要及web微信请求分析
一、爬虫概要
1、网络爬虫是什么
百度百科:网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本。另外一些不常使用的名字还有蚂蚁、自动索引、模拟程序或者蠕虫。
通俗的讲,爬虫就是能够自动访问互联网并将网站内容下载下来的的程序或脚本,类似一个机器人,能把别人网站的信息弄到自己的电脑上,再做一些过滤,筛选,归纳,整理,排序等等。
网络爬虫的英文即Web Spider,是一个很形象的名字。把互联网比喻成一个蜘蛛网,那么Spider就是在网上爬来爬去的蜘蛛。网络蜘蛛是通过网页的链接地址来寻找网页,从网站某一个页面(通常是首页)开始,读取网页的内容,找到在网页中的其它链接地址,然后通过这些链接地址寻找下一个网页,这样一直循环下去,直到把这个网站所有的网页都抓取完为止。如果把整个互联网当成一个网站,那么网络蜘蛛就可以用这个原理把互联网上所有的网页都抓取下来。
2、网络爬虫的本质及其基本流程
一般情况下,用户获取网络数据有以下两种方式:
(1)借助浏览器:输入url --> 提交请求 --> 下载网页代码 --> 渲染成页面
(2)代码模拟:模拟浏览器发送请求(获取网页代码) --> 提取有用的数据 --> 存储数据
网络爬虫的本质
- 通过代码模仿浏览器发送请求,即上述方式(2)
基本流程
向目标站点发送http请求 --> 获取响应内容 --> 解析内容 --> 保存数据
从底层剖析爬虫本质:
浏览器本质,socket客户端遵循Http协议(通过\r\n分割的规范+请求响应断开连接=>无状态、短连接)
url = 'www.cnblogs.com'
sk = socket.socket()
# 连接的过程是:阻塞
sk.connect((url,80))
# HTTP协议
content = "GET /wupeiqi HTTP/1.1\r\nHost: %s\r\nUser-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36\r\n\r\n" %url
sk.sendall(content.encode('utf-8'))
# 等待服务端返回内容:阻塞
data = sk.recv(8096)
print(data)
sk.close()
3、Python爬虫必备的知识
python
- 基础
- 网络编程
WEB知识
- HTML基础
- CSS基础
- javascript基础
HTTP协议
请求头(一般情况下):
- user-agent:代指用户的访问设备
- cookie:服务端在客户端(浏览器)保留的标记
- refer:请求来源(从哪里请求的)
- host:
- content-type:
请求体(数据格式)
- name=alex&age=18
- {'name':alex,'age':18}
状态码(重定向302)
- 响应头中的Location
分析HTTP请求(抓包)
- chrome
- fiddler
二、web微信基本通信过程分析
1、微信服务器返回一个会话ID(uuid)
web微信采用扫描二维码登录,不使用用户名密码登录,因此微信服务器需要分配一个唯一的会话ID,用来标识当前的一次登录。GET请求的host及参数如下:
qcode_host = "https://login.wx2.qq.com/jslogin"
# GET请求参数
params = {
'appid':"wx782c26e4c19acffb",
'redirect_uri':"https%3A%2F%2Fwx2.qq.com%2Fcgi-bin%2Fmmwebwx-bin%2Fwebwxnewloginpage",
'fun':"new",
'lang':"zh_",
'_':ctime
}
# 发送GET请求
res = requests.get(
url=qcode_host,
params=params
)
请求成功,服务器会返回如下的字符串:
- window.QRLogin.code = 200; window.QRLogin.uuid = "SCrc8SK6ZG=="
- 200表示请求成功,字符串"SCrc8SK6ZG=="是这次请求微信服务器返回的会话ID(uuid)。
2、通过会话ID获得登录二维码
通过浏览器或者代码发送如下GET请求,获取登录二维码:https://login.weixin.qq.com/l/SCrc8SK6ZG==
3、通过长轮询检测是否已扫描二维码,通过响应状态判断是否确认登录
获得二维码后,需要用户在手机端扫描二维码,并确认是否登录,此时浏览器或代码并不知道用户何时操作,因此只有轮询,为了提高轮训效率,web微信采用长轮询的方式,即向如下地址发送GET请求:
check_host = "https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login"
params = {
'loginicon':'true',
'uuid':qcode,
'tip':'0',
'r':'-1036255891',
'_':ctime
}
res = requests.get(
url=check_host,
params=params
)
- 服务器返回分析:
- window.code=201 说明用户已经完成扫码,但还没确认登录
- window.code=200 window.redirect_uri="https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket=A5ncNUM2NJBYNOpJ49Jd38m2@qrticket_0&uuid=Ia7HTPkEdQ==&lang=zh_CN&scan=1485320697" 说明用户已确认登录,保存window.redirect_uri跳转地址
- window.code=408 说明用户未扫码,等待超时,继续轮询
4、获取uin、sid、pass_ticket、skey参数值(注意此处构造的请求地址)
确认登录后,通过向如下redirect_uri地址发送GET请求,获取uin、sid、pass_ticket、skey参数值,便于后续发送请求时使用
- redirect_uri = window.redirect_uri + "&fun=new&version=v2"
5、初使化用户等信息
上述已完成登录过程,下面需要获取用户信息、好友列表、公众号等信息,向如下地址发送POST请求:
init_host = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxinit"
# POST请求参数
params = {
'r': '-1039465096',
'lang': 'zh_CN',
'pass_ticket': ticket_dict.get('pass_ticket')
}
# POST请求体
form_data = {
"BaseRequest":{
"DeviceID":"e626652155210212",
"Sid":ticket_dict.get('wxsid'),
"Uin":ticket_dict.get('wxuin'),
"Skey":ticket_dict.get('skey'),
}
}
init_res = requests.post(
url=init_host,
params=params,
# 第1中json格式数据
# json=data_dict,
# 第2中data格式,需要带请求头
data=json.dumps(form_data),
headers={
'Content-Type':'application/json'
}
)
服务器返回用户信息以及同步键值,SyncKey是用户与服务器同步的键值,User是当前登录用户信息。
6、获得所有的好友列表
在上一步骤中已经获得部分好友和公众帐号,如果需要获得完整的好友信息,需要请求如下地址:
- https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact?pass_ticket=gzP3GEH0awvApwIttyTwxzAvA27%2BwVAp9tQ1osM%2FLL90XWWU5JeIdNLLVjN%2BJ9bq&skey=@crypt_dcaca546_c69b06b40828731a0acb3235758c0ea6&r=1486119544662
保持之前访问的Cookies不变,在返回的数据中,MemberList包含了所有的好友信息。
7、发送消息
通过向如下地址发送POST请求,发送消息:
https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?pass_ticket=gzP3GEH0awvApwIttyTwxzAvA27%2BwVAp9tQ1osM%2FLL90XWWU5JeIdNLLVjN%2BJ9bq
# POST请求体
form_data = {
"BaseRequest": {
"DeviceID": "e626652155210212",
"Sid": ticket_dict.get('wxsid'),
"Uin": ticket_dict.get('wxuin'),
"Skey": ticket_dict.get('skey'),
},
'Msg':{
'ClientMsgId':ctime,
'LocalID':ctime,
'FromUserName':from_user,
'ToUserName':to,
"Content":content,
'Type':1
},
'Scene':0
}
send_msg_res = requests.post(
url=send_host,
params =params,
# 若是字符串中含有中文,request传递数据时,将中文转换为字节,无法为我们自动转换编码。直接encoding编码,传递字节,不让requests自动转换
# data可以是字典,字符串,字节,对于字典,字符串直接含有中文不正确,直接转字节传送,py3默认是utf-8,直接传送字节就可以,如果使用json,会将中文转换为Unicode
data=bytes(json.dumps(form_data,ensure_ascii=False),encoding='utf-8')
)
其中BaseRequest都是授权相关的值,与上述获取的值对应。
8、接收消息
检测是否有新消息到来,发送GET请求的地址及请求参数如下:
check_msg_host = "https://webpush.wx2.qq.com/cgi-bin/mmwebwx-bin/synccheck"
check_list = []
for item in user_info['SyncKey']['List']:
tmp = "%s_%s" % (item['Key'], item['Val'])
check_list.append(tmp)
check_str = "|".join(check_list)
# GET请求参数
params = {
'r': int(time.time()),
'skey': ticket_dict.get('skey'),
'sid': ticket_dict.get('wxsid'),
'uin': ticket_dict.get('wxuin'),
'deviceid': "e626652155210212",
'synckey': check_str,
'_':int(time.time())
}
check_msg_res = requests.get(
url=check_msg_host,
params=params,
cookies=all_cookies
)
响应的内容如下:
- window.synccheck={retcode:”0”,selector:”2”}
如果retcode不为0,则说明通信有问题。根据selector值,客户端需要作出进一步处理。当selector=2时表示有新消息,此时需要访问另一个接口获取新消息内容,向如下地址发送POST请求:
recv_msg_host = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsync"
# POST请求参数
params = {
'sid': ticket_dict.get('wxsid'),
'skey': ticket_dict.get('skey'),
'lang':'zh_CN',
}
# POST请求数据
form_data = {
'BaseRequest': {
"DeviceID": "e626652155210212",
"Sid": ticket_dict.get('wxsid'),
"Skey": ticket_dict.get('skey'),
"Uin": ticket_dict.get('wxuin'),
},
'SyncKey': user_info.get('SyncKey'),
'rr': int(time.time()) #数据类型
}
# 发送POST请求
recv_msg_res = requests.post(
url=recv_msg_host,
params=params,
json=form_data
)
爬虫概要及web微信请求分析的更多相关文章
- Web微信模拟
一.概要 目的:实现一个具有web微信类似功能的项目 框架:Django 模块:render.HttpResponse.BeautifulSoup.re.time.requests.json.rand ...
- requests+django+bs4实现一个web微信的功能
前言: 今天我们利用requests模块+django+bs4浏览器来实现一个web微信的基本功能,主要实现的功能如下 a.实现返回二维码 b.实现手机扫码后二维码变成变成头像 c.实现手机点击登陆成 ...
- day37 爬虫2(web微信、高性能相关、Scrapy)
s16day37 爬虫2 参考博客:http://www.cnblogs.com/wupeiqi/articles/6229292.html 课堂代码:https://github.com/liyon ...
- 实现手机扫描二维码页面登录,类似web微信-第一篇,业务分析
转自:http://www.cnblogs.com/fengyun99/p/3541249.html 关于XMPP组件的文章,先休息两天,好歹已经完整的写了一份. 这两天,先实现一套关于web微信扫描 ...
- Python 爬虫五 进阶案例-web微信登陆与消息发送
首先回顾下网页微信登陆的一般流程 1.打开浏览器输入网址 2.使用手机微信扫码登陆 3.进入用户界面 1.打开浏览器输入网址 首先打开浏览器输入web微信网址,并进行监控: https://wx.qq ...
- web微信开发总结
这两天使用Django开发了web微信,实现了显示联系人以及收发消息的功能. 总结下这过程中使用到的一些知识. 1 http请求 通过chrome浏览器自带的开发者工具查看每次请求的信息,分析请求,包 ...
- web微信开发
群里接收消息时,使用广播,但需要刷新页面才能接收到广播内容. - 轮询: 定时每秒刷新一次,当群不活跃时,群里的每个客户端都在刷新,对服务端压力太大. - 长轮询:客户端连服务端,服务端一直不断开,也 ...
- 基于Flask开发web微信
1. 获取二维码 app.py import re import time import requests from flask import Flask,render_template app = ...
- 转 web前端性能分析--实践篇
当我们知道了web前端性能的关键点后,那么接下来要做的就是如何去具体实施并获取这些关键点的数据了.通过前面的学习知道了不少好的工具,经过对比后个人觉得dynatrace还是不错的. 不仅支持ie,ff ...
随机推荐
- Vitamio视频播放器
前言 虽然Android已经内置了VideoView组件和MediaPlayer类来支持开发视频播放器,但支持格式.性能等各方面都十分有限,这里与大家一起利用免费的Vitamio来打造属于自己的And ...
- iOS 数据类型转换
1.NSString转化为UNICODE String:(NSString*)fname = @“Test”; char fnameStr[10]; memcpy(fnameStr, [fname c ...
- iOS实现传递不定长的多个参数
我们在使用苹果官方的文档的时候会发现可传不定数的参数例如: // [[UIAlertView alloc]initWithTitle:<#(nullable NSString *)#> m ...
- shiro-filter执行流程
web中 在xml中配置 <filter> <filter-name>shiroFilter</filter-name> <filter-class>o ...
- 价格战拉上了Android平板电脑
自从苹果iPad成功以来,平板电脑一直是人们争相追捧的热门产品.其中Android平板电脑已是遍地开花.去年,在移动行业,主流厂商已推出了太多各种款型的Android平板电脑,它们留给2014年的创新 ...
- activemq 实战三 了解连接器的URI-Understanding connector URIs
Before discussing the details of connectors and their role in the overall ActiveMQ architecture, it’ ...
- LeetCode——Search Insert Position
Description: Given a sorted array and a target value, return the index if the target is found. If no ...
- LeetCode——House Robber
Description: You are a professional robber planning to rob houses along a street. Each house has a c ...
- request.get... getHeader 能取得的信息 参数
转载▼ StringTokenizer st = new StringTokenizer(agent,";"); st.nextToken(); //得到用户的浏览器名 Str ...
- 2.void 0 与 不可靠的undefined
在 ES5 之前,全局的 undefined 也是可以被修改的,而在 ES5 中,该标识符被设计为了只读标识符, 假如你现在的浏览器不是太老,你可以在控制台中输入以下语句测试一下: undefined ...