Scrapy爬蟲入門教程十一 Request和Response(請求和響應)

Python版本管理:pyenv和pyenv-virtualenv
Scrapy爬蟲入門教程一 安裝和基本使用
Scrapy爬蟲入門教程二 官方提供Demo
Scrapy爬蟲入門教程三 命令行工具介紹和示例
Scrapy爬蟲入門教程四 Spider(爬蟲)
Scrapy爬蟲入門教程五 Selectors(選擇器)
Scrapy爬蟲入門教程六 Items(項目)
Scrapy爬蟲入門教程七 Item Loaders(項目加載器)
Scrapy爬蟲入門教程八 交互式 shell 方便調試
Scrapy爬蟲入門教程九 Item Pipeline(項目管道)
Scrapy爬蟲入門教程十 Feed exports(導出文件)
Scrapy爬蟲入門教程十一 Request和Response(請求和響應)
Scrapy爬蟲入門教程十二 Link Extractors(鏈接提取器)

開發環境:
Python 3.6.0 版本 (當前最新)
Scrapy 1.3.2 版本 (當前最新)

請求和響應

Scrapy的Request和Response對象用于爬網網站。

通常,Request對象在爬蟲程序中生成并傳遞到系統,直到它們到達下載程序,后者執行請求并返回一個Response對象,該對象返回到發出請求的爬蟲程序。

上面一段話比較拗口,有web經驗的同學,應該都了解的,不明白看下面的圖大概理解下。

爬蟲->Request:創建
Request->Response:獲取下載數據
Response->爬蟲:數據

兩個類Request和Response類都有一些子類,它們添加基類中不需要的功能。這些在下面的請求子類和 響應子類中描述。


Request objects

class scrapy.http.Request(url[, callback, method='GET', headers, body, cookies, meta, encoding='utf-8', priority=0, dont_filter=False, errback])

一個Request對象表示一個HTTP請求,它通常是在爬蟲生成,并由下載執行,從而生成Response。

  • 參數:
    • url(string) - 此請求的網址

    • callback(callable) - 將使用此請求的響應(一旦下載)作為其第一個參數調用的函數。有關更多信息,請參閱下面的將附加數據傳遞給回調函數。如果請求沒有指定回調,parse()將使用spider的 方法。請注意,如果在處理期間引發異常,則會調用errback。

    • method(string) - 此請求的HTTP方法。默認為'GET'。

    • meta(dict) - 屬性的初始值Request.meta。如果給定,在此參數中傳遞的dict將被淺復制。

    • body(str或unicode) - 請求體。如果unicode傳遞了a,那么它被編碼為 str使用傳遞的編碼(默認為utf-8)。如果 body沒有給出,則存儲一個空字符串。不管這個參數的類型,存儲的最終值將是一個str(不會是unicode或None)。

    • headers(dict) - 這個請求的頭。dict值可以是字符串(對于單值標頭)或列表(對于多值標頭)。如果 None作為值傳遞,則不會發送HTTP頭。

    • cookie(dict或list) - 請求cookie。這些可以以兩種形式發送。

      • 使用dict:
      request_with_cookies = Request(url="http://www.example.com",
                                     cookies={'currency': 'USD', 'country': 'UY'})
      
    * 使用列表:

    ```
    request_with_cookies = Request(url="http://www.example.com",
                                   cookies=[{'name': 'currency',
                                            'value': 'USD',
                                            'domain': 'example.com',
                                            'path': '/currency'}])
    ```

后一種形式允許定制 cookie的屬性domain和path屬性。這只有在保存Cookie用于以后的請求時才有用。

當某些網站返回Cookie(在響應中)時,這些Cookie會存儲在該域的Cookie中,并在將來的請求中再次發送。這是任何常規網絡瀏覽器的典型行為。但是,如果由于某種原因,您想要避免與現有Cookie合并,您可以通過將dont_merge_cookies關鍵字設置為True 來指示Scrapy如此操作 Request.meta。

不合并Cookie的請求示例:

request_with_cookies = Request(url="http://www.example.com",
                               cookies={'currency': 'USD', 'country': 'UY'},
                               meta={'dont_merge_cookies': True})

有關詳細信息,請參閱CookiesMiddleware

  • encoding(string) - 此請求的編碼(默認為'utf-8')。此編碼將用于對URL進行百分比編碼,并將正文轉換為str(如果給定unicode)。

  • priority(int) - 此請求的優先級(默認為0)。調度器使用優先級來定義用于處理請求的順序。具有較高優先級值的請求將較早執行。允許負值以指示相對低優先級。

  • dont_filter(boolean) - 表示此請求不應由調度程序過濾。當您想要多次執行相同的請求時忽略重復過濾器時使用。小心使用它,或者你會進入爬行循環。默認為False。

  • errback(callable) - 如果在處理請求時引發任何異常,將調用的函數。這包括失敗的404 HTTP錯誤等頁面。它接收一個Twisted Failure實例作為第一個參數。有關更多信息,請參閱使用errbacks在請求處理捕獲異常

  • url
    包含此請求的網址的字符串。請記住,此屬性包含轉義的網址,因此它可能與構造函數中傳遞的網址不同。

此屬性為只讀。更改請求使用的URL replace()

  • method
    表示請求中的HTTP方法的字符串。這保證是大寫的。例如:"GET","POST","PUT"

  • headers
    包含請求標頭的類似字典的對象。

  • body
    包含請求正文的str。

此屬性為只讀。更改請求使用的正文 replace()

  • meta
    包含此請求的任意元數據的字典。此dict對于新請求為空,通常由不同的Scrapy組件(擴展程序,中間件等)填充。因此,此dict中包含的數據取決于您啟用的擴展。

有關Scrapy識別的特殊元鍵列表,請參閱Request.meta特殊鍵

當使用or 方法克隆請求時,此dict是淺復制的 ,并且也可以在您的爬蟲中從屬性訪問。copy()replace()response.meta

  • copy()
    返回一個新的請求,它是這個請求的副本。另請參見: 將附加數據傳遞到回調函數

  • replace([url, method, headers, body, cookies, meta, encoding, dont_filter, callback, errback])
    返回具有相同成員的Request對象,但通過指定的任何關鍵字參數賦予新值的成員除外。該屬性Request.meta是默認復制(除非新的值在給定的meta參數)。另請參見 將附加數據傳遞給回調函數

將附加數據傳遞給回調函數

請求的回調是當下載該請求的響應時將被調用的函數。將使用下載的Response對象作為其第一個參數來調用回調函數。

例:

def parse_page1(self, response):
    return scrapy.Request("http://www.example.com/some_page.html",
                          callback=self.parse_page2)

def parse_page2(self, response):
    # this would log http://www.example.com/some_page.html
    self.logger.info("Visited %s", response.url)

在某些情況下,您可能有興趣向這些回調函數傳遞參數,以便稍后在第二個回調中接收參數。您可以使用該Request.meta屬性。

以下是使用此機制傳遞項目以填充來自不同頁面的不同字段的示例:

def parse_page1(self, response):
    item = MyItem()
    item['main_url'] = response.url
    request = scrapy.Request("http://www.example.com/some_page.html",
                             callback=self.parse_page2)
    request.meta['item'] = item
    yield request

def parse_page2(self, response):
    item = response.meta['item']
    item['other_url'] = response.url
    yield item

使用errbacks在請求處理中捕獲異常

請求的errback是在處理異常時被調用的函數。

它接收一個Twisted Failure實例作為第一個參數,并可用于跟蹤連接建立超時,DNS錯誤等。

這里有一個示例爬蟲記錄所有錯誤,并捕獲一些特定的錯誤,如果需要:

import scrapy

from scrapy.spidermiddlewares.httperror import HttpError
from twisted.internet.error import DNSLookupError
from twisted.internet.error import TimeoutError, TCPTimedOutError

class ErrbackSpider(scrapy.Spider):
    name = "errback_example"
    start_urls = [
        "http://www.httpbin.org/",              # HTTP 200 expected
        "http://www.httpbin.org/status/404",    # Not found error
        "http://www.httpbin.org/status/500",    # server issue
        "http://www.httpbin.org:12345/",        # non-responding host, timeout expected
        "http://www.httphttpbinbin.org/",       # DNS error expected
    ]

    def start_requests(self):
        for u in self.start_urls:
            yield scrapy.Request(u, callback=self.parse_httpbin,
                                    errback=self.errback_httpbin,
                                    dont_filter=True)

    def parse_httpbin(self, response):
        self.logger.info('Got successful response from {}'.format(response.url))
        # do something useful here...

    def errback_httpbin(self, failure):
        # log all failures
        self.logger.error(repr(failure))

        # in case you want to do something special for some errors,
        # you may need the failure's type:

        if failure.check(HttpError):
            # these exceptions come from HttpError spider middleware
            # you can get the non-200 response
            response = failure.value.response
            self.logger.error('HttpError on %s', response.url)

        elif failure.check(DNSLookupError):
            # this is the original request
            request = failure.request
            self.logger.error('DNSLookupError on %s', request.url)

        elif failure.check(TimeoutError, TCPTimedOutError):
            request = failure.request
            self.logger.error('TimeoutError on %s', request.url)


Request.meta特殊鍵

Request.meta屬性可以包含任何任意數據,但有一些特殊的鍵由Scrapy及其內置擴展識別。

那些是:

dont_redirect
dont_retry
handle_httpstatus_list
handle_httpstatus_all
dont_merge_cookies(參見cookies構造函數的Request參數)
cookiejar
dont_cache
redirect_urls
bindaddress
dont_obey_robotstxt
download_timeout
download_maxsize
download_latency
proxy

bindaddress

用于執行請求的出站IP地址的IP。

download_timeout

下載器在超時前等待的時間量(以秒為單位)。參見:DOWNLOAD_TIMEOUT

download_latency

自請求已啟動以來,用于獲取響應的時間量,即通過網絡發送的HTTP消息。此元鍵僅在響應已下載時可用。雖然大多數其他元鍵用于控制Scrapy行為,但這應該是只讀的。

請求子類

這里是內置子類的Request列表。您還可以將其子類化以實現您自己的自定義功能。

FormRequest對象
FormRequest類擴展了Request具有處理HTML表單的功能的基礎。它使用lxml.html表單 從Response對象的表單數據預填充表單字段。

class scrapy.http.FormRequest(url[, formdata, ...])

FormRequest類增加了新的構造函數的參數。其余的參數與Request類相同,這里沒有記錄。

  • 參數:formdata(元組的dict或iterable) - 是一個包含HTML Form數據的字典(或(key,value)元組的迭代),它將被url編碼并分配給請求的主體。
    FormRequest對象支持除標準以下類方法Request的方法:
classmethod from_response(response[, formname=None, formid=None, formnumber=0, formdata=None, formxpath=None, formcss=None, clickdata=None, dont_click=False, ...])

返回一個新FormRequest對象,其中的表單字段值已預先<form>填充在給定響應中包含的HTML 元素中。有關示例,請參閱 使用FormRequest.from_response()來模擬用戶登錄

該策略是在任何可查看的表單控件上默認自動模擬點擊,如a 。即使這是相當方便,并且經常想要的行為,有時它可能導致難以調試的問題。例如,當使用使用javascript填充和/或提交的表單時,默認行為可能不是最合適的。要禁用此行為,您可以將參數設置 為。此外,如果要更改單擊的控件(而不是禁用它),您還可以使用 參數。<input type="submit"> from_response() dont_click True clickdata

參數:

  • response(Responseobject) - 包含將用于預填充表單字段的HTML表單的響應
  • formname(string) - 如果給定,將使用name屬性設置為此值的形式。
  • formid(string) - 如果給定,將使用id屬性設置為此值的形式。
  • formxpath(string) - 如果給定,將使用匹配xpath的第一個表單。
  • formcss(string) - 如果給定,將使用匹配css選擇器的第一個形式。
  • formnumber(integer) - 當響應包含多個表單時要使用的表單的數量。第一個(也是默認)是0。
  • formdata(dict) - 要在表單數據中覆蓋的字段。如果響應<form>元素中已存在字段,則其值將被在此參數中傳遞的值覆蓋。
  • clickdata(dict) - 查找控件被點擊的屬性。如果沒有提供,表單數據將被提交,模擬第一個可點擊元素的點擊。除了html屬性,控件可以通過其相對于表單中其他提交表輸入的基于零的索引,通過nr屬性來標識。
  • dont_click(boolean) - 如果為True,表單數據將在不點擊任何元素的情況下提交。

這個類方法的其他參數直接傳遞給 FormRequest構造函數。
在新版本0.10.3:該formname參數。
在新版本0.17:該formxpath參數。
新的版本1.1.0:該formcss參數。
新的版本1.1.0:該formid參數。



請求使用示例

使用FormRequest通過HTTP POST發送數據

如果你想在你的爬蟲中模擬HTML表單POST并發送幾個鍵值字段,你可以返回一個FormRequest對象(從你的爬蟲)像這樣:

return [FormRequest(url="http://www.example.com/post/action",
                    formdata={'name': 'John Doe', 'age': '27'},
                    callback=self.after_post)]

使用FormRequest.from_response()來模擬用戶登錄

網站通常通過元素(例如會話相關數據或認證令牌(用于登錄頁面))提供預填充的表單字段。進行剪貼時,您需要自動預填充這些字段,并且只覆蓋其中的一些,例如用戶名和密碼。您可以使用 此作業的方法。這里有一個使用它的爬蟲示例:<input type="hidden"> FormRequest.from_response()

import scrapy

class LoginSpider(scrapy.Spider):
    name = 'example.com'
    start_urls = ['http://www.example.com/users/login.php']

    def parse(self, response):
        return scrapy.FormRequest.from_response(
            response,
            formdata={'username': 'john', 'password': 'secret'},
            callback=self.after_login
        )

    def after_login(self, response):
        # check login succeed before going on
        if "authentication failed" in response.body:
            self.logger.error("Login failed")
            return

        # continue scraping with authenticated session...

響應對象

class scrapy.http.Response(url[, status=200, headers=None, body=b'', flags=None, request=None])
一個Response對象表示的HTTP響應,這通常是下載(由下載),并供給到爬蟲進行處理。

參數:

  • url(string) - 此響應的URL
  • status(integer) - 響應的HTTP狀態。默認為200
  • headers(dict) - 這個響應的頭。dict值可以是字符串(對于單值標頭)或列表(對于多值標頭)。
  • body(str) - 響應體。它必須是str,而不是unicode,除非你使用一個編碼感知響應子類,如 TextResponse
  • flags(list) - 是一個包含屬性初始值的 Response.flags列表。如果給定,列表將被淺復制。
  • request(Requestobject) - 屬性的初始值Response.request。這代表Request生成此響應。

url
包含響應的URL的字符串。

此屬性為只讀。更改響應使用的URL replace()。

status
表示響應的HTTP狀態的整數。示例:200, 404。

headers
包含響應標題的類字典對象。可以使用get()返回具有指定名稱的第一個標頭值或getlist()返回具有指定名稱的所有標頭值來訪問值。例如,此調用會為您提供標題中的所有Cookie:

response.headers.getlist('Set-Cookie')

body
本回復的正文。記住Response.body總是一個字節對象。如果你想unicode版本使用 TextResponse.text(只在TextResponse 和子類中可用)。

此屬性為只讀。更改響應使用的主體 replace()。

request
Request生成此響應的對象。在響應和請求通過所有下載中間件后,此屬性在Scrapy引擎中分配。特別地,這意味著:

HTTP重定向將導致將原始請求(重定向之前的URL)分配給重定向響應(重定向后具有最終URL)。
Response.request.url并不總是等于Response.url
此屬性僅在爬蟲程序代碼和 Spider Middleware中可用,但不能在Downloader Middleware中使用(盡管您有通過其他方式可用的請求)和處理程序response_downloaded。

meta
的快捷方式Request.meta的屬性 Response.request對象(即self.request.meta)。

與Response.request屬性不同,Response.meta 屬性沿重定向和重試傳播,因此您將獲得Request.meta從您的爬蟲發送的原始屬性。

也可以看看

Request.meta 屬性

flags
包含此響應的標志的列表。標志是用于標記響應的標簽。例如:'cached','redirected '等等。它們顯示在Response(__ str__ 方法)的字符串表示上,它被引擎用于日志記錄。

copy()
返回一個新的響應,它是此響應的副本。

replace([ url,status,headers,body,request,flags,cls ] )
返回具有相同成員的Response對象,但通過指定的任何關鍵字參數賦予新值的成員除外。該屬性Response.meta是默認復制。

urljoin(url )
通過將響應url與可能的相對URL 組合構造絕對url。

這是一個包裝在urlparse.urljoin,它只是一個別名,使這個調用:

urlparse.urljoin(response.url, url)

響應子類

這里是可用的內置Response子類的列表。您還可以將Response類子類化以實現您自己的功能。

TextResponse對象

class scrapy.http.TextResponse(url[, encoding[, ...]])

TextResponse對象向基Response類添加編碼能力 ,這意味著僅用于二進制數據,例如圖像,聲音或任何媒體文件。

TextResponse對象支持一個新的構造函數參數,除了基礎Response對象。其余的功能與Response類相同,這里沒有記錄。

參數: encoding(string) - 是一個字符串,包含用于此響應的編碼。如果你創建一個TextResponse具有unicode主體的對象,它將使用這個編碼進行編碼(記住body屬性總是一個字符串)。如果encoding是None(默認值),則將在響應標頭和正文中查找編碼。
TextResponse除了標準對象之外,對象還支持以下屬性Response

text
響應體,如unicode。

同樣response.body.decode(response.encoding),但結果是在第一次調用后緩存,因此您可以訪問 response.text多次,無需額外的開銷。

注意
unicode(response.body)不是一個正確的方法來將響應身體轉換為unicode:您將使用系統默認編碼(通常為ascii)而不是響應編碼。

encoding
包含此響應的編碼的字符串。編碼通過嘗試以下機制按順序解決:

  1. 在構造函數編碼參數中傳遞的編碼
  2. 在Content-Type HTTP頭中聲明的編碼。如果此編碼無效(即未知),則會被忽略,并嘗試下一個解析機制。
  3. 在響應主體中聲明的編碼。TextResponse類不提供任何特殊功能。然而, HtmlResponse和XmlResponse類做。
  4. 通過查看響應體來推斷的編碼。這是更脆弱的方法,但也是最后一個嘗試。

selector
一個Selector使用響應為目標實例。選擇器在第一次訪問時被延遲實例化。

TextResponse對象除了標準對象外還支持以下方法Response:

xpath(查詢)
快捷方式TextResponse.selector.xpath(query)

response.xpath('//p')

css(query)
快捷方式 TextResponse.selector.css(query):

response.css('p')

body_as_unicode()
同樣text,但可用作方法。保留此方法以實現向后兼容; 請喜歡response.text。

HtmlResponse對象

class scrapy.http.HtmlResponse(url [,... ] )
本HtmlResponse類的子類,TextResponse 這增加了通過查看HTML編碼自動發現支持META HTTP-EQUIV屬性。見TextResponse.encoding。

XmlResponse對象

class scrapy.http.XmlResponse(url [,... ] )
本XmlResponse類的子類,TextResponse這增加了通過查看XML聲明線路編碼自動發現支持。見TextResponse.encoding。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,505評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,556評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,463評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,009評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,778評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,218評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,281評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,436評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,969評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,795評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,993評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,537評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,229評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,659評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,917評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,687評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,990評論 2 374

推薦閱讀更多精彩內容