1. 程式人生 > >Scrapy框架----- Downloader Middlewares

Scrapy框架----- Downloader Middlewares

反反爬蟲相關機制

Some websites implement certain measures to prevent bots from crawling them, with varying degrees of sophistication. Getting around those measures can be difficult and tricky, and may sometimes require special infrastructure. Please consider contacting commercial support if in doubt.

(有些些網站使用特定的不同程度的複雜性規則防止爬蟲訪問,繞過這些規則是困難和複雜的,有時可能需要特殊的基礎設施,如果有疑問,請聯絡商業支援。)

來自於Scrapy官方文件描述:http://doc.scrapy.org/en/master/topics/practices.html#avoiding-getting-banned

通常防止爬蟲被反主要有以下幾個策略:

  • 動態設定User-Agent(隨機切換User-Agent,模擬不同使用者的瀏覽器資訊)

  • 禁用Cookies(也就是不啟用cookies middleware,不向Server傳送cookies,有些網站通過cookie的使用發現爬蟲行為)

    • 可以通過COOKIES_ENABLED 控制 CookiesMiddleware 開啟或關閉
  • 設定延遲下載(防止訪問過於頻繁,設定為 2秒 或更高)

  • Google Cache 和 Baidu Cache:如果可能的話,使用谷歌/百度等搜尋引擎伺服器頁面快取獲取頁面資料。

  • 使用IP地址池:VPN和代理IP,現在大部分網站都是根據IP來ban的。

  • 使用 Crawlera(專用於爬蟲的代理元件),正確配置和設定下載中介軟體後,專案所有的request都是通過crawlera發出。

      DOWNLOADER_MIDDLEWARES = {
          'scrapy_crawlera.CrawleraMiddleware': 600
      }
    
      CRAWLERA_ENABLED = True
      CRAWLERA_USER = '註冊/購買的UserKey'
      CRAWLERA_PASS = '註冊/購買的Password'
    

設定下載中介軟體(Downloader Middlewares)

下載中介軟體是處於引擎(crawler.engine)和下載器(crawler.engine.download())之間的一層元件,可以有多個下載中介軟體被載入執行。

  1. 當引擎傳遞請求給下載器的過程中,下載中介軟體可以對請求進行處理 (例如增加http header資訊,增加proxy資訊等);

  2. 在下載器完成http請求,傳遞響應給引擎的過程中, 下載中介軟體可以對響應進行處理(例如進行gzip的解壓等)

要啟用下載器中介軟體元件,將其加入到 DOWNLOADER_MIDDLEWARES 設定中。 該設定是一個字典(dict),鍵為中介軟體類的路徑,值為其中介軟體的順序(order)。

這裡是一個例子:

DOWNLOADER_MIDDLEWARES = {
    'mySpider.middlewares.MyDownloaderMiddleware': 543,
}

編寫下載器中介軟體十分簡單。每個中介軟體元件是一個定義了以下一個或多個方法的Python類:

class scrapy.contrib.downloadermiddleware.DownloaderMiddleware

process_request(self, request, spider)

  • 當每個request通過下載中介軟體時,該方法被呼叫。

  • process_request() 必須返回以下其中之一:一個 None 、一個 Response 物件、一個 Request 物件或 raise IgnoreRequest:

    • 如果其返回 None ,Scrapy將繼續處理該request,執行其他的中介軟體的相應方法,直到合適的下載器處理函式(download handler)被呼叫, 該request被執行(其response被下載)。

    • 如果其返回 Response 物件,Scrapy將不會呼叫 任何 其他的 process_request() 或 process_exception() 方法,或相應地下載函式; 其將返回該response。 已安裝的中介軟體的 process_response() 方法則會在每個response返回時被呼叫。

    • 如果其返回 Request 物件,Scrapy則停止呼叫 process_request方法並重新排程返回的request。當新返回的request被執行後, 相應地中介軟體鏈將會根據下載的response被呼叫。

    • 如果其raise一個 IgnoreRequest 異常,則安裝的下載中介軟體的 process_exception() 方法會被呼叫。如果沒有任何一個方法處理該異常, 則request的errback(Request.errback)方法會被呼叫。如果沒有程式碼處理丟擲的異常, 則該異常被忽略且不記錄(不同於其他異常那樣)。

  • 引數:

    • request (Request 物件) – 處理的request
    • spider (Spider 物件) – 該request對應的spider

process_response(self, request, response, spider)

當下載器完成http請求,傳遞響應給引擎的時候呼叫

  • process_request() 必須返回以下其中之一: 返回一個 Response 物件、 返回一個 Request 物件或raise一個 IgnoreRequest 異常。

    • 如果其返回一個 Response (可以與傳入的response相同,也可以是全新的物件), 該response會被在鏈中的其他中介軟體的 process_response() 方法處理。

    • 如果其返回一個 Request 物件,則中介軟體鏈停止, 返回的request會被重新排程下載。處理類似於 process_request() 返回request所做的那樣。

    • 如果其丟擲一個 IgnoreRequest 異常,則呼叫request的errback(Request.errback)。 如果沒有程式碼處理丟擲的異常,則該異常被忽略且不記錄(不同於其他異常那樣)。

  • 引數:

    • request (Request 物件) – response所對應的request
    • response (Response 物件) – 被處理的response
    • spider (Spider 物件) – response所對應的spider

使用案例:

1. 建立middlewares.py檔案。

Scrapy代理IP、Uesr-Agent的切換都是通過DOWNLOADER_MIDDLEWARES進行控制,我們在settings.py同級目錄下建立middlewares.py檔案,包裝所有請求。

# middlewares.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import random
import base64 from settings import USER_AGENTS from settings import PROXIES # 隨機的User-Agent class RandomUserAgent(object): def process_request(self, request, spider): useragent = random.choice(USER_AGENTS) request.headers.setdefault("User-Agent", useragent) class RandomProxy(object): def process_request(self, request, spider): proxy = random.choice(PROXIES) if proxy['user_passwd'] is None: # 沒有代理賬戶驗證的代理使用方式 request.meta['proxy'] = "http://" + proxy['ip_port'] else: # 對賬戶密碼進行base64編碼轉換 base64_userpasswd = base64.b64encode(proxy['user_passwd']) # 對應到代理伺服器的信令格式裡 request.headers['Proxy-Authorization'] = 'Basic ' + base64_userpasswd request.meta['proxy'] = "http://" + proxy['ip_port'] 

為什麼HTTP代理要使用base64編碼:

HTTP代理的原理很簡單,就是通過HTTP協議與代理伺服器建立連線,協議信令中包含要連線到的遠端主機的IP和埠號,如果有需要身份驗證的話還需要加上授權資訊,伺服器收到信令後首先進行身份驗證,通過後便與遠端主機建立連線,連線成功之後會返回給客戶端200,表示驗證通過,就這麼簡單,下面是具體的信令格式:

CONNECT 59.64.128.198:21 HTTP/1.1
Host: 59.64.128.198:21
Proxy-Authorization: Basic bGV2I1TU5OTIz
User-Agent: OpenFetion

其中Proxy-Authorization是身份驗證資訊,Basic後面的字串是使用者名稱和密碼組合後進行base64編碼的結果,也就是對username:password進行base64編碼。

HTTP/1.0 200 Connection established

OK,客戶端收到收面的信令後表示成功建立連線,接下來要傳送給遠端主機的資料就可以傳送給代理伺服器了,代理伺服器建立連線後會在根據IP地址和埠號對應的連線放入快取,收到信令後再根據IP地址和埠號從快取中找到對應的連線,將資料通過該連線轉發出去。

2. 修改settings.py配置USER_AGENTS和PROXIES

  • 新增USER_AGENTS:
  USER_AGENTS = [
    "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" ] 
  • 新增代理IP設定PROXIES:

    免費代理IP可以網上搜索,或者付費購買一批可用的私密代理IP:

PROXIES = [
    {'ip_port': '111.8.60.9:8123', 'user_passwd': 'user1:pass1'},
    {'ip_port': '101.71.27.120:80', 'user_passwd': 'user2:pass2'}, {'ip_port': '122.96.59.104:80', 'user_passwd': 'user3:pass3'}, {'ip_port': '122.224.249.122:8088', 'user_passwd': 'user4:pass4'}, ] 
  • 除非特殊需要,禁用cookies,防止某些網站根據Cookie來封鎖爬蟲。
COOKIES_ENABLED = False
  • 設定下載延遲
DOWNLOAD_DELAY = 3
  • 最後設定setting.py裡的DOWNLOADER_MIDDLEWARES,新增自己編寫的下載中介軟體類。
DOWNLOADER_MIDDLEWARES = {
    #'mySpider.middlewares.MyCustomDownloaderMiddleware': 543,
    'mySpider.middlewares.RandomUserAgent': 1,
    'mySpider.middlewares.ProxyMiddleware': 100 }