人妖在线一区,国产日韩欧美一区二区综合在线,国产啪精品视频网站免费,欧美内射深插日本少妇

新聞動(dòng)態(tài)

爬蟲(chóng)框架 Feapder 和 Scrapy 的對(duì)比分析

發(fā)布日期:2022-01-03 05:28 | 文章來(lái)源:源碼中國(guó)

一、scrapy 分析

1. 解析函數(shù)或數(shù)據(jù)入庫(kù)出錯(cuò),不會(huì)重試,會(huì)造成一定的數(shù)據(jù)丟失

scrapy 自帶的重試中間件只支持請(qǐng)求重試,解析函數(shù)內(nèi)異?;蛘邤?shù)據(jù)入庫(kù)異常不會(huì)重試,但爬蟲(chóng)在請(qǐng)求數(shù)據(jù)時(shí),往往會(huì)有一些意想不到的頁(yè)面返回來(lái),若我們解析異常了,這條任務(wù)豈不是丟了。

當(dāng)然有些大佬可以通過(guò)一些自定義中間件的方式或者加異常捕獲的方式來(lái)解決,我們這里只討論自帶的。

2. 運(yùn)行方式,需借助命令行,不方便調(diào)試

若想直接運(yùn)行,需編寫如下文件,麻煩

from scrapy import cmdline

name = 'spider_name'
cmd = 'scrapy crawl {0}'.format(name)
cmdline.execute(cmd.split()

為什么必須通過(guò)命令行方式呢?因?yàn)?scrapy 是通過(guò)這種方式來(lái)加載項(xiàng)目中的 settings.py 文件的

3. 入庫(kù) pipeline,不能批量入庫(kù)

class TestScrapyPipeline(object):
 def process_item(self, item, spider):
  return item

pipelines 里的 item 是一條條傳過(guò)來(lái)的,沒(méi)法直接批量入庫(kù),但數(shù)據(jù)量大的時(shí)候,我們往往是需要批量入庫(kù)的,以節(jié)省數(shù)據(jù)庫(kù)的性能開(kāi)銷,加快入庫(kù)速度

二、scrapy-redis 分析

scrapy-redis 任務(wù)隊(duì)列使用 redis 做的,初始任務(wù)存在 [spider_name]:start_urls 里,爬蟲(chóng)產(chǎn)生的子鏈接存在 [spider_name]:requests 下,那么我們先看下 redis 里的任務(wù)

1. redis 中的任務(wù)可讀性不好

我們看下子鏈任務(wù),可以看到存儲(chǔ)的是序列化后的,這種可讀性不好

2. 取任務(wù)時(shí)直接彈出,會(huì)造成任務(wù)丟失

我們分析下 scrapy-redis 幾種任務(wù)隊(duì)列,取任務(wù)時(shí)都是直接把任務(wù)彈出來(lái),如果任務(wù)剛彈出來(lái)爬蟲(chóng)就意外退出,那剛彈出的這條任務(wù)就會(huì)丟失。

FifoQueue(先進(jìn)先出隊(duì)列) 使用 list 集合

PriorityQueue(優(yōu)先級(jí)隊(duì)列),使用 zset 集合

LifoQueue(先進(jìn)后出隊(duì)列),使用 list 集合

scrapy-redis 默認(rèn)使用 PriorityQueue 隊(duì)列,即優(yōu)先級(jí)隊(duì)列

3. 去重耗內(nèi)存

使用 redis 的 set 集合對(duì) request 指紋進(jìn)行去重,這種面對(duì)海量數(shù)據(jù)去重對(duì) redis 內(nèi)存容量要求很高

需單獨(dú)維護(hù)個(gè)下發(fā)種子任務(wù)的腳本

三、feapder 分析

feapder 內(nèi)置 AirSpider 、 Spider 、 BatchSpider 三種爬蟲(chóng),AirSpider 對(duì)標(biāo) Scrapy,Spider 對(duì)標(biāo) scrapy-redis,BatchSpider 則是應(yīng)于周期性采集的需求,如每周采集一次商品的銷量等場(chǎng)景

上述問(wèn)題解決方案:

(1)解析函數(shù)或數(shù)據(jù)入庫(kù)出錯(cuò),不會(huì)重試,會(huì)造成一定的數(shù)據(jù)丟失

feapder 對(duì)請(qǐng)求、解析、入庫(kù)進(jìn)行了全面的異常捕獲,任何位置出現(xiàn)異常會(huì)自動(dòng)重試請(qǐng)求,若有不想重試的請(qǐng)求也可指定

(2)運(yùn)行方式,需借助命令行,不方便調(diào)試

feapder 支持直接運(yùn)行,跟普通的 python 腳本沒(méi)區(qū)別,可以借助 pycharm 調(diào)試。

除了斷點(diǎn)調(diào)試,feapder 還支持將爬蟲(chóng)轉(zhuǎn)為 Debug 爬蟲(chóng),Debug 爬蟲(chóng)模式下,可指定請(qǐng)求與解析函數(shù),生產(chǎn)的任務(wù)與數(shù)據(jù)不會(huì)污染正常環(huán)境

(3)入庫(kù) pipeline,不能批量入庫(kù)

feapder 生產(chǎn)的數(shù)據(jù)會(huì)暫存內(nèi)存的隊(duì)列里,積攢一定量級(jí)或每 0.5 秒批量傳給 pipeline,方便批量入庫(kù)

def save_items(self, table, items: List[Dict]) -> bool:
 pass

這里有人會(huì)有疑問(wèn):

數(shù)據(jù)放到內(nèi)存里了,會(huì)不會(huì)造成擁堵?

答:不會(huì),這里限制了最高能積攢 5000 條的上限,若到達(dá)上限后,爬蟲(chóng)線程會(huì)強(qiáng)制將數(shù)據(jù)入庫(kù),然后再生產(chǎn)數(shù)據(jù)

若爬蟲(chóng)意外退出,數(shù)據(jù)會(huì)不會(huì)丟?

答:不會(huì),任務(wù)會(huì)在數(shù)據(jù)入庫(kù)后再刪除,若意外退出了,產(chǎn)生這些數(shù)據(jù)的任務(wù)會(huì)重做

入庫(kù)失敗了怎么辦?

答:入庫(kù)失敗,任務(wù)會(huì)重試,數(shù)據(jù)會(huì)重新入庫(kù),若失敗次數(shù)到達(dá)配置的上限會(huì)報(bào)警

(4)redis 中的任務(wù)可讀性不好

feapder 對(duì)請(qǐng)求里常用的字段沒(méi)有序列化,只有那些 json 不支持的對(duì)象才進(jìn)行序列化

(5)取任務(wù)時(shí)直接彈出,會(huì)造成任務(wù)丟失

feapder 在獲取任務(wù)時(shí),沒(méi)直接彈出,任務(wù)采用 redis zset 集合存儲(chǔ),每次只取小于當(dāng)前時(shí)間搓分?jǐn)?shù)的任務(wù),同時(shí)將取到的任務(wù)分?jǐn)?shù)修改為當(dāng)前時(shí)間搓 +10 分鐘,防止其他爬蟲(chóng)取到重復(fù)的任務(wù)。若爬蟲(chóng)意外退出,這些取到的任務(wù)其實(shí)還在任務(wù)隊(duì)列里,并沒(méi)有丟失

(6)去重耗內(nèi)存

feapder 支持三種去重方式:

  • 內(nèi)存去重:采用可擴(kuò)展的 bloomfilter 結(jié)構(gòu),基于內(nèi)存,去重一萬(wàn)條數(shù)據(jù)約 0.5 秒,一億條數(shù)據(jù)占用內(nèi)存約 285MB
  • 臨時(shí)去重:采用 redis zset 集合存儲(chǔ)數(shù)據(jù)的 md5 值,去重可指定時(shí)效性。去重一萬(wàn)條數(shù)據(jù)約 0.26 秒,一億條數(shù)據(jù)占用內(nèi)存約 1.43G
  • 永久去重:采用可擴(kuò)展的 bloomfilter 結(jié)構(gòu),基于 redis,去重一萬(wàn)條數(shù)據(jù)約 0.5 秒,一億條數(shù)據(jù)占用內(nèi)存約 285 MB

(7)分布式爬蟲(chóng)需單獨(dú)維護(hù)個(gè)下發(fā)種子任務(wù)的腳本

feapder 沒(méi)種子任務(wù)和子鏈接的分別, yield feapder.Request 都會(huì)把請(qǐng)求下發(fā)到任務(wù)隊(duì)列,我們可以在 start_requests 編寫下發(fā)種子任務(wù)的邏輯

這里又有人會(huì)有疑問(wèn)了

我爬蟲(chóng)啟動(dòng)多份時(shí), start_requests 不會(huì)重復(fù)調(diào)用,重復(fù)下發(fā)種子任務(wù)么?

答:不會(huì),分布式爬蟲(chóng)在調(diào)用 start_requests 時(shí),會(huì)加進(jìn)程鎖,保證只能有一個(gè)爬蟲(chóng)調(diào)用這個(gè)函數(shù)。并且若任務(wù)隊(duì)列中有任務(wù)時(shí),爬蟲(chóng)會(huì)走斷點(diǎn)續(xù)爬的邏輯,不會(huì)執(zhí)行 start_requests

那支持手動(dòng)下發(fā)任務(wù)么?

答:支持,按照 feapder 的任務(wù)格式,往 redis 里扔任務(wù)就好,爬蟲(chóng)支持常駐等待任務(wù)

四、三種爬蟲(chóng)簡(jiǎn)介

1. AirSpider

使用 PriorityQueue 作為內(nèi)存任務(wù)隊(duì)列,不支持分布式,示例代碼

import feapder

class AirSpiderDemo(feapder.AirSpider):
 def start_requests(self):
  yield feapder.Request("https://www.baidu.com")
 def parse(self, request, response):
  print(response)

if __name__ == "__main__":
 AirSpiderDemo().start()

2. Spider

分布式爬蟲(chóng),支持啟多份,爬蟲(chóng)意外終止,重啟后會(huì)斷點(diǎn)續(xù)爬

import feapder

class SpiderDemo(feapder.Spider):
 # 自定義數(shù)據(jù)庫(kù),若項(xiàng)目中有setting.py文件,此自定義可刪除
 __custom_setting__ = dict(
  REDISDB_IP_PORTS="localhost:6379", REDISDB_USER_PASS="", REDISDB_DB=0
 )
 def start_requests(self):
  yield feapder.Request("https://www.baidu.com")
 def parse(self, request, response):
  print(response)

if __name__ == "__main__":
 SpiderDemo(redis_key="xxx:xxx").start()

3. BatchSpider

批次爬蟲(chóng),擁有分布式爬蟲(chóng)所有特性,支持分布式

import feapder

class BatchSpiderDemo(feapder.BatchSpider):
 # 自定義數(shù)據(jù)庫(kù),若項(xiàng)目中有setting.py文件,此自定義可刪除
 __custom_setting__ = dict(
  REDISDB_IP_PORTS="localhost:6379",
  REDISDB_USER_PASS="",
  REDISDB_DB=0,
  MYSQL_IP="localhost",
  MYSQL_PORT=3306,
  MYSQL_DB="feapder",
  MYSQL_USER_NAME="feapder",
  MYSQL_USER_PASS="feapder123",
 )
 def start_requests(self, task):
  yield feapder.Request("https://www.baidu.com")
 def parse(self, request, response):
  print(response)

if __name__ == "__main__":
 spider = BatchSpiderDemo(
  redis_key="xxx:xxxx",  # redis中存放任務(wù)等信息的根key
  task_table="",  # mysql中的任務(wù)表
  task_keys=["id", "xxx"],  # 需要獲取任務(wù)表里的字段名,可添加多個(gè)
  task_state="state",  # mysql中任務(wù)狀態(tài)字段
  batch_record_table="xxx_batch_record",  # mysql中的批次記錄表
  batch_name="xxx",  # 批次名字
  batch_interval=7,  # 批次周期 天為單位 若為小時(shí) 可寫 1 / 24
 )
 # spider.start_monitor_task() # 下發(fā)及監(jiān)控任務(wù)
 spider.start() # 采集

任務(wù)調(diào)度過(guò)程:

  1. mysql 中批量取出一批種子任務(wù)
  2. 下發(fā)到爬蟲(chóng)
  3. 爬蟲(chóng)獲取到種子任務(wù)后,調(diào)度到 start_requests,拼接實(shí)際的請(qǐng)求,下發(fā)到 redis
  4. 爬蟲(chóng)從 redis 中獲取到任務(wù),調(diào)用解析函數(shù)解析數(shù)據(jù)
  5. 子鏈接入 redis,數(shù)據(jù)入庫(kù)
  6. 種子任務(wù)完成,更新種子任務(wù)狀態(tài)
  7. redis 中任務(wù)量過(guò)少,則繼續(xù)從 mysql 中批量取出一批未做的種子任務(wù)下發(fā)到爬蟲(chóng)

封裝了批次(周期)采集的邏輯,如我們指定 7 天一個(gè)批次,那么如果爬蟲(chóng) 3 天就將任務(wù)做完,爬蟲(chóng)重啟也不會(huì)重復(fù)采集,而是等到第 7 天之后啟動(dòng)的時(shí)候才會(huì)采集下一批次。

同時(shí)批次爬蟲(chóng)會(huì)預(yù)估采集速度,若按照當(dāng)前速度在指定的時(shí)間內(nèi)采集不完,會(huì)發(fā)出報(bào)警

五、feapder 項(xiàng)目結(jié)構(gòu)

上述的三種爬蟲(chóng)例子修改配置后可以直接運(yùn)行,但對(duì)于大型項(xiàng)目,可能會(huì)有就好多爬蟲(chóng)組成。feapder 支持創(chuàng)建項(xiàng)目,項(xiàng)目結(jié)構(gòu)如下:

main.py 為啟動(dòng)入口

1. feapder 部署

feapder 有對(duì)應(yīng)的管理平臺(tái) feaplat ,當(dāng)然這個(gè)管理平臺(tái)也支持部署其他腳本

在任務(wù)列表里配置啟動(dòng)命令,調(diào)度周期以及爬蟲(chóng)數(shù)等。 爬蟲(chóng)數(shù) 這個(gè)對(duì)于分布式爬蟲(chóng)是非常爽的,可一鍵啟動(dòng)幾十上百份爬蟲(chóng),再也不需要一個(gè)個(gè)部署了

-w1791:

任務(wù)啟動(dòng)后,可看到實(shí)例及實(shí)時(shí)日志

-w1785:

爬蟲(chóng)監(jiān)控面板可實(shí)時(shí)看到爬蟲(chóng)運(yùn)行情況,監(jiān)控?cái)?shù)據(jù)保留半年,滾動(dòng)刪除

六、采集效率測(cè)試

請(qǐng)求百度 1 萬(wàn)次,線程都開(kāi)到 300,測(cè)試耗時(shí)

scrapy:

class BaiduSpider(scrapy.Spider):
 name = 'baidu'
 allowed_domains = ['baidu.com']
 start_urls = ['https://baidu.com/'] * 10000
 def parse(self, response):
  print(response)

結(jié)果:

{'downloader/request_bytes': 4668123,
'downloader/request_count': 20002,
'downloader/request_method_count/GET': 20002,
'downloader/response_bytes': 17766922,
'downloader/response_count': 20002,
'downloader/response_status_count/200': 10000,
'downloader/response_status_count/302': 10002,
'finish_reason': 'finished',
'finish_time': datetime.datetime(2021, 9, 13, 12, 22, 26, 638611),
'log_count/DEBUG': 20003,
'log_count/INFO': 9,
'memusage/max': 74240000,
'memusage/startup': 58974208,
'response_received_count': 10000,
'scheduler/dequeued': 20002,
'scheduler/dequeued/memory': 20002,
'scheduler/enqueued': 20002,
'scheduler/enqueued/memory': 20002,
'start_time': datetime.datetime(2021, 9, 13, 12, 19, 58, 489472)}

耗時(shí):148.149139 秒

feapder:

import feapder
import time

class AirSpiderDemo(feapder.AirSpider):
 def start_requests(self):
  for i in range(10000):
yield feapder.Request("https://www.baidu.com")
 def parse(self, request, response):
  print(response)
 def start_callback(self):
  self.start_time = time.time()
 def end_callback(self):
  print("耗時(shí):{}".format(time.time() - self.start_time))

if __name__ == "__main__":
 AirSpiderDemo(thread_count=300).start()

結(jié)果:耗時(shí):136.10122799873352

總結(jié):

本文主要分析了 scrapy scrapy-redis 的痛點(diǎn)以及 feapder 是如何解決的,當(dāng)然 scrapy 也有優(yōu)點(diǎn),比如社區(qū)活躍、中間件靈活等。但在保證數(shù)據(jù)及任務(wù)不丟的場(chǎng)景,報(bào)警監(jiān)控等場(chǎng)景 feapder 完勝 scrapy 。并且 feapder 是基于實(shí)際業(yè)務(wù),做過(guò)大大小小 100 多個(gè)項(xiàng)目,耗時(shí) 5 年打磨出來(lái)的,因此可滿足絕大多數(shù)爬蟲(chóng)需求

效率方面,請(qǐng)求百度 1 萬(wàn)次,同為 300 線程的情況下,feapder 耗時(shí) 136 秒,scrapy 耗時(shí) 148 秒,算上網(wǎng)絡(luò)的波動(dòng),其實(shí)效率差不多。

到此這篇關(guān)于爬蟲(chóng)框架 Feapder Scrapy 的對(duì)比分析的文章就介紹到這了,更多相關(guān)爬蟲(chóng)框架 Feapder Scrapy 的對(duì)比內(nèi)容請(qǐng)搜索本站以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持本站!

版權(quán)聲明:本站文章來(lái)源標(biāo)注為YINGSOO的內(nèi)容版權(quán)均為本站所有,歡迎引用、轉(zhuǎn)載,請(qǐng)保持原文完整并注明來(lái)源及原文鏈接。禁止復(fù)制或仿造本網(wǎng)站,禁止在非www.sddonglingsh.com所屬的服務(wù)器上建立鏡像,否則將依法追究法律責(zé)任。本站部分內(nèi)容來(lái)源于網(wǎng)友推薦、互聯(lián)網(wǎng)收集整理而來(lái),僅供學(xué)習(xí)參考,不代表本站立場(chǎng),如有內(nèi)容涉嫌侵權(quán),請(qǐng)聯(lián)系alex-e#qq.com處理。

相關(guān)文章

實(shí)時(shí)開(kāi)通

自選配置、實(shí)時(shí)開(kāi)通

免備案

全球線路精選!

全天候客戶服務(wù)

7x24全年不間斷在線

專屬顧問(wèn)服務(wù)

1對(duì)1客戶咨詢顧問(wèn)

在線
客服

在線客服:7*24小時(shí)在線

客服
熱線

400-630-3752
7*24小時(shí)客服服務(wù)熱線

關(guān)注
微信

關(guān)注官方微信
頂部