python爬蟲學習筆記 4.8 (Downloader Middlewares)

python爬蟲學習筆記 4.8 (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())之間的一層組件,可以有多個下載中間件被加載運行。

  • 當引擎傳遞請求給下載器的過程中,下載中間件可以對請求進行處理 (例如增加http header信息,增加proxy信息等);

  • 在下載器完成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
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章