我试图用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个附加链接。
答案 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的错误处理和修剪。相对链接和绝对链接混合在一起,其中一些带有前斜杠和/或后斜杠。我将把这些作为练习留给读者。