原創文章,轉載請註明出處! 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,已經登陸上知乎了,是否是很開心!