python爬蟲scrapy框架——人工識別登陸知乎倒立文字驗證碼和數字英文驗證碼(2)

原創文章,轉載請註明出處! 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爬蟲


 

首先你要知道:框架

  1. 若是要爬取知乎文章就必須先登陸。
  2. 爬蟲開始前要執行 start_requests() 函數 ,而後執行 parse() 函數。

因此咱們要在 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,已經登陸上知乎了,是否是很開心!

相關文章
相關標籤/搜索