分散式爬蟲總結和使用
使用scrapy-redis:
Scrapy_redis在scrapy的基礎上實現了更多,更強大的功能,具體體現在:reqeust去重,爬蟲持久化,和輕鬆實現分散式
安裝scrapy-redis:
pip3 install scrapy-redis
Scrapy-redis提供了下面四種元件(components):(意味著四個模組都要做相應的修改)
1.Scheduler
2.Duplication Filter
3.Item Pipeline
4.Base Spider
scrapy-redis工作流程
Scheduler:
Scrapy中跟“待爬佇列”直接相關的就是排程器Scheduler,它負責對新的request進行入列操作(加入Scrapy queue),取出下一個要爬取的request(從Scrapy queue中取出)等操作。它把待爬佇列按照優先順序建立了一個字典結構.
比如:
{
優先順序0 : 佇列0
優先順序1 : 佇列1
優先順序2 : 佇列2
}
然後根據request中的優先順序,來決定該入哪個佇列,出列時則按優先順序較小的優先出列。為了管理這個比較高階的佇列字典,Scheduler需要提供一系列的方法。但是原來的Scheduler已經無法使用,所以使用Scrapy-redis的scheduler元件。
Duplication Filter:
Scrapy中用集合實現這個request去重功能,Scrapy中把已經傳送的request指紋放入到一個集合中,把下一個request的指紋拿到集合中比對,如果該指紋存在於集合中,說明這個request傳送過了,如果沒有則繼續操作。這個核心的判重功能是這樣實現的:
def request_seen(self, request):
# 把請求轉化為指紋
fp = self.request_fingerprint(request)
# 這就是判重的核心操作 ,self.fingerprints就是指紋集合
if fp in self.fingerprints:
return True #直接返回
self.fingerprints.add(fp) #如果不在,就新增進去指紋集合
if self.file:
self.file.write(fp + os.linesep)
在scrapy-redis中去重是由Duplication Filter元件來實現的,它通過redis的set 不重複的特性,巧妙的實現了Duplication Filter去重。scrapy-redis排程器從引擎接受request,將request的指紋存⼊redis的set檢查是否重複,並將不重複的request push寫⼊redis的 request queue。
Item Pipeline:
引擎將(Spider返回的)爬取到的Item給Item Pipeline,scrapy-redis 的Item Pipeline將爬取到的 Item 存⼊redis的 items queue。
修改過Item Pipeline可以很方便的根據 key 從 items queue 提取item,從⽽實現 items processes叢集。
Base Spider:
不在使用scrapy原有的Spider類,重寫的RedisSpider繼承了Spider和RedisMixin這兩個類,RedisMixin是用來從redis讀取url的類。
當我們生成一個Spider繼承RedisSpider時,呼叫setup_redis函式,這個函式會去連線redis資料庫,然後會設定signals(訊號):
一個是當spider空閒時候的signal,會呼叫spider_idle函式,這個函式呼叫schedule_next_request函式,保證spider是一直活著的狀態,並且丟擲DontCloseSpider異常。
一個是當抓到一個item時的signal,會呼叫item_scraped函式,這個函式會呼叫schedule_next_request函式,獲取下一個request。
專案說明
使用scrapy-redis的example來修改 先從github上拿到scrapy-redis的示例,然後將裡面的example-project目錄移到指定的地址:
clone github scrapy-redis原始碼檔案
拿官方的專案範例:
mv scrapy-redis/example-project ~/scrapyredis-project
我們clone到的 scrapy-redis 原始碼中有自帶一個example-project專案,這個專案包含3個spider,分別是dmoz, myspider_redis,mycrawler_redis。
一.dmoz (class DmozSpider(CrawlSpider))
注意:這裡只用到Redis的去重和儲存功能,並沒有實現分散式
這個爬蟲繼承的是CrawlSpider,它是用來說明Redis的持續性,當我們第一次執行dmoz爬蟲,然後Ctrl + C停掉之後,再執行dmoz爬蟲,之前的爬取記錄是保留在Redis裡的。
分析起來,其實這就是一個 scrapy-redis 版 CrawlSpider 類,需要設定Rule規則,以及callback不能寫parse()方法。 執行方式:
scrapy crawl dmoz
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
class DmozSpider(CrawlSpider):
"""Follow categories and extract links."""
name = 'dmoz'
allowed_domains = ['dmoz.org']
start_urls = ['http://www.dmoz.org/']
#定義了一個url的提取規則,將滿足條件的交給callback函式處理
rules = [
Rule(LinkExtractor(
restrict_css=('.top-cat', '.sub-cat', '.cat-item')
), callback='parse_directory', follow=True),
]
def parse_directory(self, response):
for div in response.css('.title-and-desc'):
#這裡將獲取到的內容交給引擎
yield {
'name': div.css('.site-title::text').extract_first(),
'description': div.css('.site-descr::text').extract_first().strip(),
'link': div.css('a::attr(href)').extract_first(),
}
二.myspider_redis (class MySpider(RedisSpider))
這個爬蟲繼承了RedisSpider, 它能夠支援分散式的抓取,採用的是basic spider,需要寫parse函式。 其次就是不再有start_urls了,取而代之的是redis_key,scrapy-redis將key從Redis裡pop出來,成為請求的url地址。
from scrapy_redis.spiders import RedisSpider
class MySpider(RedisSpider):
"""Spider that reads urls from redis queue (myspider:start_urls)."""
name = 'myspider_redis'
#手動設定允許爬取的域
allowed_domains = ['設定允許爬取的域']
# 注意redis-key的格式:
redis_key = 'myspider:start_urls'
# 可選:等效於allowd_domains(),__init__方法按規定格式寫,使用時只需要修改super()裡的類名引數即可,一般不用
def __init__(self, *args, **kwargs):
# Dynamically define the allowed domains list.
domain = kwargs.pop('domain', '')
self.allowed_domains = filter(None, domain.split(','))
# 修改這裡的類名為當前類名
super(MySpider, self).__init__(*args, **kwargs)
def parse(self, response):
return {
'name': response.css('title::text').extract_first(),
'url': response.url,
}
注意: RedisSpider類 不需要寫start_urls:
- scrapy-redis 一般直接寫allowd_domains來指定需要爬取的域,也可以從在構造方法init()裡動態定義爬蟲爬取域範圍(一般不用)。
- 必須指定redis_key,即啟動爬蟲的命令,參考格式:redis_key = 'myspider:start_urls'
- 根據指定的格式,start_urls將在 Master端的 redis-cli 裡 lpush 到 Redis資料庫裡,RedisSpider 將在資料庫裡獲取start_urls
執行方式:
1.通過runspider方法執行爬蟲的py檔案(也可以分次執行多條),爬蟲(們)將處於等待準備狀態:
scrapy runspider myspider_redis.py
or
scrapy crawl myspider_redis
2.在Master端的redis-cli輸入push指令,參考格式(指定起始url):
lpush myspider:start_urls http://www.dmoz.org/
3.Slaver端爬蟲獲取到請求,開始爬取。
三.mycrawler_redis (class MyCrawler(RedisCrawlSpider))
這個RedisCrawlSpider類爬蟲繼承了RedisCrawlSpider,能夠支援分散式的抓取。因為採用的是crawlSpider,所以需要遵守Rule規則,以及callback不能寫parse()方法。
同樣也不再有start_urls了,取而代之的是redis_key,scrapy-redis將key從Redis裡pop出來,成為請求的url地址。
from scrapy.spiders import Rule
from scrapy.linkextractors import LinkExtractor
from scrapy_redis.spiders import RedisCrawlSpider
class MyCrawler(RedisCrawlSpider):
"""Spider that reads urls from redis queue (myspider:start_urls)."""
name = 'mycrawler_redis'
allowed_domains = ['設定允許爬取的域']
redis_key = 'mycrawler:start_urls'
rules = (
# follow all links
Rule(LinkExtractor(), callback='parse_page', follow=True),
)
# __init__方法必須按規定寫,使用時只需要修改super()裡的類名引數即可(一般不用)
def __init__(self, *args, **kwargs):
# Dynamically define the allowed domains list.
domain = kwargs.pop('domain', '')
self.allowed_domains = filter(None, domain.split(','))
# 修改這裡的類名為當前類名
super(MyCrawler, self).__init__(*args, **kwargs)
def parse_page(self, response):
return {
'name': response.css('title::text').extract_first(),
'url': response.url,
}
注意: 同樣的,RedisCrawlSpider類不需要寫start_urls:
執行方式:
1.scrapy runspider myspider_redis.py
2.lpush myspider:start_urls http://www.dmoz.org/
3.Slaver端爬蟲獲取到請求,開始爬取。
總結:
1 如果只是用到Redis的去重和儲存功能,就選第一種;
2 如果要寫分散式,則根據情況,選擇第二種、第三種;
3 通常情況下,會選擇用第三種方式編寫深度聚焦爬蟲。
相關文章
- 分散式爬蟲原理之分散式爬蟲原理分散式爬蟲
- 分散式爬蟲分散式爬蟲
- 分散式爬蟲原理分散式爬蟲
- 19--Scarpy05:增量式爬蟲、分散式爬蟲爬蟲分散式
- 使用Docker Swarm搭建分散式爬蟲叢集DockerSwarm分散式爬蟲
- .NET使用分散式網路爬蟲框架DotnetSpider快速開發爬蟲功能分散式爬蟲框架IDE
- Python分散式爬蟲(三) - 爬蟲基礎知識Python分散式爬蟲
- Python爬蟲教程-34-分散式爬蟲介紹Python爬蟲分散式
- 使用 Golang 寫爬蟲經驗總結Golang爬蟲
- 分散式爬蟲的部署之Gerapy分散式管理分散式爬蟲
- 分散式爬蟲的部署之Scrapyd分散式部署分散式爬蟲
- 分散式爬蟲有哪些使用代理IP的方法?分散式爬蟲
- 分散式爬蟲之知乎使用者資訊爬取分散式爬蟲
- 爬蟲(14) - Scrapy-Redis分散式爬蟲(1) | 詳解爬蟲Redis分散式
- 爬蟲專案總結爬蟲
- 爬蟲細節總結爬蟲
- 爬蟲個人總結爬蟲
- 基於java的分散式爬蟲Java分散式爬蟲
- [爬蟲架構] 如何設計一個分散式爬蟲架構爬蟲架構分散式
- 2個月精通Python爬蟲——3大爬蟲框架+6場實戰+反爬蟲技巧+分散式爬蟲Python爬蟲框架分散式
- 網路爬蟲流程總結爬蟲
- 分散式通用爬蟲管理平臺Crawlab分散式爬蟲
- 第一個分散式爬蟲專案分散式爬蟲
- 十分鐘搞懂分散式爬蟲分散式爬蟲
- scrapy之分散式爬蟲scrapy-redis分散式爬蟲Redis
- [Python3網路爬蟲開發實戰] 分散式爬蟲原理Python爬蟲分散式
- 分散式爬蟲很難嗎?用Python寫一個小白也能聽懂的分散式知乎爬蟲分散式爬蟲Python
- 猿人學爬蟲攻防賽總結爬蟲
- 分散式爬蟲的部署之Scrapyd批量部署分散式爬蟲
- python分散式爬蟲如何設計架構?Python分散式爬蟲架構
- 分散式鎖總結分散式
- 如何簡單高效地部署和監控分散式爬蟲專案分散式爬蟲
- Python之分散式爬蟲的實現步驟Python分散式爬蟲
- 分散式爬蟲的部署之Scrapyd對接Docker分散式爬蟲Docker
- 一入爬蟲深似海,總結python爬蟲學習筆記!爬蟲Python筆記
- 分散式事務總結分散式
- Win10+Python3.6配置Spark建立分散式爬蟲Win10PythonSpark分散式爬蟲
- Python-爬蟲工程師-面試總結Python爬蟲工程師面試