(前一段时间刚学了Python,以为须要拿点东西来练手,因而就决定写个实用点的东西,也就是这条既能练手又能装逼的qq空间自动点赞的小爬虫)html
(好多不常联系的同窗都由于个人秒赞对我表示了他们的感动,搞得我都不敢说我是用程序自动点赞的)python
(然而,与其说是练手Python,其实写这个爬虫我学到的更多的知识是关于http请求的)
正则表达式—————————————————————————————————————————————————————————————————算法
行吧,开车了。服务器
①探索:当咱们按下“赞”以后,Qzone的后台发生了什么PY交易?cookie
<1>首先,抓包。打开网页版的QQ空间(我已经用F12把各类推广的窗口强行关掉了,以及,两个号都是个人小号),再打开抓包工具(这里我用的抓包工具是Fiddler,百度一下就能找到下载资源了)。先清空Fiddler抓到的包,而后点“赞”,以后“取消赞”。app
Fiddler抓到的以下四个数据包dom
<2>而后,分析包。点击分析目标,选中右边的Inspector,会获得这个包的解析数据。(若是咱们只须要“赞”的功能的话,就只分析第一个数据包就够了。以后你能够尝试本身去看“取消赞”的包,其实跟“赞”作的工做是同样的,只不过post的url不同罢了)函数
在Headers的标签页中,咱们能够看出,点赞操做用的是POST方法,向“/proxy/domain/w.qzone.qq.com/cgi-bin/likes/internal_dolike_app?g_tk=1589101394”的相对地址POST了这个包,就能实现“赞”的功能。工具因而,目标很明确,想要实现“赞”,咱们就必须模拟这个包,使用python3的http模块中的http.client.HTTPConnection.request()来将这个包发送给服务器实现“赞”。(对应Python2的httplib模块的httplib.HTTPCOnnection.request()函数,其实我到后来才发现有个requests的模块很是好用,你们能够本身百度“python requests”,但下述代码仍是以python3的http模块来实现)
发送包的代码以下:
from http import client; from urllib import parse; httpClient=client.HTTPConnection('h5.qzone.qq.com'); #h5.qzone.qq.com是Host httpClient.request("POST",url,parse.urlencode(body),headers); #method是"POST" #url是上述的"/proxy/domain/w.qzone.qq.com/cgi-bin/likes/internal_dolike_app?g_tk=1589101394",其中g_tk在每次登陆空间后都不同。 #body和headers是字典型
那么问题就来了,url和数据包的内容是什么?怎么模拟?
②解答:Qzone点赞时,该POST的数据包的内容是什么?该向谁POST数据包?
<1>该POST的数据包内容之headers
headers={'Host':'h5.qzone.qq.com', 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:49.0) Gecko/20100101 Firefox/49.0', 'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Language':'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3', 'Accept-Encoding':'gzip, deflate', 'Cookie':'', 'Connection':'keep-alive', 'Upgrade-Insecure-Requests':1, 'Content-Type':'application/x-www-form-urlencoded' } headers['Cookie']='QZ_FE_WEBP_SUPPORT=*; cpu_performance_v8=*; _gdt_close_discover=*; __Q_w_s__QZN_TodoMsgCnt=*; blabla=*; zzpaneluin=*; zzpanelkey=; p_skey=5O9avpyb9nqMw7VP6P9BZ13X8vUUJup50PDFEACDgM8_; pt4_token=*; p_uin=*; pgv_pvi=*; pgv_pvid=*; ptui_loginuin=*; pt2gguin=*; RK=*; ptcz=*; skey*; pgv_si=*; pgv_info=ssid=*; ptisp=*; uin=*; qzone_check=*' #参数值字符太多,我把cookie中的除了p_skey的参数值都用*代替了。是的,这些就是headers的内容了,除了Cookie之外,不须要知道其余参数是干吗的,由于headers字典中其余的参数对全部用户实现这个爬虫都几乎没有影响。因此,Cookie从哪里找呢?
鼠标三击Raw中的Cookie一行,便可选中整行,Ctrl+C复制,贴到代码中,去掉前缀,两侧加单引号,headers的内容就解决了。
必须使用颜色强调的是:个人这个爬虫暂没有实现自动登陆Qzone的能力,每次都要靠手动登陆,抓包获取Cookie,修改headers字典的“Cookie”来维持程序正常运行。但因为QQ空间的Cookie只要不断使用,有效时间将在12个小时以上,因此若是你想让程序长时间跑,更换Cookie也不会太频繁。(因此我称它为简单的爬虫)
<2>该POST的数据包内容之body
qqNumber='3236556749'; body={'qzreferrer':'http://user.qzone.qq.com/'+qNumber, 'opuin':qNumber, 'unikey':'', 'curkey':'', 'from':1, 'appid':311, 'typeid':0, 'active':0, 'fupdate':1 } body['unikey']='http://user.qzone.qq.com/***/mood/54a9a141c35a0b584d460300' body['curkey']='http://user.qzone.qq.com/***/mood/54a9a141c35a0b584d460300' #因为点赞对象是经常使用小号不想泄露,因此我就用***打个马赛克 params=urllib.urlencode(body)一样,我把须要注意的参数单独拉出来赋值了。包括qqNumber,unikey,和curkey。
qqNumber如其名,就是点赞者的QQ,和Cookie同属于半固定类型的——在整个程序的执行过程当中保持静态,不会变化。
而unikey和curkey则是会根听说说的不一样而动态变化的。原创说说的unikey==curkey成立,而若是是转发而来的说说则unikey!=curkey为真。curkey的值取决于被转发者的说说原创时产生的unikey,unikey的值则是转发者转发时产生的。
固然,以下图,指定说说的unikey和curkey能够在在数据包中找到,可是在自动点赞程序中,unikey和curkey显然不是静态的!
因此?unikey和curkey在哪里找呢?这个问题我如今可能很难详细地讲清楚,须要卖个关子,等下一章或者下下章条件凑齐后才能讲明白。我只能简单地说——经过正则表达式过滤含有说说的html页面来得到unikey和curkey。
<3>该向谁POST数据包?(url中的可变参数g_tk)
def getGTK(ss): hash=5381 for i in ss: hash+=(hash<<5)+ord(i); return (hash & 0x7fffffff); #算法找自百度搜索"QQ空间 g_tk"; g_tk=getGTK(p_skey); url="/proxy/domain/w.qzone.qq.com/cgi-bin/likes/internal_dolike_app?g_tk="+str(g_tk);
g_tk的值取决于Cookie中的p_skey的参数值。能够说,它也是半固定的值——整个程序运行过程当中g_tk的值不会动态变化。可使用上述算法从Cookie中的p_skey计算而来,也能够以下找到:
一般我都是选择从Cookie中计算出来,避免重启爬虫的时候须要改太多参数了。一样,须要用到正则表达式来将目标p_skey从Cookie中过滤出来,而后计算。
p_skey=re.search('p_skey=([^;^\']*)',cookie).group(1);#正则过滤cookie获得p_skey g_tk=getGTK(p_skey); url="/proxy/domain/w.qzone.qq.com/cgi-bin/likes/internal_dolike_app?g_tk="+str(g_tk);②至此,咱们已经具有写出“点赞类”的主要相关知识
from http import client from urllib import parse import re import sys class httpPOSTer: headers=None; body=None; qNum=None; url=None; cookie=None; url=None; def getGTK(self,ss): hash=5381 for i in ss: hash+=(hash<<5)+ord(i); return (hash & 0x7fffffff); def __init__(self,coo,qqNumber): self.cookie=coo;self.qNum=qqNumber; p_skey=re.search('p_skey=([^;^\']*)',self.cookie).group(1); g_tk=self.getGTK(p_skey); self.url="/proxy/domain/w.qzone.qq.com/cgi-bin/likes/internal_dolike_app?g_tk="+str(g_tk); self.headers={'Host':'h5.qzone.qq.com', 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:49.0) Gecko/20100101 Firefox/49.0', 'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Language':'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3', 'Accept-Encoding':'gzip, deflate', 'Cookie':'', 'Connection':'keep-alive', 'Upgrade-Insecure-Requests':1, 'Content-Type':'application/x-www-form-urlencoded' } self.headers['Cookie']=coo; self.body={'qzreferrer':'http://user.qzone.qq.com/'+qqNumber, 'opuin':qqNumber, 'unikey':'',#mark 'curkey':'',#mark 'from':1, 'appid':311, 'typeid':0, 'active':0, 'fupdate':1 } def thumbs_up(self,unikey,curkey): self.body['unikey']=unikey; self.body['curkey']=curkey; print("url="+self.url); httpClient=client.HTTPConnection('h5.qzone.qq.com'); httpClient.request("POST",self.url,parse.urlencode(self.body),self.headers); response=httpClient.getresponse(); print("thumbs_up "+str(response.status)+" "+response.reason); httpClient.close(); #main process BEGIN cookie='(输入区)';#本身输入cookie qqNumber='(输入区)';#本身输入qq qzoneP=httpPOSTer(cookie,qqNumber);#实例化一个点赞类 qzoneP.thumbs_up(unikey,curkey);#使用"thumbs_up()"方法,unikey和curkey的得到将在下一章或下下章讲述 #main process END
(详细讲的话,一章显然讲不彻底。我跟同窗说,我要写一篇0基础看了、都能看懂这个爬虫代码的教程,因此可能有点啰嗦……见谅)
(以后可能还会有一章,或者两章,讲述较多简单的细节,反正我如今是写不完了。凌晨四点了,好困……)