日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > python >内容正文

python

python分布式爬虫系统_如何构建一个分布式爬虫:理论篇

發(fā)布時間:2024/1/23 python 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python分布式爬虫系统_如何构建一个分布式爬虫:理论篇 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

前言

本系列文章計劃分三個章節(jié)進(jìn)行講述,分別是理論篇、基礎(chǔ)篇和實戰(zhàn)篇。理論篇主要為構(gòu)建分布式爬蟲而儲備的理論知識,基礎(chǔ)篇會基于理論篇的知識寫一個簡易的分布式爬蟲,實戰(zhàn)篇則會以微博為例,教大家做一個比較完整且足夠健壯的分布式微博爬蟲。通過這三篇文章,希望大家能掌握如何構(gòu)建一個分布式爬蟲的方法;能舉一反三,將celery用于除爬蟲外的其它場景。目前基本上的博客都是教大家使用scrapyd或者scrapy-redis構(gòu)建分布式爬蟲,本系列文章會從另外一個角度講述如何用requests+celery構(gòu)建一個健壯的、可伸縮并且可擴展的分布式爬蟲。

本系列文章屬于爬蟲進(jìn)階文章,期望受眾是具有一定Python基礎(chǔ)知識和編程能力、有爬蟲經(jīng)驗并且希望提升自己的同學(xué)。小白要是感興趣,也可以看看,看不懂的話,可以等有了一定基礎(chǔ)和經(jīng)驗后回過頭來再看。

另外一點說明,本系列文章不是旨在構(gòu)建一個分布式爬蟲框架或者分布式任務(wù)調(diào)度框架,而是利用現(xiàn)有的分布式任務(wù)調(diào)度工具來實現(xiàn)分布式爬蟲,所以請輕噴。

分布式爬蟲概覽

何謂分布式爬蟲?

通俗的講,分布式爬蟲就是多臺機器多個 spider 對多個 url 的同時處理問題,分布式的方式可以極大提高程序的抓取效率。

構(gòu)建分布式爬蟲通暢需要考慮的問題

(1)如何能保證多臺機器同時抓取同一個URL?

(2)如果某個節(jié)點掛掉,會不會影響其它節(jié)點,任務(wù)如何繼續(xù)?

(3)既然是分布式,如何保證架構(gòu)的可伸縮性和可擴展性?不同優(yōu)先級的抓取任務(wù)如何進(jìn)行資源分配和調(diào)度?

基于上述問題,我選擇使用celery作為分布式任務(wù)調(diào)度工具,是分布式爬蟲中任務(wù)和資源調(diào)度的核心模塊。它會把所有任務(wù)都通過消息隊列發(fā)送給各個分布式節(jié)點進(jìn)行執(zhí)行,所以可以很好的保證url不會被重復(fù)抓取;它在檢測到worker掛掉的情況下,會嘗試向其他的worker重新發(fā)送這個任務(wù)信息,這樣第二個問題也可以得到解決;celery自帶任務(wù)路由,我們可以根據(jù)實際情況在不同的節(jié)點上運行不同的抓取任務(wù)(在實戰(zhàn)篇我會講到)。本文主要就是帶大家了解一下celery的方方面面(有celery相關(guān)經(jīng)驗的同學(xué)和大牛可以直接跳過了)

Celery知識儲備

celery基礎(chǔ)講解

按celery官網(wǎng)的介紹來說

Celery 是一個簡單、靈活且可靠的,處理大量消息的分布式系統(tǒng),并且提供維護(hù)這樣一個系統(tǒng)的必需工具。它是一個專注于實時處理的任務(wù)隊列,同時也支持任務(wù)調(diào)度。

下面幾個關(guān)于celery的核心知識點

broker:翻譯過來叫做中間人。它是一個消息傳輸?shù)闹虚g件,可以理解為一個郵箱。每當(dāng)應(yīng)用程序調(diào)用celery的異步任務(wù)的時候,會向broker傳遞消息,而后celery的worker將會取到消息,執(zhí)行相應(yīng)程序。這其實就是消費者和生產(chǎn)者之間的橋梁。

backend: 通常程序發(fā)送的消息,發(fā)完就完了,可能都不知道對方時候接受了。為此,celery實現(xiàn)了一個backend,用于存儲這些消息以及celery執(zhí)行的一些消息和結(jié)果。

worker: Celery類的實例,作用就是執(zhí)行各種任務(wù)。注意在celery3.1.25后windows是不支持celery worker的!

producer: 發(fā)送任務(wù),將其傳遞給broker

beat: celery實現(xiàn)的定時任務(wù)。可以將其理解為一個producer,因為它也是通過網(wǎng)絡(luò)調(diào)用定時將任務(wù)發(fā)送給worker執(zhí)行。注意在windows上celery是不支持定時任務(wù)的!

下面是關(guān)于celery的架構(gòu)示意圖,結(jié)合上面文字的話應(yīng)該會更好理解

由于celery只是任務(wù)隊列,而不是真正意義上的消息隊列,它自身不具有存儲數(shù)據(jù)的功能,所以broker和backend需要通過第三方工具來存儲信息,celery官方推薦的是 RabbitMQ和Redis,另外mongodb等也可以作為broker或者backend,可能不會很穩(wěn)定,我們這里選擇Redis作為broker兼backend。

關(guān)于redis的安裝和配置可以查看這里

實際例子

先安裝celery

pip install celery

我們以官網(wǎng)給出的例子來做說明,并對其進(jìn)行擴展。首先在項目根目錄下,這里我新建一個項目叫做celerystudy,然后切換到該項目目錄下,新建文件tasks.py,然后在其中輸入下面代碼

from celery import Celery

app = Celery('tasks', broker='redis://:''@223.129.0.190:6379/2', backend='redis://:''@223.129.0.190:6379/3')

@app.task

def add(x, y):

return x + y

這里我詳細(xì)講一下代碼:我們先通過app=Celery()來實例化一個celery對象,在這個過程中,我們指定了它的broker,是redis的db 2,也指定了它的backend,是redis的db3, broker和backend的連接形式大概是這樣

redis://:password@hostname:port/db_number

然后定義了一個add函數(shù),重點是@app.task,它的作用在我看來就是**將add()

注冊為一個類似服務(wù)的東西,本來只能通過本地調(diào)用的函數(shù)被它裝飾后,就可以通過網(wǎng)絡(luò)來調(diào)用。這個tasks.py中的app就是一個worker。它可以有很多任務(wù),比如這里的任務(wù)函數(shù)add。我們再通過在命令行切換到項目根目錄**,執(zhí)行

celery -A tasks worker -l info

啟動成功后就是下圖所示的樣子

這里我說一下各個參數(shù)的意思,-A指定的是app(即Celery實例)所在的文件模塊,我們的app是放在tasks.py中,所以這里是 tasks;worker表示當(dāng)前以worker的方式運行,難道還有別的方式?對的,比如運行定時任務(wù)就不用指定worker這個關(guān)鍵字; -l info表示該worker節(jié)點的日志等級是info,更多關(guān)于啟動worker的參數(shù)(比如-c、-Q等常用的)請使用

celery worker --help

進(jìn)行查看

將worker啟動起來后,我們就可以通過網(wǎng)絡(luò)來調(diào)用add函數(shù)了。我們在后面的分布式爬蟲構(gòu)建中也是采用這種方式分發(fā)和消費url的。在命令行先切換到項目根目錄,然后打開python交互端

from tasks import add

rs = add.delay(2, 2) # 這里的add.delay就是通過網(wǎng)絡(luò)調(diào)用將任務(wù)發(fā)送給add所在的worker執(zhí)行

這個時候我們可以在worker的界面看到接收的任務(wù)和計算的結(jié)果。

[2017-05-19 14:22:43,038: INFO/MainProcess] Received task: tasks.add[c0dfcd0b-d05f-4285-b944-0a8aba3e7e61] # worker接收的任務(wù)

[2017-05-19 14:22:43,065: INFO/MainProcess] Task tasks.add[c0dfcd0b-d05f-4285-b944-0a8aba3e7e61] succeeded in 0.025274309000451467s: 4 # 執(zhí)行結(jié)果

這里是異步調(diào)用,如果我們需要返回的結(jié)果,那么要等rs的ready狀態(tài)true才行。這里add看不出效果,不過試想一下,如果我們是調(diào)用的比較占時間的io任務(wù),那么異步任務(wù)就比較有價值了

rs #

rs.ready() # true 表示已經(jīng)返回結(jié)果了

rs.status # 'SUCCESS' 任務(wù)執(zhí)行狀態(tài),失敗還是成功

rs.successful() # True 表示執(zhí)行成功

rs.result # 4 返回的結(jié)果

rs.get() # 4 返回的結(jié)果

#這里我們backend 結(jié)果存儲在redis里

上面講的是從Python交互終端中調(diào)用add函數(shù),如果我們要從另外一個py文件調(diào)用呢?除了通過import然后add.delay()這種方式,我們還可以通過send_task()這種方式,我們在項目根目錄另外新建一個py文件叫做 excute_tasks.py,在其中寫下如下的代碼

from tasks import add

if __name__ == '__main__':

add.delay(5, 10)

這時候可以在celery的worker界面看到執(zhí)行的結(jié)果

[2017-05-19 14:25:48,039: INFO/MainProcess] Received task: tasks.add[f5ed0d5e-a337-45a2-a6b3-38a58efd9760]

[2017-05-19 14:25:48,074: INFO/MainProcess] Task tasks.add[f5ed0d5e-a337-45a2-a6b3-38a58efd9760] succeeded in 0.03369094600020617s: 15

此外,我們還可以通過send_task()來調(diào)用,將excute_tasks.py改成這樣

from tasks import app

if __name__ == '__main__':

app.send_task('tasks.add', args=(10, 15),)

這種方式也是可以的。send_task()還可能接收到為注冊(即通過@app.task裝飾)的任務(wù),這個時候worker會忽略這個消息

[2017-05-19 14:34:15,352: ERROR/MainProcess] Received unregistered task of type 'tasks.adds'.

The message has been ignored and discarded.

定時任務(wù)

上面部分講了怎么啟動worker和調(diào)用worker的相關(guān)函數(shù),這里再講一下celery的定時任務(wù)。

爬蟲由于其特殊性,可能需要定時做增量抓取,也可能需要定時做模擬登陸,以防止cookie過期,而celery恰恰就實現(xiàn)了定時任務(wù)的功能。在上述基礎(chǔ)上,我們將tasks.py文件改成如下內(nèi)容

from celery import Celery

app = Celery('add_tasks', broker='redis:''//223.129.0.190:6379/2', backend='redis:''//223.129.0.190:6379/3')

app.conf.update(

# 配置所在時區(qū)

CELERY_TIMEZONE='Asia/Shanghai',

CELERY_ENABLE_UTC=True,

# 官網(wǎng)推薦消息序列化方式為json

CELERY_ACCEPT_CONTENT=['json'],

CELERY_TASK_SERIALIZER='json',

CELERY_RESULT_SERIALIZER='json',

# 配置定時任務(wù)

CELERYBEAT_SCHEDULE={

'my_task': {

'task': 'tasks.add', # tasks.py模塊下的add方法

'schedule': 60, # 每隔60運行一次

'args': (23, 12),

}

}

)

@app.task

def add(x, y):

return x + y

然后先通過ctrl+c停掉前一個worker,因為我們代碼改了,需要重啟worker才會生效。我們再次以celery -A tasks worker -l info這個命令開啟worker。

這個時候我們只是開啟了worker,如果要讓worker執(zhí)行任務(wù),那么還需要通過beat給它定時發(fā)送,我們再開一個命令行,切換到項目根目錄,通過

celery beat -A tasks -l info

celery beat v3.1.25 (Cipater) is starting.

__ - ... __ - _

Configuration ->

. broker -> redis://223.129.0.190:6379/2

. loader -> celery.loaders.app.AppLoader

. scheduler -> celery.beat.PersistentScheduler

. db -> celerybeat-schedule

. logfile -> [stderr]@%INFO

. maxinterval -> now (0s)

[2017-05-19 15:56:57,125: INFO/MainProcess] beat: Starting...

這樣就表示定時任務(wù)已經(jīng)開始運行了。

眼尖的同學(xué)可能看到我這里celery的版本是3.1.25,這是因為celery支持的windows最高版本是3.1.25。由于我的分布式微博爬蟲的worker也同時部署在了windows上,所以我選擇了使用 3.1.25。如果全是linux系統(tǒng),建議使用celery4。

此外,還有一點需要注意,在celery4后,定時任務(wù)(通過schedule調(diào)度的會這樣,通過crontab調(diào)度的會馬上執(zhí)行)會在當(dāng)前時間再過定時間隔執(zhí)行第一次任務(wù),比如我這里設(shè)置的是60秒的間隔,那么第一次執(zhí)行add會在我們通過celery beat -A tasks -l info啟動定時任務(wù)后60秒才執(zhí)行;celery3.1.25則會馬上執(zhí)行該任務(wù)。

關(guān)于定時任務(wù)更詳細(xì)的請看官方文檔celery定時任務(wù)

至此,我們把構(gòu)建一個分布式爬蟲的理論知識都講了一遍,主要就是對于celery的了解和使用,這里并未涉及到celery的一些高級特性,實戰(zhàn)篇可能會講解一些我自己使用的特性。

下一篇我將介紹如何使用celery寫一個簡單的分布式爬蟲,希望大家能有所收獲。

如果本文對大家有幫助,不妨點個贊鼓勵一下我,繼續(xù)創(chuàng)作。

此外,打一個廣告,我寫了一個分布式的微博爬蟲,主要就是利用celery做的分布式實戰(zhàn)篇我也將會以該項目其中一個模塊進(jìn)行講解,有興趣的可以點擊看看,也歡迎有需求的朋友試用。

總結(jié)

以上是生活随笔為你收集整理的python分布式爬虫系统_如何构建一个分布式爬虫:理论篇的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。