Python爬蟲:關(guān)于 廣度優(yōu)先 和 深度優(yōu)先

廣度優(yōu)先和深度優(yōu)先

關(guān)于廣度優(yōu)先和深度優(yōu)先设塔,首先,不管是廣度還是深度,都需要定義一個(gè)爬取的深度 crawl_deepth寺擂,深度優(yōu)先比較容易實(shí)現(xiàn) 顯示遞歸嘛 爬取的層次。

所謂廣度優(yōu)先 就是要把當(dāng)前頁的 link 全部爬取完畢再進(jìn)行下一深度的遍歷,這就要給一些隊(duì)列分類 一般分為待爬隊(duì)列, 已爬隊(duì)列, 新加隊(duì)列, pop隊(duì)列响委,首先要確保訪問每個(gè)深度頁是的待爬隊(duì)列已經(jīng)清空 才獲取下一頁的超鏈接,思路嘛 大概可以用 while 1 來實(shí)現(xiàn) 窖梁。

當(dāng)然也可以直接寫好 pop 方法 直接 pop 出來 到最后清空隊(duì)列 繼續(xù)往下走赘风。

這里有一個(gè)簡(jiǎn)單的例子 可供參考,雖然沒有解析函數(shù) 思想可行纵刘。

image

定義 Redis 隊(duì)列

class RedisQueue(object):
    def __init__(self, name, namespace='queue', **redis_kwargs):
        self.__db = redis.Redis(host='127.0.0.1', port=6379, db=0, password=None)
        self.key = f"{name,namespace}"

    # 返回隊(duì)列大小
    def qsize(self):
        return self.__db.llen(self.key)

    # 判斷隊(duì)列用盡
    def empty(self):
        return self.qsize() == 0

    # rpush進(jìn)去或者lpush都可以
    def put(self, item):
        self.__db.rpush(self.key, item)

    # get出來
    def get(self, block=True, timeout=None)
        if block:
            item = self.__db.blpop(self.key, timeout=timeout)
        else:
            item = self.__db.lpop(self.key)
        return item

    def get_nowait(self):
        return self.get(False)

廣度優(yōu)先
直接上套餐

class MyCrawler:

    def __init__(self):

        # 初始化當(dāng)前抓取的深度
        self.current_deepth = 1

        # 使用種子初始化url隊(duì)列
        self.vistedQueue = RedisQueue("vistedQueue")
        self.unvistedQueue = RedisQueue("unvistedQueue")

    def put_unvistedQueue(self, seeds):
        if isinstance(seeds, str):
            self.unvistedQueue.put(seeds)
        if isinstance(seeds, list):
            for seed in seeds:
                self.unvistedQueue.put(seed)
        print("成功添加到未爬隊(duì)列")

    # 主函數(shù)
    def crawling(self, crawl_deepth):

        # 深度 crawl_deepth
        while self.current_deepth <= crawl_deepth:

            # 確保清空隊(duì)列之后再繼續(xù) 先廣后深
            while not self.unvistedQueue.empty():
                # 出隊(duì)列
                visitUrl = self.unvistedQueue.get_nowait().decode()
                print(f"取出url {visitUrl}")

                # 獲取超鏈接
                links = self.getHyperLinks(visitUrl)
                print(f"頁面 link 數(shù)量 {len(links)}")

                # 將url放入已訪問的url中
                self.vistedQueue.put(visitUrl)
                print("當(dāng)前深度: " + str(self.current_deepth))

                # 未訪問的url入列
                for link in links:
                    self.unvistedQueue.put(link)
                # 深度加 1
                self.current_deepth += 1

    # 獲取源碼中超鏈接
    def getHyperLinks(self, url):
        links = []
        data = self.getPageSource(url)
        if data:
            soup = BeautifulSoup(data)
            a = soup.findAll("a", {"href": re.compile('^http|^/')})
            for i in a:
                if i["href"].find("http://") != -1:
                    links.append(i["href"])
        return links

    # get html
    def getPageSource(self, url,  headers=None, timeout=15):
        try:
            request = requests.get(url,headers,timeout=timeout)
            if request.status_code in [200,201]:
                request.encoding = request.apparent_encoding
                return request.text
        except ConnectionError:
            return None

執(zhí)行主函數(shù)

if __name__=="__main__":

     # 指定爬取的深度 10
     c = MyCrawler()
     c.put_unvistedQueue(["http://www.baidu.com", "http://www.google.com"])
     c.crawling(10)

我這里用的是 Redis 作為未爬 和 已爬的隊(duì)列(其實(shí)用內(nèi)置 set 也一樣)
由于我這里是 rpush(右邊進(jìn)) 和 lpop(左邊出) 這樣就達(dá)到了 先廣后深 的爬取目的了

深度優(yōu)先
比廣度優(yōu)先好寫一點(diǎn) 就是遞歸爬取 只需要定義深度

import requests
import re
import time

exist_urls = []
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36',
}

def get_link(url):
    try:
        response = requests.get(url=url, headers=headers)
        response.encoding = 'UTF-8'
        html = response.text
        link_lists = re.findall('.*?<a target=_blank href="/item/([^:#=<>]*?)".*?</a>', html)
        return link_lists
    except Exception as e:
        pass
    finally:
        exist_urls.append(url)

# 當(dāng)爬取深度小于10層時(shí)邀窃,遞歸調(diào)用主函數(shù),繼續(xù)爬取第二層的所有鏈接
def main(start_url, depth=1):
    link_lists = get_link(start_url)
    if link_lists:
        unique_lists = list(set(link_lists) - set(exist_urls))
        for unique_url in unique_lists:
            unique_url = 'https://baike.baidu.com/item/' + unique_url
            output = 'Depth:' + str(depth) + '\t' + start_url + '======>' + unique_url + '\n'
            print(output)

            with open('url.txt', 'a+') as f:
                f.write(unique_url + '\n')
                f.close()
            if depth < 10:
                main(unique_url, depth + 1)

執(zhí)行主函數(shù)

if __name__ == '__main__':
    t1 = time.time()
    start_url = 'https://baike.baidu.com/item/%E7%99%BE%E5%BA%A6%E7%99%BE%E7%A7%91'
    main(start_url)
    t2 = time.time()
    print('總時(shí)間', t2 - t1)

以上的例子實(shí)現(xiàn) 深度優(yōu)先 和 廣度優(yōu)先的代碼假哎,其實(shí)沒啥復(fù)雜的瞬捕,也比較好理解。
提供思路舵抹,僅供參考肪虎。

歡迎轉(zhuǎn)載,但要聲明出處掏父,不然我順著網(wǎng)線過去就是一拳笋轨。
個(gè)人技術(shù)博客:http://www.gzky.live

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末秆剪,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子爵政,更是在濱河造成了極大的恐慌仅讽,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,816評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件钾挟,死亡現(xiàn)場(chǎng)離奇詭異洁灵,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)掺出,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門徽千,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人汤锨,你說我怎么就攤上這事双抽。” “怎么了闲礼?”我有些...
    開封第一講書人閱讀 158,300評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵牍汹,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我柬泽,道長(zhǎng)慎菲,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,780評(píng)論 1 285
  • 正文 為了忘掉前任锨并,我火速辦了婚禮露该,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘第煮。我一直安慰自己解幼,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,890評(píng)論 6 385
  • 文/花漫 我一把揭開白布包警。 她就那樣靜靜地躺著书幕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪揽趾。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,084評(píng)論 1 291
  • 那天苛骨,我揣著相機(jī)與錄音篱瞎,去河邊找鬼。 笑死痒芝,一個(gè)胖子當(dāng)著我的面吹牛俐筋,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播严衬,決...
    沈念sama閱讀 39,151評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼澄者,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起粱挡,我...
    開封第一講書人閱讀 37,912評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤赠幕,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后询筏,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體榕堰,經(jīng)...
    沈念sama閱讀 44,355評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,666評(píng)論 2 327
  • 正文 我和宋清朗相戀三年嫌套,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了逆屡。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,809評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡踱讨,死狀恐怖魏蔗,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情痹筛,我是刑警寧澤莺治,帶...
    沈念sama閱讀 34,504評(píng)論 4 334
  • 正文 年R本政府宣布,位于F島的核電站味混,受9級(jí)特大地震影響产雹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜翁锡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,150評(píng)論 3 317
  • 文/蒙蒙 一蔓挖、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧馆衔,春花似錦瘟判、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至减细,卻和暖如春匆瓜,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背未蝌。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評(píng)論 1 267
  • 我被黑心中介騙來泰國(guó)打工驮吱, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人萧吠。 一個(gè)月前我還...
    沈念sama閱讀 46,628評(píng)論 2 362
  • 正文 我出身青樓左冬,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親纸型。 傳聞我的和親對(duì)象是個(gè)殘疾皇子拇砰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,724評(píng)論 2 351

推薦閱讀更多精彩內(nèi)容