接上一篇《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:抓取知乎的话题结构

🔔 Email 或 RSS 订阅本博客

添加新评论