<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          干貨!爬蟲框架 Feapder 和 Scrapy 的對(duì)比分析

          共 7152字,需瀏覽 15分鐘

           ·

          2021-09-20 04:10

          這是「進(jìn)擊的Coder」的第 476?篇技術(shù)分享作者:Boris來(lái)源:程序員技術(shù)寶典

          閱讀本文大概需要 8 分鐘。


          本篇文章在源碼層面比對(duì) feapder、scrapy 、scrapy-redis 的設(shè)計(jì),閱讀本文后,會(huì)加深您對(duì) scrapy 以及 feapder 的了解,以及為什么推薦使用 feapder

          scrapy 分析

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

          scrapy 自帶的重試中間件只支持請(qǐng)求重試,解析函數(shù)內(nèi)異常或者數(shù)據(jù)入庫(kù)異常不會(huì)重試,但爬蟲在請(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)的,沒法直接批量入庫(kù),但數(shù)據(jù)量大的時(shí)候,我們往往是需要批量入庫(kù)的,以節(jié)省數(shù)據(jù)庫(kù)的性能開銷,加快入庫(kù)速度

          scrapy-redis 分析

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

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

          6e2c68318e243c60f8b4130a44b9f3ee.webp

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

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

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

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

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

            56833bf3b41cc607f433164003f06469.webp
          3. LifoQueue(先進(jìn)后出隊(duì)列),使用 list 集合

            984096cac356f4ebce631d9a41be5fee.webp

          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)存容量要求很高

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

          feapder 分析

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

          上述問題解決方案

          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 腳本沒區(qū)別,可以借助 pycharm 調(diào)試。

          除了斷點(diǎn)調(diào)試,feapder 還支持將爬蟲轉(zhuǎn)為 Debug 爬蟲,Debug 爬蟲模式下,可指定請(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ì)有疑問

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

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

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

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

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

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

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

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

          bc5ba9e37ed104455f545624ab61895c.webp

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

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

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

          feapder 支持三種去重方式

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

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

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

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

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

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

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

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

          三種爬蟲簡(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

          分布式爬蟲,支持啟多份,爬蟲意外終止,重啟后會(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

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

          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ā)到爬蟲
          3. 爬蟲獲取到種子任務(wù)后,調(diào)度到 start_requests,拼接實(shí)際的請(qǐng)求,下發(fā)到 redis
          4. 爬蟲從 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ā)到爬蟲

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

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

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

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

          b968c9e5f16cf5b8bb801bdaec7704db.webp

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

          feapder 部署

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

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

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

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

            0f7a18fb2ef52291fe660495c689edc6.webp

          采集效率測(cè)試

          請(qǐng)求百度 1 萬(wàn)次,線程都開到 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é)

          本文主要分析了scrapyscrapy-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ù)爬蟲需求

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

          feapder 爬蟲文檔:https://boris-code.gitee.io/feapder/#/

          33f8dfb1fa40ee6d589bedf408a3760a.webp

          feaplat 管理平臺(tái):https://boris-code.gitee.io/feapder/#/feapder_platform/%E7%88%AC%E8%99%AB%E7%AE%A1%E7%90%86%E7%B3%BB%E7%BB%9F

          1. 爬蟲管理系統(tǒng)不僅支持 feapderscrapy,且支持執(zhí)行任何腳本,可以把該系統(tǒng)理解成腳本托管的平臺(tái) 。

          2. 支持集群

          3. 工作節(jié)點(diǎn)根據(jù)配置定時(shí)啟動(dòng),執(zhí)行完釋放,不常駐

          4. 一個(gè)worker內(nèi)只運(yùn)行一個(gè)爬蟲,worker彼此之間隔離,互不影響。

          5. 支持管理員普通用戶兩種角色

          6. 可自定義爬蟲端鏡像

          26e0fb113c39c6f5fdd515a097969725.webp

          End

          「進(jìn)擊的Coder」專屬學(xué)習(xí)群已正式成立,搜索「CQCcqc4」添加崔慶才的個(gè)人微信或者掃描下方二維碼拉您入群交流學(xué)習(xí)。


          看完記得關(guān)注@進(jìn)擊的Coder
          及時(shí)收看更多好文
          ↓↓↓


          崔慶才的「進(jìn)擊的Coder」知識(shí)星球已正式成立,感興趣的可以查看《我創(chuàng)辦了一個(gè)知識(shí)星球》了解更多內(nèi)容,歡迎您的加入:



          好文和朋友一起看~
          瀏覽 68
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  操b在线视频播放 | 三级片在线观看视频网站 | 丁香久久五月 | www爆操美女骚穴视频www | 免费成人性爱视频 |