Python爬虫:模拟登录知乎
接上一篇《Python 爬虫:抓取知乎某一话题下的全部问题》,需要说明的是我换了开发环境及一些工具库,现在用的是
环境:Python 3.5
HTTP请求:request
XML处理:BeautifulSoup + lxml
能够抓取一个话题下的问题后,我在想要如何抓取知乎全站数据呢?传统的方法,随便从某一个页面(通常是首页)开始抓取,然后提取页面中的URL,再根据提取到的URL去抓下一个页面。但对于新手,感觉一开始就这样处理,难度挺大,比如要做很多URL的分析、调度、去重等。又不想直接上Scrapy这样的框架,那就得想想其他法子。
考虑到我只是抓取知乎,而且知乎网站的结构比较清晰。内容上是按照「话题→问题→答案→回复」组织的,所以完全可以按照这个顺序去抓,最后再抓取「用户」信息就大功告成了。
那第一步就是要抓所有话题,找到话题结构页,从「根话题」开始,结果发现话题结构页需要登录才能查看。于是乎有了这篇文章。
获取登录信息
使用chrome的开发者工具查看知乎的登录信息,如下图:
可以看到知乎的登录地址是http://www.zhihu.com/login/email
,请求方式是POST
,登录时需要提交五个数据,分别是
_xsrf: 估计是随机生成的校验类数据,可在网页源码中找到
password: 密码
captcha: 验证码
remember_me: 记住我,布尔值
email: 邮箱地址
email、password和remember_me这三个很简单,主要是如何拿到_xsrf
和验证码。
在网页原码中可以找到下面这段代码,就是_xsrf
,可以使用BeautifulSoup解析HTML获取。
<input type="hidden" name="_xsrf" value="df557baede680642b1e1ab5974011246"/>
验证码是图片,复制图片链接地址就能看到,如下:
http://www.zhihu.com/captcha.gif
程序中需要抓取验证码图片并手动输入验证码才行。
模拟登录知乎
搞清楚登录过程及信息后,就可以开始写代码了。
import requests
import re
from bs4 import BeautifulSoup
# 设置一个session对象,保存登录信息
s = requests.Session()
# 设置headers
headers = {
"Accept": "*/*",
"Accept-Encoding": "gzip,deflate",
"Accept-Language": "en-US,en;q=0.8,zh-TW;q=0.6,zh;q=0.4",
"Connection": "keep-alive",
"Content-Type":" application/x-www-form-urlencoded; charset=UTF-8",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.111 Safari/537.36",
"Referer": "http://www.zhihu.com/"
}
html = s.get('http://www.zhihu.com/', headers=headers) # GET请求,获取一个响应对象
soup = BeautifulSoup(html.text,'lxml-xml') # 使用BeautifulSoup解析HTML
# 获取_xsrf
_xsrf = soup.findAll(type='hidden')[0]['value']
# 获取验证码图片并保存在本地
captcha_url = 'http://www.zhihu.com/captcha.gif'
captcha = s.get(captcha_url, stream=True, headers=headers)
with open('captcha.gif', 'wb') as f:
for line in captcha.iter_content(10):
f.write(line)
f.close()
# 输入获取到的验证码,并入变量captch_str
print('输入验证码:', end='')
captcha_str = input()
# POST请求需要提交的信息组合
data = {
'_xsrf': _xsrf,
'email': '123456789@qq.com', # 请用正确的邮箱
'password': 'password', # 请用正确的密码
'remember_me': True,
'captcha': captcha_str
}
# 登录请求
r = s.post(url='http://www.zhihu.com/login/email', data=data, headers=headers)
# 验证登录是否成功
print('登录状态:', r.json())
使用正确的邮箱和密码后,运行程序,将提示输入验证码,根据本地保存的图片输入即可。最终的输出如下(发现「陆」字错了):
输入验证码:hrfv
登录状态: {'r': 0, 'msg': '登陆成功'}
大功告成。
NEXT:抓取知乎的话题结构