Вы очень на правильном пути. Ключ к DFS - рекурсия, отсутствующий элемент в приведенном выше коде. Для каждой ссылки на текущей странице, рекурсивно исследуйте ее перед посещением оставшихся ссылок на странице. Используйте набор visited
, чтобы отслеживать, какие страницы уже были просканированы, чтобы избежать зацикливания.
Значение "общее количество изученных ссылок", скорее всего, не поможет в DFS, поскольку ваш сканер просто снимет первую ссылку с первых 100 страниц, а затем вернется назад без какой-либо широты (почти каждая страница в Интернете имеет ссылки, поэтому терминальные узлы трудно найти). Ограничение «глубины» (или distance ) имеет больше смысла: это позволяет нам исследовать все ссылки 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
Это довольно миниатюрные наброски. Обработка ошибок и сокращение hrefs практически не рассматриваются. Существует сочетание относительных и абсолютных ссылок, некоторые из которых имеют начальную и / или конечную косую черту. Я оставлю манипулирование ими как упражнение для читателя.