官方文檔 https://docs.scrapy.org/en/latest/topics/spiders.html#crawlspider
CrawlSpider定義了一組用以提取鏈接的規則,可以大大簡化爬蟲的寫法。
rules
是一組Rule
對象。每條Rule
定義了抓取網頁的方式。如果多條規則匹配到同一鏈接,根據定義規則的順序,使用第一個鏈接。
parse_start_url(response)
用來處理start_urls
的響應,返回的結果必須是Item
對象,或Request
對象,或者是二者的可迭代對象。
爬取規則
Rule
的用法
scrapy.spiders.Rule(link_extractor, callback=None, cb_kwargs=None, follow=None, process_links=None, process_request=None)
link_extractor
是鏈接抽取對象,它定義瞭如何抽取鏈接;
callback
是調回函數,注意不要使用parse
做調回函數;
cb_kwargs
是一個字典,可以將關鍵字參數傳給調回函數;
follow
是一個布爾值,指定要不要抓取鏈接。如果callback
是None,則follow
默認是True
,否則默認爲False
;
process_links
可以對link_extractor
提取出來的鏈接做處理,主要用於過濾;
process_request
是一個可調用函數,會處理這條Rule提取出來的每個請求,會返回request或None。
鏈接抽取
link_extractor
的用法
from scrapy.linkextractors import LinkExtractor
因爲用法和LxmlLinkExtractor
相同,官網使用後者說明,LxmlLinkExtractor
是基於lxml的HTMLParser實現的:
class scrapy.linkextractors.lxmlhtml.LxmlLinkExtractor(allow=(), deny=(), allow_domains=(), deny_domains=(), deny_extensions=None, restrict_xpaths=(), restrict_css=(), tags=('a', 'area'), attrs=('href', ), canonicalize=False, unique=True, process_value=None, strip=True)
allow
:(一個或一個列表)出鏈必須要匹配的正則表達式。如果allow爲空,則匹配所有鏈接;
deny
:(一個或一個列表)出鏈必須要匹配的正則表達式,以做排除。優先於allow
。如果爲空,則不排除任何鏈接;
allow_domains
:(一個或一個列表)提取鏈接的域名;
deny_domains
:(一個或一個列表)不提取鏈接的域名;
deny_extensions
:(一個或一個列表)要忽略的後綴,如果爲空,則爲包scrapy.linkextractors
中的列表IGNORED_EXTENSIONS
,如下所示:
IGNORED_EXTENSIONS = [ # 圖片 'mng', 'pct', 'bmp', 'gif', 'jpg', 'jpeg', 'png', 'pst', 'psp', 'tif', 'tiff', 'ai', 'drw', 'dxf', 'eps', 'ps', 'svg', # 音頻 'mp3', 'wma', 'ogg', 'wav', 'ra', 'aac', 'mid', 'au', 'aiff', # 視頻 '3gp', 'asf', 'asx', 'avi', 'mov', 'mp4', 'mpg', 'qt', 'rm', 'swf', 'wmv', 'm4a', 'm4v', 'flv', # 辦公軟件 'xls', 'xlsx', 'ppt', 'pptx', 'pps', 'doc', 'docx', 'odt', 'ods', 'odg', 'odp', # 其它 'css', 'pdf', 'exe', 'bin', 'rss', 'zip', 'rar', ]
restrict_xpaths
:(一個或一個列表)xpath,定義了從響應文本的哪部分提取鏈接;
restrict_css
:(一個或一個列表)css,定義了從響應文本的哪部分提取鏈接;
tags
:(一個或一個列表)用以抽取鏈接的標籤,默認是('a', 'area')
;
attrs
:(一個或一個列表)屬性,定義了從響應文本的哪部分提取鏈接,默認是('href',)
;
canonicalize
:(布爾值)建議設爲False;
unique
:(布爾值)是否過濾重複鏈接;
process_value
:(可調用對象)可以對標籤和屬性掃描結果做修改,下面是官網給的例子;
# 一個要提取的鏈接 <a href="javascript:goToPage('../other/page.html'); return false">Link text</a> # 要提取的是 “../other/page.html” def process_value(value): m = re.search("javascript:goToPage\('(.*?)'", value) if m: return m.group(1)
strip
:(布爾值)默認開啓。
官網給的CrawlSpider的例子:
import scrapy from scrapy.spiders import CrawlSpider, Rule from scrapy.linkextractors import LinkExtractor class MySpider(CrawlSpider): name = 'example.com' allowed_domains = ['example.com'] start_urls = ['http://www.example.com'] rules = ( # 提取匹配 'category.php' 的鏈接 (不匹配 'subsection.php') # 沒有設置callback,則默認follow=True,繼續抓取符合該條規則的所有鏈接 Rule(LinkExtractor(allow=('category\.php', ), deny=('subsection\.php', ))), # 提取匹配 'item.php' 的鏈接,用parse_item方法做解析 Rule(LinkExtractor(allow=('item\.php', )), callback='parse_item'), ) def parse_item(self, response): self.logger.info('Hi, this is an item page! %s', response.url) item = scrapy.Item() item['id'] = response.xpath('//td[@id="item_id"]/text()').re(r'ID: (\d+)') item['name'] = response.xpath('//td[@id="item_name"]/text()').extract() item['description'] = response.xpath('//td[@id="item_description"]/text()').extract() return item
感覺還是xpath更好用,還是用麥田租房舉例子:http://bj.maitian.cn/zfall/PG1
這樣寫規則就行了
rules = ( Rule(LinkExtractor(restrict_xpaths='//*[contains(@class,"down_page")]')), Rule(LinkExtractor(restrict_xpaths='//div[@class="list_title"]/h1/'), callback='parse_item') )