原创文章,转载请注明出处! html
操做环境:python3python
在上一文中python爬虫scrapy框架——人工识别登陆知乎倒立文字验证码和数字英文验证码(1)咱们已经介绍了用Requests库来登陆知乎,本文若是看不懂能够先看以前的文章便于理解json
本文将介绍如何用scrapy来登陆知乎。服务器
很少说,直接上代码:cookie
import scrapy import re import json class ZhihuSpider(scrapy.Spider): name = 'zhihu' allowed_domains = ['www.zhihu.com'] start_urls = ['https://www.zhihu.com/'] headers = { 'HOST': 'www.zhihu.com', 'Referer': 'https://www.zhihu.com', 'User-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.1.2 Safari/603.3.8', } def parse(self, response): pass def parse_detail(self, response): # 爬取文章细节 pass # scrapy开始时先进入start_requests() def start_requests(self): # 为了提取_xsrf:要先访问知乎的登陆页面,让scrapy在登陆页面获取服务器给咱们的数据(_xsrf),再调用login return [scrapy.Request('https://www.zhihu.com/#signin', headers=self.headers, callback=self.login)] def login(self, response): xsrf = '' match_obj = re.match('[\s\S]*name="_xsrf" value="(.*?)"', response.text) if match_obj: xsrf = match_obj.group(1) # 若是提取到了xsrf就进行下面的操做,若是没xsrf有就不必往下作了 if xsrf: post_data = { 'captcha_type': 'cn', '_xsrf': xsrf, 'phone_num': 'YourPhoneNum', 'password': 'YourPassWord', 'captcha': '', } import time captcha_url = 'https://www.zhihu.com/captcha.gif?r=%d&type=login&lang=cn' % (int(time.time() * 1000)) # scrapy会默认把Request的cookie放进去 return scrapy.Request(captcha_url, headers=self.headers, meta={'post_data': post_data}, callback=self.login_after_captcha) def login_after_captcha(self, response): # 保存并打开验证码 with open('captcha.gif', 'wb') as f: f.write(response.body) f.close() from PIL import Image try: img = Image.open('captcha.gif') img.show() except: pass # 输入验证码 captcha = { 'img_size': [200, 44], 'input_points': [], } points = [[22.796875, 22], [42.796875, 22], [63.796875, 21], [84.796875, 20], [107.796875, 20], [129.796875, 22], [150.796875, 22]] seq = input('请输入倒立字的位置\n>') for i in seq: captcha['input_points'].append(points[int(i) - 1]) captcha = json.dumps(captcha) post_url = 'https://www.zhihu.com/login/phone_num' post_data = response.meta.get('post_data', {}) post_data['captcha'] = captcha return scrapy.FormRequest( # 在这里完成像以前的requests的登陆操做,每个Request若是要作下一步处理都要设置callback url=post_url, formdata=post_data, headers=self.headers, callback=self.check_login, ) def check_login(self, response): # 验证服务器的返回数据判断是否成功 text_json = json.loads(response.text) if 'msg' in text_json and text_json['msg'] == '登陆成功': print('登陆成功!') for url in self.start_urls: yield scrapy.Request(url, dont_filter=True, headers=self.headers)
这个文件是你爬虫目录下的spider/zhihu.py,有scrapy基础的都看得懂。app
下面让咱们一块儿分析一下这个逻辑python爬虫
首先你要知道:框架
因此咱们要在 start_requests() 里进行登陆,再在 parse() 里进行提取咱们要爬取的字段。这里咱们不分析 parse() 怎么写,只分析如何登陆。下面让咱们逐步分析如何登陆:dom
首先要访问知乎的登陆界面获取 "_xsrf" 字段的值:scrapy
def start_requests(self): return [scrapy.Request('https://www.zhihu.com/#signin', headers=self.headers, callback=self.login)]
在scrapy请求了https://www.zhihu.com/#signin后,知乎服务器返回的cookies就会被scrapy保存,下次请求(request)会默认带着这些cookies。
在 login() 函数里进行提取 "_xsrf" 字段(看不懂如何提取的可参考以前的文章),并去请求知乎的验证码URL,这里是必需要注意的,在请求知乎的验证码URL后,知乎服务器会返回cookies,咱们在提交验证码字段时必须带上直呼服务器给你的cookies,知乎服务器会进行匹配,若是cookies不对就会验证失败。
def login(self, response): xsrf = '' match_obj = re.match('[\s\S]*name="_xsrf" value="(.*?)"', response.text) if match_obj: xsrf = match_obj.group(1) # 若是提取到了xsrf就进行下面的操做,若是没xsrf有就不必往下作了 if xsrf: post_data = { 'captcha_type': 'cn', '_xsrf': xsrf, 'phone_num': '这里写你登陆的电话号', 'password': '这里写你的登陆密码', 'captcha': '', } import time captcha_url = 'https://www.zhihu.com/captcha.gifr=%d&type=login&lang=cn' % (int(time.time() * 1000)) # scrapy会默认把Request的cookie放进去 yield scrapy.Request(captcha_url, headers=self.headers, meta={'post_data': post_data}, callback=self.login_after_captcha)
向知乎服务器请求验证码后,这个 request 返回的 response 里其实就是验证码图片了,下面咱们会调用 login_after_captcha() 函数,进行验证码图片的保存、自动打开、手动输入验证码的位置,再利用 python 的 Json 模块把 captcha 这个dict转换成 Json 格式放入 post_data 中。顺便一提,目前这里的 yield 彻底能够用 return 代替。
def login_after_captcha(self, response): # 保存并打开验证码 with open('captcha.gif', 'wb') as f: f.write(response.body) f.close() from PIL import Image try: img = Image.open('captcha.gif') img.show() except: pass # 输入验证码 captcha = { 'img_size': [200, 44], 'input_points': [], } points = [[22.796875, 22], [42.796875, 22], [63.796875, 21], [84.796875, 20], [107.796875, 20], [129.796875, 22], [150.796875, 22]] seq = input('请输入倒立字的位置\n>') for i in seq: captcha['input_points'].append(points[int(i) - 1]) captcha = json.dumps(captcha) post_url = 'https://www.zhihu.com/login/phone_num' post_data = response.meta.get('post_data', {}) post_data['captcha'] = captcha return [scrapy.FormRequest( # 在这里完成像以前的requests的登陆操做,每个Request若是要作下一步处理都要设置callback url=post_url, formdata=post_data, headers=self.headers, callback=self.check_login, )]
把填写好的 post_data 发送给知乎登陆URL:https://www.zhihu.com/login/phone_num,这里只演示电话号码登陆,邮箱登陆一个原理,只不过URL不同:https://www.zhihu.com/login/email。以后咱们要调用 check_login() 函数来检查是否登陆成功,思路就是查看返回的"msg"字段是否为"登录成功"。而后再调用scrapy原有的 start_request() 函数里的方法,经查看源码它的方法实际就是下面的遍历self.start_url再进行request(个人start_url是知乎主页,因此这个request就会访问知乎主页)
def check_login(self, response): # 验证服务器的返回数据判断是否成功 text_json = json.loads(response.text) if 'msg' in text_json and text_json['msg'] == '登陆成功': print('登陆成功!') for url in self.start_urls: yield scrapy.Request(url, dont_filter=True, headers=self.headers)
因为咱们已经登录成功了,scrapy再访问知乎主页www.zhihu.com就会带着知乎服务器返回已经登陆成功的cookies,所以就会直接进入登陆成功的主页。
到此为止,咱们就大功告成了!
让咱们利用 Pycharm 的 Debug 模式在parse那打个断点,查看response的text,已经登陆上知乎了,是否是很开心!