You need to enable JavaScript to run this app. Python网页爬虫递归改造与动态队列全量遍历实现咨询
优惠活动
大模型
产品
解决方案
定价
更多

Python网页爬虫递归改造与动态队列全量遍历实现咨询

现有代码核心问题梳理
  • 全局变量类型定义混乱:初始queue为列表,但代码中误用set()执行类型转换、调用列表不存在的add()方法,后续又错误转回列表,实际运行会直接抛出类型错误
  • 遍历逻辑硬编码初始长度:main函数在循环启动时就将length绑定为当前队列长度,动态新增的队列元素无法被纳入遍历范围,导致爬取在处理完首批链接后就提前终止
  • 队列去重逻辑缺失:新增链接时仅判断是否在待爬队列中,未和已爬取集合crawled做交叉校验,容易出现重复入队、死循环爬取相同链接的问题
递归版实现方案

递归逻辑核心:每次从队列头部取出未爬取的链接完成处理后,立即递归调用自身继续处理剩余队列元素,直到队列为空时触发递归终止条件,不需要手动提前绑定遍历长度。
调整后的完整可运行代码如下:

import urllib.request
from bs4 import BeautifulSoup
from urllib.parse import urljoin  # 规范处理链接拼接,替代手动字符串匹配

# 全局初始化
queue = []  # 待爬取队列
crawled = set()  # 已爬取集合,支持O(1)时间复杂度查询
base_url = 'https://www.example.com'
start_url = 'https://www.example.com/'

header = {
    'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.11',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',
    'Accept-Encoding': 'none',
    'Accept-Language': 'en-US,en;q=0.8',
    'Connection': 'keep-alive'
}

def get_http_response(url):
    # 跳过已处理过的链接
    if url in crawled:
        return None
    try:
        request = urllib.request.Request(url, headers=header)
        response = urllib.request.urlopen(request, timeout=10)
        crawled.add(url)
        return response
    except Exception as e:
        print(f"请求失败 {url}: {str(e)}")
        crawled.add(url)  # 请求失败的链接也标记为已处理,避免重复请求
        return None

def get_html_content(http_response):
    if not http_response:
        return None
    content = http_response.read()
    return BeautifulSoup(content, 'html.parser')

def link_finder(html):
    if not html:
        return []
    valid_new_links = []
    for tag in html.select('[href]'):
        raw_href = tag['href']
        # 自动识别绝对路径、相对路径、协议相对路径,自动拼接为完整URL
        full_url = urljoin(base_url, raw_href)
        # 三重校验:仅保留同域名、未爬取、未入队的有效链接
        if full_url.startswith(base_url) and full_url not in crawled and full_url not in queue:
            valid_new_links.append(full_url)
    return valid_new_links

def crawler_recursive():
    # 递归终止条件:待爬队列为空时停止
    if not queue:
        return
    # 取出队首待爬链接
    current_url = queue.pop(0)
    # 完成当前链接的请求、解析、提取新链接全流程
    response = get_http_response(current_url)
    html = get_html_content(response)
    new_links = link_finder(html)
    # 新发现的有效链接加入队列
    queue.extend(new_links)
    # 递归处理下一个队列元素
    crawler_recursive()

def main():
    # 初始化队列加入起始爬取地址
    if start_url not in crawled:
        queue.append(start_url)
    crawler_recursive()
    print(f"爬取完成,共处理 {len(crawled)} 个页面")

if __name__ == "__main__":
    main()
关键逻辑说明
  • 递归终止条件直接判断队列是否为空,不需要手动计算固定遍历长度,队列动态新增的元素会自动被纳入后续处理流程
  • 用urljoin替代手动拼接链接,避免漏处理带查询参数、多级相对路径、协议相对路径的链接
  • 三重去重校验机制:新链接同时排除已爬取集合、待爬队列中的重复项,避免无意义的重复请求
  • 增加基础异常捕获,避免单个页面请求失败导致整个爬虫崩溃
    注意:Python默认递归深度上限为1000,如果目标网站待爬链接量超过递归深度阈值,可将递归逻辑替换为等价的while循环实现,处理逻辑完全一致,不会出现栈溢出问题:
def crawler_loop():
    while queue:
        current_url = queue.pop(0)
        response = get_http_response(current_url)
        html = get_html_content(response)
        new_links = link_finder(html)
        queue.extend(new_links)

内容的提问来源于stack exchange,提问作者Soumya Pandey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.07 19:36:01