#-*-coding:utf-8 -*-
__author__ = "ruoniao"
__date__ = "2017/5/31 20:59"
之前我们通过爬取伯乐在线的文章,伯乐在线对爬取没有什么限制,这次爬取知乎,就有了爬取限制,首先就是
登录限制;为破解限制,首先就是模拟登录
模拟登陆首先要明白的就是session和cookie机制:
简单的说(个人理解):
http是一种无状态的协议,为解决用户每次都需要输入密码登录的烦恼,也为了服务器能够记住每次请求的浏览器,就有了会话机制,
就是每次对话不需要问你是谁,浏览器只需要将服务器原先发送给浏览器的ID原封不动的还给服务器,这样服务器就可以在自己的
数据库中查找这个ID就可以,而只有这个ID是没用的,若想要用户登录,还需要用用户名和密码,加密后以cookie的形式存储在本地,
下次请求直接发送给服务器就行
总之:为了服务器和浏览器之间互相确认身份,服务器生成一个session_id并且保存在服务器,还有给浏览器一份,浏览器将这个session_id写入cookie,
发送给服务器,服务器对照自己保存在本地的,就能互相确认身份;不同的是:cookie中还带了用户的个人信息等
cookie是存储在本地的记录某个网站的个人信息的机制
session是存储在服务器中的记录某个浏览器(用户)的信息的机制,更安全;
具体理解可参考这篇文章
不同的网站模拟登录的策略不同,不同的网站要进行不同的分析;但都是大同小异;做过web的明白,无非就是用户的验证;较难的就是识别验证码了
知乎的登录破解:
1:这里遇到了坑,因为在firebug中测试时,post到url时没有填写验证码;而通过requests post到URL
具体参数时报错:验证码错误,这就很纳闷了;
2:原来:当向首页get时,因为有cookies,所以登录时就不需要填写验证码;通过代码时没有加cookies,需要填写验证码
而验证码不好识别,只能更换思路
3: 模拟浏览器的行为,若当初为取的xsrf时get带上cookie,下次登录就不需要验证码了
4:那么怎么才能将cookie post到URL呢?了解requests.post()方法的知道:post()可带的参数很多
其中cookies= {}或CookieJar
5:将cookies以字典的形式post方便操作,只需要在firebug中的cookies复制为字典的格式
以CookieJar的形式:因为cookie是保存在硬盘的,可以参考这篇博文
6:因为cookie是有生存周期的额,为了下面重新登录,可以将登录后的cookie以txt的形式保存在本地,下次直接load就可以
实例代码注释
1 import requests 2 #适合python2和python3版本的导包 3 try: 4 import cookielib 5 except: 6 import http.cookiejar as cookielib 7 import re 8 from urllib import parse, request 9 10 #使用会话机制向url发送request,提高效率,不必每次都发请求(类比浏览器直接在本标签页操作,不需重新产生新的标签页) 11 session = requests.session() 12 #将会话产生的cookies保存在本地 13 session.cookies = cookielib.LWPCookieJar(filename="cookies.txt") 14 15 #浏览器版本信息,目的是伪装成一个浏览器,让服务器认为我们的代码是一个浏览器请求而不是爬虫,避免被拒绝 16 headers = { 17 "User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64; rv:53.0) Gecko/20100101 Firefox/53.0", 18 "Host":"www.zhihu.com", 19 "Referer":"https://www.zhihu.com/", 20 } 21 22 #获取登录xsrf 23 def get_xsrf(): 24 25 url = "https://www.zhihu.com/#signin" 26 27 try: 28 #带上cookie,避免产生验证码识别 29 req = session.get(url=url,cookies=cookies,headers=headers) 30 #通过正则表达式解析出 xsrf 类比csrf机制 31 xsrf = re.findall('<input type="hidden" name="_xsrf" value="(.*?)"/>',req.text) 32 if xsrf: 33 xsrf = xsrf[0] 34 print(xsrf) 35 return xsrf 36 else: 37 return xsrf 38 except Exception as e: 39 print(e) 40 print("failed download") 41 42 43 44 #知乎登录 45 def zhihu_login(account,password): 46 47 #首先获取xsrf 48 xsrf = get_xsrf() 49 #判断是手机号:以手机号登录,提交表单和提交URL不同,构造不同的URL和表单 50 if re.match("d{10}",account): 51 52 url = "https://www.zhihu.com/login/phone_num" 53 data={ 54 "_xsrf":xsrf, 55 'remember_me': 'true', 56 "password":password, 57 "phone_num":account 58 } 59 if '@' in account: 60 url = "https://www.zhihu.com/login/email" 61 data={ 62 "_xsrf":xsrf, 63 'remember_me': 'true', 64 "password":password, 65 "email":account 66 } 67 #将获取到的xsrf加载到cookie中 68 cookies["_xsrf"] = xsrf 69 #带上表单,头信息,cookies申请登录 70 r = session.post(url=url,data=data,headers=headers,cookies=cookies) 71 print(r.text) 72 #登录成功将cookies保存到本地 73 session.cookies.save() 74 75 76 #获取首页;登录后可直接获取,因为session中已经(带了)加载了cookie 77 def get_index(): 78 response = session.get("https://www.zhihu.com/",headers=headers) 79 print(response.status_code) 80 #将首页写入本地文件 81 with open("index_page.html","wb") as f: 82 f.write(response.text.encode("utf-8")) 83 print("write ok") 84 85 #查看登录状态;向一个只有登录的页面get,若登录会返回200;否则304,会重定向到登录页(重定向后会返回200) 86 def is_login(): 87 url = "https://www.zhihu.com/inbox" 88 #allow_redirects 禁止重定向 89 response = session.get(url=url,headers=headers,allow_redirects=False) 90 #判断是否登录 91 if response.status_code != 200: 92 return False 93 else: 94 return True 95 96 97 #先尝试本地cookie登录,不成功使用浏览器copy下来的cookies重新登录,生成本地cookies 98 try: 99 #先尝试加载之前保存在本地的cookies 100 session.cookies.load(ignore_discard=True) 101 print("cookies 已记载") 102 except: 103 #没加载就重新登录 104 print("cookie 未加载") 105 #这个cookie是从firebug中复制来的 106 cookies = { 107 "d_c0":"", 108 "l_cap_id":"", 109 "r_cap_id":"", 110 "cap_id":"", 111 "_zap":"", 112 "__utmc":"", 113 "__utmb":"", 114 "__utmv":"", 115 "__utma":"", 116 "__utmz":"", 117 "q_c1":""118 119 } 120 #调用登录函数,成功后会更新cookie到本地 121 zhihu_login("342200377@qq.com","") 122 #更新成功后重新加载cookies 123 session.cookies.load(ignore_discard=True) 124 125 126 print(is_login())