把之前使用requests库模拟登录知乎的代码改了一下,改成了Scrapy框架的版本,具体代码如下:
class ZhiHuSpider(CrawlSpider):
name = "zhihu"
# allowed_domains = ["zhihu.com"]
start_urls = [
"https://www.zhihu.com"
]
headers = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Encoding': 'gzip, deflate, sdch, br',
'Accept-Language': 'zh-CN,zh;q=0.8',
'Connection': 'keep-alive',
'Host': 'www.zhihu.com',
'Origin': 'https://www.zhihu.com',
'Referer': 'https://www.zhihu.com/',
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36',
'x-hd-token': 'hello',
}
def start_requests(self):
return [
Request("https://www.zhihu.com/captcha.gif?r=1495546872530&type=login", meta={'cookiejar': 1},
headers=self.headers, callback=self.get_captcha),
]
def get_captcha(self,response):
with open("../captcha.jpg", 'wb') as w:
w.write(response.body)
return Request("https://www.zhihu.com/#signin", meta={'cookiejar': response.meta['cookiejar']}, headers=self.headers, callback=self.post_login)
def post_login(self, response):
print('Preparing login')
xsrf = Selector(response).xpath('//input[@name="_xsrf"]/@value').extract()[0]
print(xsrf)
captcha = input("请自行打开图片查看验证码并输入验证码:")
# 登陆成功后, 会调用after_login回调函数
return [FormRequest(url='https://www.zhihu.com/login/phone_num',
meta={'cookiejar': response.meta['cookiejar']},
headers=self.headers, # 注意此处的headers
formdata={
'_xsrf': xsrf,
'phone_num': 'XXXX',
'password': 'XXXXX',
'captcha': captcha
},
callback=self.after_login,
dont_filter=True
)]
def after_login(self, response):
# for url in self.start_urls:
# yield self.make_requests_from_url(url)
print(json.loads(response.body.decode()))
if json.loads(response.body.decode())['r'] == 0:
yield scrapy.Request(
'http://www.zhihu.com',
headers=self.headers,
meta={'cookiejar': response.meta['cookiejar']},
callback=self.parse_page,
dont_filter=True, # 因为是第二次请求, 设置为True, 默认是False, 否则报错
)
def parse_page(self, response):
html_parser = HTMLParser()
text = html_parser.unescape(response.body.decode())
print(text)
有几处需要注意的地方:
①Scrapy中保存“登录”这个状态需要使用cookie,在未登录前各种请求带上
meta={'cookiejar': 1}
在登录后各种请求带上
meta={'cookiejar': response.meta['cookiejar']},
这样可以使得请求带上登录信息。
②需要在setting中设置启用cookie
COOKIES_ENABLED = True
③在爬取过程中出现了UnicodeEncodeError: 'gbk' codec can't encode character '\u2600' in position 19383: illegal multibyte sequence,查询资料得知是因为cmd命令行里使用的是gbk格式,如果包含一些gbk无法显示的字符就会爆这个错误,具体可以见https://www.crifan.com/unicodeencodeerror_gbk_codec_can_not_encode_character_in_position_illegal_multibyte_sequence/
也可以使用直接在python运行scrapy的方式显示到pycharm的控制台就不会报错。关于如何在pycharm上直接运行scrapy可以参考http://blog.csdn.net/wangsidadehao/article/details/52911746