如何实现广度优先和深度优先的搜索网络搜寻器?

时间:2019-04-20 01:01:28

标签: python-3.x beautifulsoup web-crawler depth-first-search breadth-first-search

我试图用Python编写带有美丽汤的网络爬虫,以便对所有链接进行爬网。在获得主页上的所有链接之后,我试图实现深度优先和宽度优先的搜索以找到100个其他链接。目前,我已经抓取并获得了主页上的链接。现在,我需要帮助来实现我的搜寻器的深度优先和宽度优先。

我相信我的网络爬虫正在进行深度优先搜索。这是正确的还是我的代码没有正确进行深度优先搜索?此外,如何调整代码以创建广度优先搜索?我相信我需要有一个队列并使用pop函数,但是由于我是Python的新手,所以我不确定如何正确执行循环。

我已经尝试过调整代码,但是到目前为止,我没有尝试过任何工作来获得正确的结果。

from pandas import *
import urllib.request
import re
import time
from bs4 import BeautifulSoup

#open webpage and put into soup

myURL="http://toscrape.com"
response = urllib.request.urlopen(myURL)
html = response.read()
soup = BeautifulSoup(html, "html.parser")

#get links on the main page 

websitesvisited = []
for link in soup.findAll('a'):
    websitesvisited.append(link.get('href'))

#use depth-first search to find 100 additional links

allLinks= [] 
for links in websitesvisited:
    myURL=links
    response = urllib.request.urlopen(myURL)
    html = response.read()
    soup = BeautifulSoup(html, "html.parser")
    if len(allLinks) < 101:
        for link in soup.findAll('a'):
            if link.get('href') not in allLinks:
                if link.get('href') != None:
                    if link.get('href') [0:4] == 'http':
                        allLinks.append(link.get('href'))
    time.sleep(3)

for weblinks in allLinks:
    print(weblinks)

我在网上抓取了主页并获得了所有链接。现在,我期望使用深度优先和宽度优先的网络爬网获得大约100个附加链接。

1 个答案:

答案 0 :(得分:3)

您非常正确。 DFS的关键是递归,这是上面代码中缺少的元素。对于当前页面上的每个链接,请在访问页面上的其余链接之前递归浏览它。使用visited设置来跟踪已被爬网的页面,以避免陷入循环。

在DFS中,“探索的链接总数”值可能无济于事,因为您的搜寻器只会击倒前100页的第一个链接,然后回头浏览而没有任何内容(互联网上几乎每个页面都有链接,因此很难找到终端节点)。 “深度”(或“距离” )上限更有意义:这使我们可以探索当前页面以外的所有链接max_depth页。

无论哪种方式,代码都基本相同,当然,如果您将其编码为基本情况,则可以说“给我第一个cap链接,最多可深入max_depth页”在递归中。另一个想法是确保您正在浏览的所有链接都来自quotes.toscrape网站。 BFS严格探索附近区域并散开。可以使用队列迭代地完成此操作。

这是递归DFS草图:

import requests
from bs4 import BeautifulSoup

def get_links_recursive(base, path, visited, max_depth=3, depth=0):
    if depth < max_depth:
        try:
            soup = BeautifulSoup(requests.get(base + path).text, "html.parser")

            for link in soup.find_all("a"):
                href = link.get("href")

                if href not in visited:
                    visited.add(href)
                    print(f"at depth {depth}: {href}")

                    if href.startswith("http"):
                        get_links_recursive(href, "", visited, max_depth, depth + 1)
                    else:
                        get_links_recursive(base, href, visited, max_depth, depth + 1)
        except:
            pass


get_links_recursive("http://toscrape.com", "", set(["http://toscrape.com"]))

这是BFS草图:

import requests
from bs4 import BeautifulSoup
from collections import deque

visited = set(["http://toscrape.com"])
dq = deque([["http://toscrape.com", "", 0]])
max_depth = 3

while dq:
    base, path, depth = dq.popleft()
    #                         ^^^^ removing "left" makes this a DFS (stack)

    if depth < max_depth:
        try:
            soup = BeautifulSoup(requests.get(base + path).text, "html.parser")

            for link in soup.find_all("a"):
                href = link.get("href")

                if href not in visited:
                    visited.add(href)
                    print("  " * depth + f"at depth {depth}: {href}")

                    if href.startswith("http"):
                        dq.append([href, "", depth + 1])
                    else:
                        dq.append([base, href, depth + 1])
        except:
            pass

这些是非常简单的草图。几乎不处理href的错误处理和修剪。相对链接和绝对链接混合在一起,其中一些带有前斜杠和/或后斜杠。我将把这些作为练习留给读者。