深度優先、廣度優先python爬蟲


搜索引擎課的一次小實驗~

題目是這樣的:

以指定網址為根節點,遍歷(深度優先、廣度優先)訪問 50 個頁面並爬取這些頁面上的所有網址。

代碼

import re
import requests
from requests.exceptions import ReadTimeout, ConnectionError, RequestException
import urllib3
# 使用requests訪問https時會有SSL驗證,需要在get方法時關閉驗證,同時會顯示警告
urllib3.disable_warnings() # 用該行代碼消除警告

visited = [] # 已經訪問過(爬取過)的url。訪問:即get該頁面並取出該頁面上的所有url
unvisited = [] # 已經取出的、但是還沒有訪問的/等待訪問的url
url_count = 0 # 已經訪問過的url數量
END_COUNT = 50 # 總共需要訪問的url數量
end_flag = False # 標志是否該結束了(url_count >= END_COUNT)

# 訪問頁面:獲取指定頁面中含有的url
def visit(url, depth):
    visited.append(url) # 將該鏈接置為訪問過
    try:
        req = requests.get(url, verify=False, timeout=5) # verify參數:關閉SSL驗證
    except ReadTimeout: # 超時異常
        print('Timeout: ', url)
         ## 需要把當前的 url 放到任務中,過一段時間再嘗試連接
    except ConnectionError: # 連接異常
        print('Connection error: ', url)
    except RequestException: # 請求異常
        print('Error: ', url)
    else:
        if req.status_code == 404:
            print('404頁面不存在: ', url)
            ## 把當前的 url 從爬蟲任務中刪除掉
        if req.status_code == 403:
            print('403頁面禁止訪問: ', url)
            ## ... 
        if req.status_code == 200:

            # 如果正確訪問,count+1;判斷是否結束
            global url_count
            global end_flag
            url_count += 1
            if url_count >= END_COUNT:
                end_flag = True

            print("\t"*depth, "#%d-%d %s"%(depth, url_count, url))

            PATTERN_URl = "<a.*href=\"(https?://.*?)[\"|\'].*"
            ulist = re.findall(PATTERN_URl, req.text)
            ulist = [url for url in ulist if url.find(".pdf") == -1 ] # 為了防止下載pdf文件,特意跳過了:只保留沒有".pdf"后綴的url

            return ulist
    return None


def dfs(url, depth=1):
    ulist = visit(url, depth)
    if ulist:
        ulist = list(set(ulist)-set(visited)) # ulist是局部變量,指的是一個節點的所有子節點
        for url in ulist:
            if depth<3 and not end_flag: # 只訪問1、2、3層(根節點是第0層)
                dfs(url, depth+1)


def bfs(url):
    depth = 0
    global unvisited
    unvisited.append([url, depth])

    while(unvisited): # unvisited每個元素是[url, depth]
        [url, depth] = unvisited.pop(0)

        # 只訪問1、2層
        if end_flag or depth >= 3:
            break
        
        ulist = visit(url, depth)
        if ulist:
            ulist = list(set(ulist)-set(visited))
            depth += 1 # ulist中的url都是當前url的孩子,所以深度加一
            unvisited = unvisited + [[url, depth] for url in ulist]

if __name__ == '__main__':
    start_url = "http://www.hzau.edu.cn"
    strategy = input("輸入dfs/bfs:")
    if strategy == "dfs":
        print("\t"*0, "#%d %s"%(0, start_url))
        dfs(start_url)
    elif strategy == "bfs":
        bfs(start_url)
    else:
        print("輸入格式有誤,請重新輸入")

結果截圖



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM