Scrapy爬蟲入門教程十一 Request和Response(請求和響應)
開發環境: Python 3.6.0 版本
(當前最新) Scrapy 1.3.2 版本
(當前最新)
目錄
請求和響應
Scrapy的Request和Response物件用於爬網網站。
通常,Request物件在爬蟲程式中生成並傳遞到系統,直到它們到達下載程式,後者執行請求並返回一個Response物件,該物件返回到發出請求的爬蟲程式。
上面一段話比較拗口,有web經驗的同學,應該都瞭解的,不明白看下面的圖大概理解下。
爬蟲爬蟲RequestRequestResponseResponse建立獲取下載資料資料
兩個類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'})
- 1
- 2
- 使用列表:
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})
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中包含的資料取決於您啟用的擴充套件。
當使用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) - 要在表單資料中覆蓋的欄位。如果響應元素中已存在欄位,則其值將被在此引數中傳遞的值覆蓋。
- 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(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
包含此響應的編碼的字串。編碼通過嘗試以下機制按順序解決:
- 在建構函式編碼引數中傳遞的編碼
- 在Content-Type HTTP頭中宣告的編碼。如果此編碼無效(即未知),則會被忽略,並嘗試下一個解析機制。
- 在響應主體中宣告的編碼。TextResponse類不提供任何特殊功能。然而, HtmlResponse和XmlResponse類做。
- 通過檢視響應體來推斷的編碼。這是更脆弱的方法,但也是最後一個嘗試。
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。