欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

爬蟲框架 Feapder 和 Scrapy 的對比分析

 更新時間:2021年09月17日 09:40:40   作者:Boris  
本篇文章在源碼層面比對 feapder、scrapy 、scrapy-redis 的設計,閱讀本文后,會加深您對 scrapy 以及 feapder 的了解,以及為什么推薦使用 feapder,剛興趣的朋友可以參考下面文章內(nèi)容

一、scrapy 分析

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

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

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

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

若想直接運行,需編寫如下文件,麻煩

from scrapy import cmdline


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

為什么必須通過命令行方式呢?因為 scrapy 是通過這種方式來加載項目中的 settings.py 文件的

3. 入庫 pipeline,不能批量入庫

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

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

二、scrapy-redis 分析

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

1. redis 中的任務可讀性不好

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

2. 取任務時直接彈出,會造成任務丟失

我們分析下 scrapy-redis 幾種任務隊列,取任務時都是直接把任務彈出來,如果任務剛彈出來爬蟲就意外退出,那剛彈出的這條任務就會丟失。

FifoQueue(先進先出隊列) 使用 list 集合

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

 

LifoQueue(先進后出隊列),使用 list 集合

scrapy-redis 默認使用 PriorityQueue 隊列,即優(yōu)先級隊列

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

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

需單獨維護個下發(fā)種子任務的腳本

三、feapder 分析

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

上述問題解決方案:

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

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

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

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

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

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

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

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


這里有人會有疑問:

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

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

若爬蟲意外退出,數(shù)據(jù)會不會丟?

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

入庫失敗了怎么辦?

答:入庫失敗,任務會重試,數(shù)據(jù)會重新入庫,若失敗次數(shù)到達配置的上限會報警

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

feapder 對請求里常用的字段沒有序列化,只有那些 json 不支持的對象才進行序列化

(5) 取任務時直接彈出,會造成任務丟失

feapder 在獲取任務時,沒直接彈出,任務采用 redis zset 集合存儲,每次只取小于當前時間搓分數(shù)的任務,同時將取到的任務分數(shù)修改為當前時間搓 +10 分鐘,防止其他爬蟲取到重復的任務。若爬蟲意外退出,這些取到的任務其實還在任務隊列里,并沒有丟失

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

feapder 支持三種去重方式:

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

(7)分布式爬蟲需單獨維護個下發(fā)種子任務的腳本

feapder 沒種子任務和子鏈接的分別, yield feapder.Request 都會把請求下發(fā)到任務隊列,我們可以在 start_requests 編寫下發(fā)種子任務的邏輯

這里又有人會有疑問了

我爬蟲啟動多份時, start_requests 不會重復調(diào)用,重復下發(fā)種子任務么?

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

那支持手動下發(fā)任務么?

答:支持,按照 feapder 的任務格式,往 redis 里扔任務就好,爬蟲支持常駐等待任務

四、三種爬蟲簡介

1. AirSpider

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

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

分布式爬蟲,支持啟多份,爬蟲意外終止,重啟后會斷點續(xù)爬

import feapder


class SpiderDemo(feapder.Spider):
    # 自定義數(shù)據(jù)庫,若項目中有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

批次爬蟲,擁有分布式爬蟲所有特性,支持分布式

import feapder


class BatchSpiderDemo(feapder.BatchSpider):
    # 自定義數(shù)據(jù)庫,若項目中有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中存放任務等信息的根key
        task_table="",  # mysql中的任務表
        task_keys=["id", "xxx"],  # 需要獲取任務表里的字段名,可添加多個
        task_state="state",  # mysql中任務狀態(tài)字段
        batch_record_table="xxx_batch_record",  # mysql中的批次記錄表
        batch_name="xxx",  # 批次名字
        batch_interval=7,  # 批次周期 天為單位 若為小時 可寫 1 / 24
    )

    # spider.start_monitor_task() # 下發(fā)及監(jiān)控任務
    spider.start() # 采集

任務調(diào)度過程:

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

封裝了批次(周期)采集的邏輯,如我們指定 7 天一個批次,那么如果爬蟲 3 天就將任務做完,爬蟲重啟也不會重復采集,而是等到第 7 天之后啟動的時候才會采集下一批次。

同時批次爬蟲會預估采集速度,若按照當前速度在指定的時間內(nèi)采集不完,會發(fā)出報警

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

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

main.py 為啟動入口

1. feapder 部署

feapder 有對應的管理平臺 feaplat ,當然這個管理平臺也支持部署其他腳本

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

-w1791:

任務啟動后,可看到實例及實時日志

-w1785:

爬蟲監(jiān)控面板可實時看到爬蟲運行情況,監(jiān)控數(shù)據(jù)保留半年,滾動刪除

六、采集效率測試

請求百度 1 萬次,線程都開到 300,測試耗時

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)}

耗時: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("耗時:{}".format(time.time() - self.start_time))


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

結(jié)果:耗時:136.10122799873352

總結(jié):

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

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

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

相關文章

  • python持久性管理pickle模塊詳細介紹

    python持久性管理pickle模塊詳細介紹

    這篇文章主要介紹了python持久性管理pickle模塊詳細介紹,本文講解了什么是持久性、一些經(jīng)過 pickle 的 Python等內(nèi)容,并講給出了18個使用示例,需要的朋友可以參考下
    2015-02-02
  • Python中__name__的使用實例

    Python中__name__的使用實例

    這篇文章主要介紹了Python中__name__的使用實例,并總結(jié)了兩種情況下__name__的值會是什么,需要的朋友可以參考下
    2015-04-04
  • 淺析python標準庫中的glob

    淺析python標準庫中的glob

    glob 文件名模式匹配,不用遍歷整個目錄判斷每個文件是不是符合。這篇文章主要介紹了python標準庫中的glob的相關知識,本文通過實例代碼給大家介紹的非常詳細,需要的朋友可以參考下
    2020-03-03
  • Python手動或自動協(xié)程操作方法解析

    Python手動或自動協(xié)程操作方法解析

    這篇文章主要介紹了Python手動或自動協(xié)程操作方法解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-06-06
  • Python實現(xiàn)爬蟲IP負載均衡和高可用集群的示例代碼

    Python實現(xiàn)爬蟲IP負載均衡和高可用集群的示例代碼

    做大型爬蟲項目經(jīng)常遇到請求頻率過高的問題,這里需要說的是使用爬蟲IP可以提高抓取效率,本文主要介紹了Python實現(xiàn)爬蟲IP負載均衡和高可用集群的示例代碼,感興趣的可以了解一下
    2023-12-12
  • Pyqt5打開電腦攝像頭進行拍照的實現(xiàn)示例

    Pyqt5打開電腦攝像頭進行拍照的實現(xiàn)示例

    本文介紹了如何使用Pyqt5來控制攝像頭拍照,通過構(gòu)建一個簡單的用戶界面,我們可以實現(xiàn)從攝像頭實時獲取圖像,保存圖片,感興趣的可以了解一下
    2023-08-08
  • 使用Python做垃圾分類的原理及實例代碼附源碼

    使用Python做垃圾分類的原理及實例代碼附源碼

    這篇文章主要介紹了用Python做垃圾分類的實現(xiàn)原理,本文通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值 ,需要的朋友可以參考下
    2019-07-07
  • python實現(xiàn)無證書加密解密實例

    python實現(xiàn)無證書加密解密實例

    這篇文章主要介紹了python實現(xiàn)無證書加密解密的方法,實例講述了無證書加密解密的原理與具體實現(xiàn)過程,非常具有實用價值,需要的朋友可以參考下
    2014-10-10
  • matplotlib制作雷達圖報錯ValueError的實現(xiàn)

    matplotlib制作雷達圖報錯ValueError的實現(xiàn)

    這篇文章主要介紹了matplotlib制作雷達圖報錯ValueError的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-01-01
  • python接入GoogleAuth的實現(xiàn)

    python接入GoogleAuth的實現(xiàn)

    經(jīng)常會用到GoogleAuth作為二次驗證碼,本文主要介紹了python接入GoogleAuth的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-08-08

最新評論