Scrapy spiders介绍
Spider用于定義一個網站會被如何爬取以及解析。
一個Spider爬取的周期通常包括這幾步:
- 由初始URLS發出Request,并指定回調函數來處理response
The first requests to perform are obtained by calling the start_requests() method which (by default) generates Request for the URLs specified in the start_urls and the parse method as callback function for the Requests.
- 在回調函數中處理response并返回含提取出來的數據的dicts、Item或Request。這些Request同樣會有回調函數并且會被下載然后由指定的回調函數處理
- 回調函數解析頁面內容,通常是用Selectors(也可以用BeatifulSoup,lxml等)方法解析
- 將spider解析的數據存儲下來,如數據庫(使用Item Pipeline)或者文件(使用Feed exports)中。
雖說這幾步適用于所有的spider,但是基于不同的目的仍然有多種spider存在。
1. 所有Spider的基類:scrapy.Spider
class scrapy.spiders.Spider
最簡單的spider,是其它所有spider的基類。不提供任何特殊的功能,只提供了默認的`start_requests()`的實現,用于從`start_urls`發出request并調用`parse`方法處理返回的response。 主要成員變量:- name spider名,同一個項目中的不同spider名字不能相同
- allowed_domains 從爬取指定的域名
- start_urls 起始URLS
- custom_settings 自定義設置信息
- crawler 指向綁定了當前spider的Crawler對象(links to the Crawler object to which this spider instance is bound)
- settings 是Settings類的一個實例,含有spider的配置信息
- logger 用name創建的logger,可以用來發送log信息
主要成員函數:
- from_crawler(crawler,*args,**kwargs) scrapy用來創建spider的函數
statr_requests() 若沒有指定URLS,調用star_requests;若指定了,調用make_requests_from_urls()來發出request。
如果你想要改變發送請求的方式,可以覆蓋這個方法。例如,你想要用POST方式發請求:class MySpider(scrapy.Spider):
def start_requests(self):return [scrapy.FormRequest("http://www.example.com/login",formdata={'user': 'john', 'pass': 'secret'},callback=self.logged_in)]def logged_in(self, response):# here you would extract links to follow and return Requests for# each of them, with another callbackpass
name = ‘myspider’make requests_from_url(url)
- parse(response) 默認回調函數
This method, as well as any other Request callback, must return an iterable of Request and/or dicts or Item objects.
- log(message[,level,component])
- closed(reason)
使用示例: import scrapyclass MySpider(scrapy.Spider):name = 'example.com'allowed_domains = ['example.com']start_urls = ['http://www.example.com/1.html','http://www.example.com/2.html','http://www.example.com/3.html',]def parse(self, response):self.logger.info('A response from %s just arrived!', response.url) 一個回調函數返回多個request和Items: import scrapyclass MySpider(scrapy.Spider):name = 'example.com'allowed_domains = ['example.com']start_urls = ['http://www.example.com/1.html','http://www.example.com/2.html','http://www.example.com/3.html',]def parse(self, response):for h3 in response.xpath('//h3').extract():yield {"title": h3}for url in response.xpath('//a/@href').extract():yield scrapy.Request(url, callback=self.parse) 你也可以不用`start_urls`,直接使用`statr_requests()`,同時為了讓返回數據更結構化,你可以使用Items: import scrapy from myproject.items import MyItemclass MySpider(scrapy.Spider):name = 'example.com'allowed_domains = ['example.com']def start_requests(self):yield scrapy.Request('http://www.example.com/1.html', self.parse)yield scrapy.Request('http://www.example.com/2.html', self.parse)yield scrapy.Request('http://www.example.com/3.html', self.parse)def parse(self, response):for h3 in response.xpath('//h3').extract():yield MyItem(title=h3)for url in response.xpath('//a/@href').extract():yield scrapy.Request(url, callback=self.parse)
2. 給Spider傳遞參數
Spider可以接收參數來調整其運行方法。通常的用法是用來定義起始URLS或者限制spider的爬取范圍,但是它也能用于配置spider的其他功能。 spider的參數通過`crawl`命令的`-a` 選項來傳入。 scrapy crawl myspider -a category=electronics Spider從構造函數中接受參數: import scrapyclass MySpider(scrapy.Spider):name = 'myspider'def __init__(self, category=None, *args, **kwargs):super(MySpider, self).__init__(*args, **kwargs)self.start_urls = ['http://www.example.com/categories/%s' % category]# ... Spider arguments can also be passed through the Scrapyd schedule.json API. See Scrapyd documentation.3. Generic Spiders:通用spider
Scrapy附帶一些可以用來繼承實現的有用的generic spider。它們的目的在于為不同的cases提供方便的功能,如following all links on a site based on certain rules, crawling from Sitemaps, or parsing an XML/CSV feed. 對于下面的的例子,我們假設在myproject.items中實現了TestItem: import scrapyclass TestItem(scrapy.Item):id = scrapy.Field()name = scrapy.Field()description = scrapy.Field()3.1 CrawlSpider
class scrapy.spiders.CrawlSpider
爬取普通網頁最常用的spider,它提供了基于rules跟隨Link的方便機制。 除繼承自scrapy.Spider的屬性外,CrawlSpider還提供了一下屬性:- rules 一個存放Rule的list。每個`Rule定義了一個爬取頁面的規則。如果多個Rule匹配了同一個link,那么使用第一個。
- parse_start_url(response) 處理從start_urls的返回的response(避免使用parse函數!)
Crawling rules:
class scrapy.spiders.Rule(link_extractor, callback=None, cb_kwargs=None, follow=None, process_links=None, process_request=None)
- link_extractor 一個Link Extractor對象,用于定義如何從爬到的頁面提取link
- callback
- 是一個callable或string(該spider中同名的函數將會被調用)。
- 從link_extractor中每獲取到鏈接時將會調用該函數。
- 回調函數接受一個response作為其第一個參數, 并返回一個包含 Item 以及(或) Request 對象(或者這兩者的子類)的列表(list)。
- 不要使用parse函數作為回調函數,由于 CrawlSpider 使用 parse 方法來實現其邏輯,如果覆蓋了 parse 方法,crawl spider 將會運行失敗。
- cb_kwargs 包含傳遞給回調函數的參數(keyword argument)的字典。
- follow 是一個布爾值,指定了根據該規則從response提取的鏈接是否需要跟進。 如果 callback 為None, follow 默認設置為 True ,否則默認為 False 。
- process_links 是一個callable或string(該spider中同名的函數將會被調用)。 從link_extractor中獲取到鏈接列表時將會調用該函數。該方法主要用來過濾。
- process_request 是一個callable或string(該spider中同名的函數將會被調用)。 該規則提取到每個request時都會調用該函數。該函數必須返回一個request或者None。 (用來過濾request)
CrawSpider示例:
import scrapy from scrapy.contrib.spiders import CrawlSpider, Rule from scrapy.contrib.linkextractors import LinkExtractorclass 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' 的鏈接并使用spider的parse_item方法進行分析Rule(LinkExtractor(allow=('item\.php', )), callback='parse_item'),)def parse_item(self, response):self.log('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該spider將從example.com的首頁開始爬取,獲取category以及item的鏈接并對后者使用 parse_item 方法。 當item獲得返回(response)時,將使用XPath處理HTML并生成一些數據填入 Item 中。
3.2 XMLFeedSpider
class scrapy.contrib.spiders.XMLFeedSpider
用于通過迭代各個節點來分析XML源(XML feed)。
迭代器可以從 iternodes , xml , html 選擇。 鑒于 xml 以及 html 迭代器需要先讀取所有DOM再分析而引起的性能問題, 一般還是推薦使用 iternodes 。 不過使用 html 作為迭代器能有效應對錯誤的XML。
使用XMLFeedSpider需要定義下列類屬性來設置迭代器以及標簽名(tag name):
iterator
用于確定使用哪個迭代器的string。可選項有:- iternodes - 一個高性能的基于正則表達式的迭代器
- html - 使用 Selector 的迭代器。 需要注意的是該迭代器使用DOM進行分析,其需要將所有的DOM載入內存, 當數據量大的時候會產生問題。
- xml - 使用 Selector 的迭代器。 需要注意的是該迭代器使用DOM進行分析,其需要將所有的DOM載入內存, 當數據量大的時候會產生問題。
- 默認值為 iternodes 。
itertag 一個包含開始迭代的節點名的string。例如:itertag = 'product'
namespaces 一個由 (prefix, url) 元組(tuple)所組成的list。 其定義了在該文檔中會被spider處理的可用的namespace。 prefix 及 uri 會被自動調用 register_namespace() 生成namespace。
可以通過在 itertag 屬性中制定節點的namespace。class YourSpider(XMLFeedSpider):
namespaces = [('n', 'http://www.sitemaps.org/schemas/sitemap/0.9')] itertag = 'n:url' # ...adapt_response() 該方法在spider分析response前被調用。您可以在response被分析之前使用該函數來修改內容(body)。 該方法接受一個response并返回一個response(可以相同也可以不同)。
- parse_node() 當節點符合提供的標簽名時(itertag)該方法被調用。 接收到的response以及相應的 Selector 作為參數傳遞給該方法。 該方法返回一個 Item 對象或者 Request 對象 或者一個包含二者的可迭代對象(iterable)。
- process_results() 當spider返回結果(item或request)時該方法被調用。 設定該方法的目的是在結果返回給框架核心(framework core)之前做最后的處理, 例如設定item的ID。其接受一個結果的列表(list of results)及對應的response。 其結果必須返回一個結果的列表(list of results)(包含Item或者Request對象)。
XMLFeedSpider示例:
from scrapy import log from scrapy.contrib.spiders import XMLFeedSpider from myproject.items import TestItemclass MySpider(XMLFeedSpider):name = 'example.com'allowed_domains = ['example.com']start_urls = ['http://www.example.com/feed.xml']iterator = 'iternodes' # This is actually unnecessary, since it's the default valueitertag = 'item'def parse_node(self, response, node):log.msg('Hi, this is a <%s> node!: %s' % (self.itertag, ''.join(node.extract())))item = TestItem()item['id'] = node.xpath('@id').extract()item['name'] = node.xpath('name').extract()item['description'] = node.xpath('description').extract()return item簡單來說,我們在這里創建了一個spider,從給定的 start_urls 中下載feed, 并迭代feed中每個 item 標簽,輸出,并在 Item 中存儲有些隨機數據。
3.3 CSVSpider
class scrapy.contrib.spiders.CSVFeedSpider
除了其按行遍歷而不是節點之外其他和XMLFeedSpider十分類似。其在每次迭代時調用的是 parse_row() 。
- delimiter 在CSV文件中用于區分字段的分隔符。類型為string。 默認為 ','(逗號)。
- quotechar A string with the enclosure character for each field in the CSV file Defaults to '"'(quotation mark).
- headers 在CSV文件中包含的用來提取字段的行的列表。參考下邊的例子。
- parse_row() 該方法接收一個response對象及一個以提供或檢測出來的header為鍵的字典(代表每行)。 該spider中,您也可以覆蓋 adapt_response 及 process_results 方法來進行預處理(pre-processing)及后(post-processing)處理。
CSVFeedSpider示例
下面的例子和之前的例子很像,但使用了 CSVFeedSpider:
3.4 SitemapSpider
class scrapy.contrib.spiders.SitemapSpider
在爬取網站時可以通過 Sitemaps 來發現爬取的URL。
其支持嵌套的sitemap,并能從 robots.txt 中獲取sitemap的url。
總結
以上是生活随笔為你收集整理的Scrapy spiders介绍的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 线性独立成分分析(ICA)与鸡尾酒会问题
- 下一篇: 计算机病毒分为哪三类