如何将Python链接爬虫从深度优先改为广度优先遍历?
如何将基于BeautifulSoup的深度优先网页爬虫改为广度优先遍历?
我有一个网站结构如下:
http://example.com/home包含指向/page1、/page2、/page3的链接http://example.com/page1包含指向/page2368的链接http://example.com/page2包含指向/page41的链接http://example.com/page2368包含指向/page999990到/page999999的链接
目前我用下面这段基于BeautifulSoup的Python代码做链接爬取,它是深度优先遍历(DFS)的,会先走完
/home→/page1→/page2368→/page999990这条线,之后才会去访问/page2:from bs4 import BeautifulSoup def visit(url, recursion=0): links = getpage_and_retrieve_ahref_links(url) # using beautifulsoup for link in links: if recursion < 10: # limit recursion to 10 visit(link, recursion+1) visit('http://example.com/home')
我需要把它改成广度优先遍历(BFS),也就是先爬完所有
recursion=1层级的页面(/page1、/page2、/page3),再爬recursion=2层级的(/page2368、/page41),以此类推,访问顺序应该是:/home→/page1→/page2→/page3→/page2368→/page41→/page999990... 请问该怎么修改代码?
核心思路:用队列替代递归
咱们先理清楚本质:深度优先遍历(DFS)靠的是递归的“栈”特性(后进先出),会一条路走到头再回头;而广度优先遍历(BFS)需要队列(先进先出)来管理待爬的URL,先把当前层级的所有页面都处理完,再去处理下一层级的内容。
Python的collections.deque是实现队列的绝佳选择,它的popleft()操作是O(1)的,比用列表模拟队列高效得多。
修改后的代码
from bs4 import BeautifulSoup from collections import deque def bfs_crawl(start_url, max_depth=10): # 初始化队列,每个元素是(当前URL, 当前层级) queue = deque() queue.append((start_url, 0)) # 可选:记录已访问的URL,避免重复爬取(根据需求选择是否添加) visited = set() visited.add(start_url) while queue: current_url, depth = queue.popleft() # 处理当前页面:获取所有链接 links = getpage_and_retrieve_ahref_links(current_url) # 如果当前层级还没到最大限制,就把新链接加入队列 if depth < max_depth: for link in links: # 可选:跳过已访问的链接 if link not in visited: visited.add(link) queue.append((link, depth + 1)) # 启动爬虫 bfs_crawl('http://example.com/home')
关键细节说明
- 队列的作用:每次从队列头部取出最早上加入的URL(当前层级的页面),爬完后把它的子链接(下一层级)加到队列尾部,完美实现“先爬完当前所有层级,再爬下一层”的BFS逻辑。
- 层级管理:用
(url, depth)的元组替代原来的递归参数,清晰记录每个页面的层级,确保不会超过你设置的最大深度限制。 - 去重优化:添加
visited集合是为了避免重复爬取同一个URL(比如不同页面指向同一个链接的情况),如果你的网站没有重复链接,也可以去掉这部分,但建议保留以提升爬虫效率。 - 替代递归的优势:BFS用迭代+队列实现,不仅更符合遍历逻辑,还能避免递归深度过大导致的栈溢出问题(比如如果你的层级限制不是10而是100,递归大概率会报错)。
内容的提问来源于stack exchange,提问作者Basj
相关产品推荐
相关产品推荐

