1. 程式人生 > >三十二、scrapy中介軟體的使用

三十二、scrapy中介軟體的使用

1. scrapy中介軟體的分類和作用

1.1 scrapy中介軟體的分類

根據scrapy執行流程中所在位置不同分為:

  • 下載中介軟體
  • 爬蟲中介軟體

1.2 scrapy中間的作用:預處理request和response物件

  • 如對非200響應的重試(重新構造Request物件yield給引擎)
  • 也可以對header以及cookie進行更換和處理
  • 使用代理ip等

  但在scrapy預設的情況下 兩種中介軟體都在middlewares.py一個檔案中,爬蟲中介軟體使用方法和下載中介軟體相同,且功能重複,常使用下載中介軟體

2. 下載中介軟體的使用方法:

接下來我們對騰訊招聘爬蟲進行修改完善,通過下載中介軟體來學習如何使用中介軟體 編寫一個Downloader Middlewares和我們編寫一個pipeline一樣,定義一個類,然後在setting中開啟

Downloader Middlewares預設的方法:

 process_request(self, request, spider)
  • 當每個request通過下載中介軟體時,該方法被呼叫。
  • 返回None值:沒有return也是返回None,該request物件傳遞給下載器,或通過引擎傳遞給其他權重低的process_request方法
  • 返回Response物件:不再請求,把response返回給引擎
  • 返回Request物件:把request物件通過引擎交給排程器,此時將不通過其他權重低的process_request方法
process_response(self, request, response, spider)
  • 當下載器完成http請求,傳遞響應給引擎的時候呼叫
  • 返回Resposne:通過引擎交給爬蟲處理或交給權重更低的其他下載中介軟體的process_response方法
  • 返回Request物件:通過引擎交給調取器繼續請求,此時將不通過其他權重低的process_request方法

在settings.py中配置開啟中介軟體,權重值越小越優先執行

3. 定義實現隨機User-Agent的下載中介軟體

3.1 在middlewares.py中完善程式碼

import random
from Tencent.settings import USER_AGENTS_LIST # 注意匯入路徑,請忽視pycharm的錯誤提示

class UserAgentMiddleware(object):
    def process_request(self, request, spider):
        user_agent = random.choice(USER_AGENTS_LIST)
        request.headers['User-Agent'] = user_agent
        # 不寫return

class CheckUA:
    def process_response(self,request,response,spider):
        print(request.headers['User-Agent'])
        return response # 不能少!

3.2 在settings中設定開啟自定義的下載中介軟體,設定方法同管道

DOWNLOADER_MIDDLEWARES = {
   'Tencent.middlewares.UserAgentMiddleware': 543, # 543是權重值
   'Tencent.middlewares.CheckUA': 600, # 先執行543權重的中介軟體,再執行600的中介軟體
}

3.3 在settings中新增UA的列表

USER_AGENTS_LIST = [
    "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Media Center PC 6.0)",
    "Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 1.0.3705; .NET CLR 1.1.4322)",
    "Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.04506.30)",
    "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.3 (Change: 287 c9dfb30)",
    "Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.6",
    "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070215 K-Ninja/2.1.1",
    "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9) Gecko/20080705 Firefox/3.0 Kapiko/3.0",
    "Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070322 Kazehakase/0.4.5"
]

執行爬蟲觀察現象

4. 代理ip的使用

4.1 思路分析

  • 代理新增的位置:request.meta中增加proxy欄位
  • 獲取一個代理ip,賦值給request.meta[‘proxy’]
  • 代理池中隨機選擇代理ip
  • 代理ip的webapi傳送請求獲取一個代理ip

4.2 具體實現

(1)免費代理ip:

class ProxyMiddleware(object):
    def process_request(self,request,spider):
        # proxies可以在settings.py中,也可以來源於代理ip的webapi
        # proxy = random.choice(proxies) 

        # 免費的會失效,報 111 connection refused 資訊!重找一個代理ip再試
        proxy = 'https://1.71.188.37:3128' 

        request.meta['proxy'] = proxy
        return None # 可以不寫return

(2)收費代理ip:
(按照官方要求使用)

# 人民幣玩家的程式碼(使用abuyun提供的代理ip)
import base64

# 代理隧道驗證資訊  這個是在那個網站上申請的
proxyServer = 'http://proxy.abuyun.com:9010' # 收費的代理ip伺服器地址,這裡是abuyun
proxyUser = 使用者名稱
proxyPass = 密碼
proxyAuth = "Basic " + base64.b64encode(proxyUser + ":" + proxyPass)

class ProxyMiddleware(object):
    def process_request(self, request, spider):
        # 設定代理
        request.meta["proxy"] = proxyServer
        # 設定認證
        request.headers["Proxy-Authorization"] = proxyAuth

4.3 檢測代理ip是否可用

在使用了代理ip的情況下可以在下載中介軟體的process_response()方法中處理代理ip的使用情況,如果該代理ip不能使用可以替換其他代理ip

class ProxyMiddleware(object):
    ......
    def process_response(self, request, response, spider):
        if response.status != '200':
            request.dont_filter = True # 重新發送的請求物件能夠再次進入佇列
            return requst

在settings.py中開啟該中介軟體

5. 在中介軟體中使用selenium

以github登陸為例

5.1 完成爬蟲程式碼

import scrapy

class Login4Spider(scrapy.Spider):
    name = 'login4'
    allowed_domains = ['github.com']
    start_urls = ['https://github.com/1596930226'] # 直接對驗證的url傳送請求

    def parse(self, response):
        with open('check.html', 'w') as f:
            f.write(response.body.decode())

5.2 在middlewares.py中使用selenium

import time
from selenium import webdriver

def getCookies():
    # 使用selenium模擬登陸,獲取並返回cookie
    username = input('輸入github賬號:')
    password = input('輸入github密碼:')
    options = webdriver.ChromeOptions()
    options.add_argument('--headless')
    options.add_argument('--disable-gpu')
    driver = webdriver.Chrome('/home/worker/Desktop/driver/chromedriver',
                              chrome_options=options)
    driver.get('https://github.com/login')
    time.sleep(1)
    driver.find_element_by_xpath('//*[@id="login_field"]').send_keys(username)
    time.sleep(1)
    driver.find_element_by_xpath('//*[@id="password"]').send_keys(password)
    time.sleep(1)
    driver.find_element_by_xpath('//*[@id="login"]/form/div[3]/input[3]').click()
    time.sleep(2)
    cookies_dict = {cookie['name']: cookie['value'] for cookie in driver.get_cookies()}
    driver.quit()
    return cookies_dict

class LoginDownloaderMiddleware(object):

    def process_request(self, request, spider):
        cookies_dict = getCookies()
        print(cookies_dict)
        request.cookies = cookies_dict # 對請求物件的cookies屬性進行替換

配置檔案中設定開啟該中介軟體後,執行爬蟲可以在日誌資訊中看到selenium相關內容