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
包含此響應的編碼的字符串。編碼通過嘗試以下機制按順序解決:
- 在構造函數編碼參數中傳遞的編碼
- 在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。