如何優(yōu)雅的落地一個(gè)分布式爬蟲:實(shí)戰(zhàn)篇

本篇文章將從實(shí)戰(zhàn)角度來(lái)介紹如何構(gòu)建一個(gè)穩(wěn)健的分布式微博爬蟲。這里我沒敢談高效,抓過(guò)微博數(shù)據(jù)的同學(xué)應(yīng)該都知道微博的反爬蟲能力,也知道微博數(shù)據(jù)抓取的瓶頸在哪里。我在知乎上看過(guò)一些同學(xué)的說(shuō)法,把微博的數(shù)據(jù)抓取難度簡(jiǎn)單化了,我只能說(shuō),那是你太naive,沒深入了解和長(zhǎng)期抓取而已。

創(chuàng)新互聯(lián)秉承實(shí)現(xiàn)全網(wǎng)價(jià)值營(yíng)銷的理念,以專業(yè)定制企業(yè)官網(wǎng),成都網(wǎng)站設(shè)計(jì)、做網(wǎng)站,小程序定制開發(fā),網(wǎng)頁(yè)設(shè)計(jì)制作,移動(dòng)網(wǎng)站建設(shè),成都全網(wǎng)營(yíng)銷推廣幫助傳統(tǒng)企業(yè)實(shí)現(xiàn)“互聯(lián)網(wǎng)+”轉(zhuǎn)型升級(jí)專業(yè)定制企業(yè)官網(wǎng),公司注重人才、技術(shù)和管理,匯聚了一批優(yōu)秀的互聯(lián)網(wǎng)技術(shù)人才,對(duì)客戶都以感恩的心態(tài)奉獻(xiàn)自己的專業(yè)和所長(zhǎng)。

本文將會(huì)以PC端微博進(jìn)行講解,因?yàn)橐苿?dòng)端微博數(shù)據(jù)不如PC短全面,而且抓取和解析難度都會(huì)小一些。文章比較長(zhǎng),由于篇幅所限,文章并沒有列出所有代碼,只是講了大致流程和思路。

要抓微博數(shù)據(jù),第一步便是模擬登陸,因?yàn)楹芏嘈畔ⅲū热缬脩粜畔?,用戶主?yè)微博數(shù)據(jù)翻頁(yè)等各種翻頁(yè))都需要在登錄狀態(tài)下才能查看

這里我簡(jiǎn)單說(shuō)一下,做爬蟲的同學(xué)不要老想著用什么機(jī)器學(xué)習(xí)的方法去識(shí)別復(fù)雜驗(yàn)證碼,真的難度非常大,這應(yīng)該也不是一個(gè)爬蟲工程師的工作重點(diǎn),當(dāng)然這只是我的個(gè)人建議。工程化的項(xiàng)目,我還是建議大家通過(guò)打碼平臺(tái)來(lái)解決驗(yàn)證碼的問(wèn)題。

說(shuō)完模擬登陸(具體請(qǐng)參見我寫的那兩篇文章,篇幅所限,我就不copy過(guò)來(lái)了),我們現(xiàn)在正式進(jìn)入微博的數(shù)據(jù)抓取。這里我會(huì)以微博用戶信息抓取為例來(lái)進(jìn)行分析和講解。

關(guān)于用戶信息抓取,可能我們有兩個(gè)目的。一個(gè)是我們只想抓一些指定用戶,另外一個(gè)是我們想盡可能多的抓取更多數(shù)量的用戶的信息。我的目的假定是第二種。那么我們?cè)撘允裁礃拥牟呗詠?lái)抓取,才能獲得盡可能多的用戶信息呢?如果我們初始用戶選擇有誤,選了一些不活躍的用戶,很可能會(huì)形成一個(gè)環(huán),這樣就抓不了太多的數(shù)據(jù)。這里有一個(gè)很簡(jiǎn)單的思路:我們把一些大V拿來(lái)做為種子用戶,我們先抓他們的個(gè)人信息,然后再抓大V所關(guān)注的用戶和粉絲,大V關(guān)注的用戶肯定也是類似大V的用戶,這樣的話,就不容易形成環(huán)了。

策略我們都清楚了。就該是分析和編碼了。

我們先來(lái)分析如何構(gòu)造用戶信息的URL。這里我以微博名為一起神吐槽的博主為例進(jìn)行分析。做爬蟲的話,一個(gè)很重要的意識(shí)就是爬蟲能抓的數(shù)據(jù)都是人能看到的數(shù)據(jù),反過(guò)來(lái),人能在瀏覽器上看到的數(shù)據(jù),爬蟲幾乎都能抓。這里用的是幾乎,因?yàn)橛械臄?shù)據(jù)抓取難度特別。我們首先需要以正常人的流程看看怎么獲取到用戶的信息。我們先進(jìn)入該博主的主頁(yè),如下圖
如何優(yōu)雅的落地一個(gè)分布式爬蟲:實(shí)戰(zhàn)篇

種子用戶主頁(yè)

點(diǎn)擊查看更多,可以查看到該博主的具體信息

如何優(yōu)雅的落地一個(gè)分布式爬蟲:實(shí)戰(zhàn)篇

種子博主具體信息

這里我們就看到了他的具體信息了。然后,我們看該頁(yè)面的url構(gòu)造

weibo.com/p/100505175…
我直接copy的地址欄的url。這樣做有啥不好的呢?對(duì)于老鳥來(lái)說(shuō),一下就看出來(lái)了,這樣做的話,可能會(huì)導(dǎo)致信息不全,因?yàn)榭赡苡行┬畔⑹莿?dòng)態(tài)加載的。所以,我們需要通過(guò)抓包來(lái)判斷到底微博會(huì)通過(guò)該url返回所有信息,還是需要請(qǐng)求一些ajax 鏈接才會(huì)返回一些關(guān)鍵信息。這里我就重復(fù)一下我的觀點(diǎn):抓包很重要,抓包很重要,抓包很重要!重要的事情說(shuō)三遍。

我們抓完包,發(fā)現(xiàn)并沒有ajax請(qǐng)求。那么可以肯定請(qǐng)求前面的url,會(huì)返回所有信息。我們通過(guò)點(diǎn)擊鼠標(biāo)右鍵,查看網(wǎng)頁(yè)源代碼,然后ctrl+a、ctrl+c將所有的頁(yè)面源碼保存到本地,這里我命名為personinfo.html。我們用瀏覽器打開該文件,發(fā)現(xiàn)我們需要的所有信息都在這段源碼中,這個(gè)工作和抓包判斷數(shù)據(jù)是否全面有些重復(fù),但是在我看來(lái)是必不可少的,因?yàn)槲覀兘馕鲰?yè)面數(shù)據(jù)的時(shí)候還可以用到這個(gè)html文件,如果我們每次都通過(guò)網(wǎng)絡(luò)請(qǐng)求去解析內(nèi)容的話,那么可能賬號(hào)沒一會(huì)兒就會(huì)被封了(因?yàn)轭l繁訪問(wèn)微博信息),所以我們需要把要解析的文件保存到本地。

從上面分析中我們可以得知

weibo.com/p/100505175…
這個(gè)url就是獲取用戶數(shù)據(jù)的url。那么我們?cè)谥恢烙脩鬷d的時(shí)候怎么構(gòu)造它呢?我們可以多拿幾個(gè)用戶id來(lái)做測(cè)試,看構(gòu)造是否有規(guī)律,比如我這里以用戶名為網(wǎng)易云音樂的用戶做分析,發(fā)現(xiàn)它的用戶信息頁(yè)面構(gòu)造如下

weibo.com/1721030997/…
這個(gè)就和上面那個(gè)不同了。但是我們仔細(xì)觀察,可以發(fā)現(xiàn)上面那個(gè)是個(gè)人用戶,下面是企業(yè)微博用戶。我們嘗試一下把它們url格式都統(tǒng)一為第一種或者第二種的格式

weibo.com/1751195602/…
這樣會(huì)出現(xiàn)404,那么統(tǒng)一成上面那種呢?

weibo.com/p/100505172…
這樣子的話,它會(huì)被重定向到用戶主頁(yè),而不是用戶詳細(xì)資料頁(yè)。所以也就不對(duì)了。那么該以什么依據(jù)判斷何時(shí)用第一種url格式,何時(shí)用第二種url格式呢?我們多翻幾個(gè)用戶,會(huì)發(fā)現(xiàn)除了100505之外,還有100305、100206等前綴,那么我猜想這個(gè)應(yīng)該可以區(qū)分不同用戶。這個(gè)前綴在哪里可以得到呢?我們打開我們剛保存的頁(yè)面源碼,搜索100505,可以發(fā)現(xiàn)
如何優(yōu)雅的落地一個(gè)分布式爬蟲:實(shí)戰(zhàn)篇

domain

微博應(yīng)該是根據(jù)這個(gè)來(lái)區(qū)分不同用戶類型的。這里大家可以自己也可以試試,看不同用戶的domain是否不同。為了數(shù)據(jù)能全面,我也是做了大量測(cè)試,發(fā)現(xiàn)個(gè)人用戶的domain是1005051,作家是100305,其他基本都是認(rèn)證的企業(yè)號(hào)。前兩個(gè)個(gè)人信息的url構(gòu)造就是

weibo.com/p/domain+ui…
后者的是

weibo.com/uid/about
弄清楚了個(gè)人信息url的構(gòu)造方式,但是還有一個(gè)問(wèn)題。我們已知只有uid啊,沒有domain啊。如果是企業(yè)號(hào),我們通過(guò)domain=100505會(huì)被重定向到主頁(yè),如果是作家等(domain=100305或者100306),也會(huì)被重定向主頁(yè)。我們?cè)谥黜?yè)把domain提取出來(lái),再請(qǐng)求一次,不就能拿到用戶詳細(xì)信息了嗎?

關(guān)于如何構(gòu)造獲取用戶信息的url的相關(guān)分析就到這里了。因?yàn)槲覀兪窃诘卿浀那闆r下進(jìn)行數(shù)據(jù)抓取的,可能在抓取的時(shí)候,某個(gè)賬號(hào)突然就被封了,或者由于網(wǎng)絡(luò)原因,某次請(qǐng)求失敗了,該如何處理?對(duì)于前者,我們需要判斷每次請(qǐng)求返回的內(nèi)容是否符合預(yù)期,也就是看response url是否正常,看response content是否是404或者讓你驗(yàn)證手機(jī)號(hào)等,對(duì)于后者,我們可以做一個(gè)簡(jiǎn)單的重試策略,大概代碼如下

@timeout_decorator
def get_page(url, user_verify=True, need_login=True):
"""
:param url: 待抓取url
:param user_verify: 是否為可能出現(xiàn)驗(yàn)證碼的頁(yè)面(ajax連接不會(huì)出現(xiàn)驗(yàn)證碼,如果是請(qǐng)求微博或者用戶信息可能出現(xiàn)驗(yàn)證碼),否為抓取轉(zhuǎn)發(fā)的ajax連接
:param need_login: 抓取頁(yè)面是否需要登錄,這樣做可以減小一些賬號(hào)的壓力
:return: 返回請(qǐng)求的數(shù)據(jù),如果出現(xiàn)404或者403,或者是別的異常,都返回空字符串
"""
crawler.info('本次抓取的url為{url}'.format(url=url))
count = 0

while count < max_retries:

    if need_login:
        # 每次重試的時(shí)候都換cookies,并且和上次不同,如果只有一個(gè)賬號(hào),那么就允許相同
        name_cookies = Cookies.fetch_cookies()

        if name_cookies is None:
            crawler.warning('cookie池中不存在cookie,正在檢查是否有可用賬號(hào)')
            rs = get_login_info()

            # 選擇狀態(tài)正常的賬號(hào)進(jìn)行登錄,賬號(hào)都不可用就停掉celery worker
            if len(rs) == 0:
                crawler.error('賬號(hào)均不可用,請(qǐng)檢查賬號(hào)健康狀況')
                # 殺死所有關(guān)于celery的進(jìn)程
                if 'win32' in sys.platform:
                    os.popen('taskkill /F /IM "celery*"')
                else:
                    os.popen('pkill -f "celery"')
            else:
                crawler.info('重新獲取cookie中...')
                login.excute_login_task()
                time.sleep(10)

    try:
        if need_login:
            resp = requests.get(url, headers=headers, cookies=name_cookies[1], timeout=time_out, verify=False)

            if "$CONFIG['islogin'] = '0'" in resp.text:
                crawler.warning('賬號(hào){}出現(xiàn)異常'.format(name_cookies[0]))
                freeze_account(name_cookies[0], 0)
                Cookies.delete_cookies(name_cookies[0])
                continue
        else:
            resp = requests.get(url, headers=headers, timeout=time_out, verify=False)

        page = resp.text
        if page:
            page = page.encode('utf-8', 'ignore').decode('utf-8')
        else:
            continue

        # 每次抓取過(guò)后程序sleep的時(shí)間,降低封號(hào)危險(xiǎn)
        time.sleep(interal)

        if user_verify:
            if 'unfreeze' in resp.url or 'accessdeny' in resp.url or 'userblock' in resp.url or is_403(page):
                crawler.warning('賬號(hào){}已經(jīng)被凍結(jié)'.format(name_cookies[0]))
                freeze_account(name_cookies[0], 0)
                Cookies.delete_cookies(name_cookies[0])
                count += 1
                continue

            if 'verifybmobile' in resp.url:
                crawler.warning('賬號(hào){}功能被鎖定,需要手機(jī)解鎖'.format(name_cookies[0]))

                freeze_account(name_cookies[0], -1)
                Cookies.delete_cookies(name_cookies[0])
                continue

            if not is_complete(page):
                count += 1
                continue

            if is_404(page):
                crawler.warning('url為{url}的連接不存在'.format(url=url))
                return ''

    except (requests.exceptions.ReadTimeout, requests.exceptions.ConnectionError, AttributeError) as e:
        crawler.warning('抓取{}出現(xiàn)異常,具體信息是{}'.format(url, e))
        count += 1
        time.sleep(excp_interal)

    else:
        Urls.store_crawl_url(url, 1)
        return page

crawler.warning('抓取{}已達(dá)到最大重試次數(shù),請(qǐng)?jiān)趓edis的失敗隊(duì)列中查看該url并檢查原因'.format(url))
Urls.store_crawl_url(url, 0)
return ''

這里大家把上述代碼當(dāng)一段偽代碼讀就行了,主要看看如何處理抓取時(shí)候的異常。因?yàn)槿绻N整個(gè)用戶抓取的代碼,不是很現(xiàn)實(shí),代碼量有點(diǎn)大。

下面講頁(yè)面解析的分析。有一些做PC端微博信息抓取的同學(xué),可能曾經(jīng)遇到過(guò)這么個(gè)問(wèn)題:保存到本地的html文件打開都能看到所有信息啊,為啥在頁(yè)面源碼中找不到呢?因?yàn)镻C端微博頁(yè)面的關(guān)鍵信息都是像下圖這樣,被FM.view()包裹起來(lái)的,里面的數(shù)據(jù)可能被json encode過(guò)。

如何優(yōu)雅的落地一個(gè)分布式爬蟲:實(shí)戰(zhàn)篇

標(biāo)簽

那么這么多的FM.view(),我們?cè)趺粗涝撎崛∧膫€(gè)呢?這里有一個(gè)小技巧,由于只有中文會(huì)被編碼,英文還是原來(lái)的樣子,所以我們可以看哪段script中包含了渲染后的頁(yè)面中的字符,那么那段應(yīng)該就可能包含所有頁(yè)面信息。我們這里以頂部的頭像為例,如圖

如何優(yōu)雅的落地一個(gè)分布式爬蟲:實(shí)戰(zhàn)篇
根據(jù)唯一性判斷

我們?cè)陧?yè)面源碼中搜索,只發(fā)現(xiàn)一個(gè)script中有該字符串,那么就是那段script是頁(yè)面相關(guān)信息。我們可以通過(guò)正則表達(dá)式把該script提取出來(lái),然后把其中的html也提取出來(lái),再保存到本地,看看信息是否全面。這里我就不截圖了。感覺還有很多要寫的,不然篇幅太長(zhǎng)了。

另外,對(duì)于具體頁(yè)面的解析,我也不做太多的介紹了。太細(xì)的東西還是建議讀讀源碼。我只講一下,我覺得的一種處理異常的比較優(yōu)雅的方式。微博爬蟲的話,主要是頁(yè)面樣式太多,如果你打算包含所有不同的用戶的模版,那么我覺得幾乎不可能,不同用戶模版,用到的解析規(guī)則就不一樣。那么出現(xiàn)解析異常如何處理?尤其是你沒有catch到的異常。很可能因?yàn)檫@個(gè)問(wèn)題,程序就崩掉。其實(shí)對(duì)于Python這門語(yǔ)言來(lái)說(shuō),我們可以通過(guò) 裝飾器 來(lái)捕捉我們沒有考慮到的異常,比如我這個(gè)裝飾器

def parse_decorator(return_type):
"""
:param return_type: 用于捕捉頁(yè)面解析的異常, 0表示返回?cái)?shù)字0, 1表示返回空字符串, 2表示返回[],3表示返回False, 4表示返回{}, 5返回None
:return: 0,'',[],False,{},None
"""
def page_parse(func):@wraps(func)
br/>@wraps(func)
keys):
try:
return func(keys)
except Exception as e:
parser.error(e)

            if return_type == 5:
                return None
            elif return_type == 4:
                return {}
            elif return_type == 3:
                return False
            elif return_type == 2:
                return []
            elif return_type == 1:
                return ''
            else:
                return 0

    return handle_error

return page_parse

上面的代碼就是處理解析頁(yè)面發(fā)生異常的情況,我們只能在數(shù)據(jù)的準(zhǔn)確性、全面性和程序的健壯性之間做一些取舍。用裝飾器的話,程序中不用寫太多的 try語(yǔ)句,代碼重復(fù)率也會(huì)減少很多。

頁(yè)面的解析由于篇幅所限,我就講到這里了。沒有涉及太具體的解析,其中一個(gè)還有一個(gè)比較難的點(diǎn),就是數(shù)據(jù)的全面性,讀者可以去多觀察幾個(gè)微博用戶的個(gè)人信息,就會(huì)發(fā)現(xiàn)有的個(gè)人信息,有的用戶有填寫,有的并沒有。解析的時(shí)候要考慮完的話,建議從自己的微博的個(gè)人信息入手,看到底有哪些可以填。這樣可以保證幾乎不會(huì)漏掉一些重要的信息。

最后,我再切合本文的標(biāo)題,講如何搭建一個(gè)分布式的微博爬蟲。開發(fā)過(guò)程中,我們可以先就做單機(jī)單線程的爬蟲,然后再改成使用celery的方式。這里這樣做是為了方便開發(fā)和測(cè)試,因?yàn)槟銌螜C(jī)搭起來(lái)并且跑得通了,那么分布式的話,就很容易改了,因?yàn)閏elery的API使用本來(lái)就很簡(jiǎn)潔。

我們抓取的是用戶信息和他的關(guān)注和粉絲uid。用戶信息的話,我們一個(gè)請(qǐng)求大概能抓取一個(gè)用戶的信息,而粉絲和關(guān)注我們一個(gè)請(qǐng)求可以抓取18個(gè)左右(因?yàn)檫@個(gè)抓的是列表),顯然可以發(fā)現(xiàn)用戶信息應(yīng)該多占一些請(qǐng)求的資源。這時(shí)候就該介紹理論篇沒有介紹的關(guān)于celery的一個(gè)高級(jí)特性了,它叫做任務(wù)路由。直白點(diǎn)說(shuō),它可以規(guī)定哪個(gè)分布式節(jié)點(diǎn)能做哪些任務(wù),不能做哪些任務(wù)。它的存在可以讓資源分配更加合理, 分布式微博爬蟲項(xiàng)目初期,就沒有使用任務(wù)路由,然后抓了十多萬(wàn)條關(guān)注和分析,結(jié)果發(fā)現(xiàn)用戶信息抓幾萬(wàn)條,這就是資源分配得不合理。那么如何進(jìn)行任務(wù)路由呢?

coding:utf-8

import os
from datetime import timedelta
from celery import Celery
from kombu import Exchange, Queue
from config.conf import get_broker_or_backend
from celery import platforms

允許celery以root身份啟動(dòng)

platforms.C_FORCE_ROOT = True

worker_log_path = os.path.join(os.path.dirname(os.path.dirname(file))+'/logs', 'celery.log')
beat_log_path = os.path.join(os.path.dirname(os.path.dirname(file))+'/logs', 'beat.log')

tasks = ['tasks.login', 'tasks.user']

include的作用就是注冊(cè)服務(wù)化函數(shù)

app = Celery('weibo_task', include=tasks, broker=get_broker_or_backend(1), backend=get_broker_or_backend(2))

app.conf.update(
CELERY_TIMEZONE='Asia/Shanghai',
CELERY_ENABLE_UTC=True,
CELERYD_LOG_FILE=worker_log_path,
CELERYBEAT_LOG_FILE=beat_log_path,
CELERY_ACCEPT_CONTENT=['json'],
CELERY_TASK_SERIALIZER='json',
CELERY_RESULT_SERIALIZER='json',
CELERY_QUEUES=(
Queue('login_queue', exchange=Exchange('login', type='direct'), routing_key='for_login'),
Queue('user_crawler', exchange=Exchange('user_info', type='direct'), routing_key='for_user_info'),
Queue('fans_followers', exchange=Exchange('fans_followers', type='direct'), routing_key='for_fans_followers'),
)
上述代碼我指定了有l(wèi)ogin_queue、user_crawler、fans_followers三個(gè)任務(wù)隊(duì)列。它們分別的作用是登錄、用戶信息抓取、粉絲和關(guān)注抓取。現(xiàn)在假設(shè)我有三臺(tái)爬蟲服務(wù)器A、B和C。我想讓我所有的賬號(hào)登錄任務(wù)分散到三臺(tái)服務(wù)器、讓用戶抓取在A和B上執(zhí)行,讓粉絲和關(guān)注抓取在C上執(zhí)行,那么啟動(dòng)A、B、C三個(gè)服務(wù)器的celery worker的命令就分別是

celery -A tasks.workers -Q login_queue,user_crawler worker -l info -c 1 # A服務(wù)器和B服務(wù)器啟動(dòng)worker的命令,它們只會(huì)執(zhí)行登錄和用戶信息抓取任務(wù)
celery -A tasks.workers -Q login_queue,fans_followers worker -l info -c 1 # C服務(wù)器啟動(dòng)worker的命令,它只會(huì)執(zhí)行登錄、粉絲和關(guān)注抓取任務(wù)
然后我們通過(guò)命令行或者代碼(如下)就能發(fā)送所有任務(wù)給各個(gè)節(jié)點(diǎn)執(zhí)行了

coding:utf-8

from tasks.workers import app
from page_get import user as user_get
from db.seed_ids import get_seed_ids, get_seed_by_id, insert_seeds, set_seed_other_crawled

@app.task(ignore_result=True)
def crawl_follower_fans(uid):
seed = get_seed_by_id(uid)
if seed.other_crawled == 0:
rs = user_get.get_fans_or_followers_ids(uid, 1)
rs.extend(user_get.get_fans_or_followers_ids(uid, 2))
datas = set(rs)

重復(fù)數(shù)據(jù)跳過(guò)插入

    if datas:
        insert_seeds(datas)
    set_seed_other_crawled(uid)

@app.task(ignore_result=True)
def crawl_person_infos(uid):
"""
根據(jù)用戶id來(lái)爬取用戶相關(guān)資料和用戶的關(guān)注數(shù)和粉絲數(shù)(由于微博服務(wù)端限制,默認(rèn)爬取前五頁(yè),企業(yè)號(hào)的關(guān)注和粉絲也不能查看)
:param uid: 用戶id
:return:
"""
if not uid:
return

# 由于與別的任務(wù)共享數(shù)據(jù)表,所以需要先判斷數(shù)據(jù)庫(kù)是否有該用戶信息,再進(jìn)行抓取
user = user_get.get_profile(uid)
# 不抓取企業(yè)號(hào)
if user.verify_type == 2:
    set_seed_other_crawled(uid)
    return
app.send_task('tasks.user.crawl_follower_fans', args=(uid,), queue='fans_followers',
              routing_key='for_fans_followers')

@app.task(ignore_result=True)
def excute_user_task():
seeds = get_seed_ids()
if seeds:
for seed in seeds:

在send_task的時(shí)候指定任務(wù)隊(duì)列

        app.send_task('tasks.user.crawl_person_infos', args=(seed.uid,), queue='user_crawler',
                      routing_key='for_user_info')

這里我們是通過(guò) queue='user_crawler',routing_key='for_user_info'來(lái)將任務(wù)和worker進(jìn)行關(guān)聯(lián)的。

關(guān)于celery任務(wù)路由的更詳細(xì)的資料請(qǐng)閱讀官方文檔。

到這里,基本把微博信息抓取的過(guò)程和分布式進(jìn)行抓取的過(guò)程都講完了,具體實(shí)現(xiàn)分布式的方法,可以讀讀基礎(chǔ)篇。由于代碼量比較大,我并沒有貼上完整的代碼,只講了要點(diǎn)。分析過(guò)程是講的抓取過(guò)程的分析和頁(yè)面解析的分析,并在最后,結(jié)合分布式,講了一下使用任務(wù)隊(duì)列來(lái)讓分布式爬蟲更加靈活和可擴(kuò)展。

如果有同學(xué)想跟著做一遍,可能需要參考分布式微博爬蟲的源碼,自己動(dòng)手實(shí)現(xiàn)一下,或者跑一下,印象可能會(huì)更加深刻。

文章題目:如何優(yōu)雅的落地一個(gè)分布式爬蟲:實(shí)戰(zhàn)篇
轉(zhuǎn)載注明:http://www.muchs.cn/article22/jpcsjc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站建設(shè)、網(wǎng)站設(shè)計(jì)公司、自適應(yīng)網(wǎng)站、網(wǎng)站導(dǎo)航Google、企業(yè)網(wǎng)站制作

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都網(wǎng)頁(yè)設(shè)計(jì)公司