Scrapy是一個優秀的Python爬蟲框架,它支援並發、分散式、非同步等高階特性,可以幫助開發者更快、更穩定地爬取網路上的資料。在Scrapy中,連結提取器和去重工具是非常重要的組件,用來輔助爬蟲完成自動化的資料抓取和處理。本文將對Scrapy中的連結擷取器和去重工具進行分析,探討它們是如何實現的,以及在Scrapy爬取過程中的應用。
一、連結提取器的作用及實作
連結提取器(Link Extractor)是Scrapy爬蟲框架中的一個自動提取URL連結的工具。在一個完整的爬蟲過程中,往往需要從網頁中提取一些URL鏈接,然後根據這些鏈接進一步進行訪問和處理。連結提取器就是用來實現這個過程的,它可以根據一些規則從網頁中自動提取出鏈接,並將這些鏈接保存到Scrapy的請求隊列中等待後續處理。
在Scrapy中,連結提取器是透過正規表示式或XPath表達式來進行匹配的。 Scrapy提供了兩個連結提取器:基於正規表示式的LinkExtractor和基於XPath表達式的LxmlLinkExtractor。
基於正規表示式的LinkExtractor可以透過對網頁中的URL進行正規匹配,自動提取出匹配成功的連結。例如,我們希望從一個網頁中提取所有以http://example.com/ 開頭的鏈接,可以使用以下代碼:
from scrapy.linkextractors import LinkExtractor link_extractor = LinkExtractor(allow=r'^http://example.com/') links = link_extractor.extract_links(response)
allow參數指定了一個正則表達式,用來匹配所有以http ://example.com/ 開頭的連結。 extract_links()方法可以提取所有匹配成功的鏈接,並保存在一個Link物件列表中。
Link物件是Scrapy框架中用來表示連結的資料結構,其中包含了連結的URL、標題、anchor文字和連結的類型等資訊。透過這些對象,我們可以很方便地獲取到需要的鏈接,並在Scrapy爬蟲中進一步處理和訪問。
基於XPath表達式的LxmlLinkExtractor可以透過對網頁中的HTML標籤進行XPath表達式匹配,自動提取出匹配成功的鏈接。例如,我們希望從一個網頁中提取所有class屬性等於"storylink" 的a鏈接,可以使用以下程式碼:
from scrapy.linkextractors import LxmlLinkExtractor link_extractor = LxmlLinkExtractor(restrict_xpaths='//a[@class="storylink"]') links = link_extractor.extract_links(response)
restrict_xpaths參數指定了一個XPath表達式,用來匹配所有class屬性等於"storylink " 的a標籤。 LxmlLinkExtractor的使用方式和LinkExtractor類似,可以將提取到的連結保存在一個Link物件清單中。需要注意的是,由於LxmlLinkExtractor使用了lxml庫進行HTML解析,因此需要在專案的設定檔中加入以下程式碼:
# settings.py DOWNLOAD_HANDLERS = { 's3': None, }
以上程式碼可以停用Scrapy中預設的下載器,從而使用lxml庫的HTML解析器。
二、去重工具的作用及實作
在進行Web爬取時,連結去重是非常重要的,因為在大多數情況下,同一個網頁的不同連結是會重複出現的,如果不去重,就會造成重複爬取的問題,浪費頻寬和時間。因此,在Scrapy中引入了去重工具(Duplicate Filter),用來對已經爬取過的連結進行標記和判斷,避免重複訪問。
去重工具的原理是透過將已經訪問過的URL連結保存到一個資料結構中,然後對新的URL連結進行判斷是否已經訪問過,如果訪問過,則將該URL連結丟棄,否則將其加入到爬蟲的請求隊列中。 Scrapy內建了許多種去重工具,包括基於記憶體的Set類別去重器、基於磁碟的SQLite3去重器以及基於Redis的去重器等。不同的去重器有不同的適用場景,以下我們以Redis去重器為例進行說明。
Redis是一款高效能的NoSQL記憶體資料庫,可以支援分散式、持久化、資料結構豐富等進階特性,非常適合用來實現Scrapy的去重工具。 Scrapy中的Redis去重器可以透過對已經造訪過的URL連結進行標記,避免重複造訪。
Scrapy預設使用的是基於記憶體的Set類別去重器,如果需要使用Redis去重器,可以在專案的設定檔中加入以下程式碼:
# settings.py DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter" SCHEDULER = "scrapy_redis.scheduler.Scheduler" SCHEDULER_PERSIST = True REDIS_HOST = "localhost" REDIS_PORT = 6379
其中,DUPEFILTER_CLASS參數指定了去重工具使用的去重策略,這裡我們使用的是scrapy_redis.dupefilter.RFPDupeFilter,該去重器是基於Redis的set資料結構實現的。
SCHEDULER參數指定了調度器使用的調度策略,此處我們使用的是scrapy_redis.scheduler.Scheduler,該調度器是基於Redis的sorted set資料結構實現的。
SCHEDULER_PERSIST參數指定了調度器是否需要在Redis中持久化,即是否需要保存上一次爬取的狀態,從而避免重新爬取已經爬取過的URL。
REDIS_HOST和REDIS_PORT參數分別指定了Redis資料庫的IP位址和連接埠號,如果Redis資料庫不在本機,則需要設定對應的IP位址。
使用Redis去重器之后,需要在爬虫中添加redis_key参数,用来指定Redis中保存URL链接的key名。例如:
# spider.py class MySpider(scrapy.Spider): name = 'myspider' start_urls = ['http://example.com'] custom_settings = { 'REDIS_HOST': 'localhost', 'REDIS_PORT': 6379, 'DUPEFILTER_CLASS': 'scrapy_redis.dupefilter.RFPDupeFilter', 'SCHEDULER': 'scrapy_redis.scheduler.Scheduler', 'SCHEDULER_PERSIST': True, 'SCHEDULER_QUEUE_CLASS': 'scrapy_redis.queue.SpiderPriorityQueue', 'REDIS_URL': 'redis://user:pass@localhost:6379', 'ITEM_PIPELINES': { 'scrapy_redis.pipelines.RedisPipeline': 400, }, 'DOWNLOADER_MIDDLEWARES': { 'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None, 'scrapy_useragents.downloadermiddlewares.useragents.UserAgentsMiddleware': 500, }, 'FEED_URI': 'result.json', 'FEED_FORMAT': 'json', 'LOG_LEVEL': 'INFO', 'SPIDER_MIDDLEWARES': { 'scrapy.spidermiddlewares.httperror.HttpErrorMiddleware': 300, } } def __init__(self, *args, **kwargs): domain = kwargs.pop('domain', '') self.allowed_domains = filter(None, domain.split(',')) self.redis_key = '%s:start_urls' % self.name super(MySpider, self).__init__(*args, **kwargs) def parse(self, response): pass
以上是一个简单的爬虫示例,redis_key参数指定了在Redis中保存URL链接的键名为myspider:start_urls。在parse()方法中,需要编写自己的网页解析代码,提取出需要的信息。
三、总结
链接提取器和去重工具是Scrapy爬虫框架中非常重要的组件,它们可以大大简化我们编写爬虫的工作,并提高爬虫的效率。在使用Scrapy爬虫时,我们可以根据自己的需求选择不同的链接提取器和去重工具,从而实现更为高效和灵活的爬虫功能。
以上是Scrapy中的連結提取器與去重工具分析的詳細內容。更多資訊請關注PHP中文網其他相關文章!