使用BeautifulSoup抓取AJAX动态加载内容的策略有哪些

来源:Java编程网作者:深圳程序员头衔:程序员
导读:本期聚焦于深圳程序员创作的《使用BeautifulSoup抓取AJAX动态加载内容的策略有哪些》,敬请观看详情。很多网页的内容通过AJAX动态加载,直接使用BeautifulSoup抓取静态页面无法获取完整数据。本文介绍几种实用的抓取策略,包括分析网络请求直接获取接口数据、结合selenium模拟浏览器执行JS加载内容、使用requests-html渲染页面等方法。每种策略都会配合具体的代码实现,说明适用场景和注意事项,帮助开发者根据实际需求选择合适的方案,解决动态内容抓取难题,提升爬虫开发的效率。

在网页抓取实践中,许多页面的关键信息并不是一开始就写在服务器返回的 HTML 中,而是通过异步请求在浏览器中二次加载,再由前端脚本插入到文档对象模型里。BeautifulSoup 擅长解析已经拿到的 HTML 文本,但它本身不会执行脚本,也不会主动发起浏览器内部的异步请求。因此,当目标数据由 AJAX 生成时,单纯解析初始响应往往只能得到骨架、占位符或加载提示。要解决这个问题,需要根据页面加载机制选择合适策略,而不是机械地重复解析静态源码。

理解 AJAX 动态加载与 BeautifulSoup 的解析边界

从原理上看,AJAX 动态内容通常分为几类。第一类是后端接口返回 JSON,前端拿到数据后拼接成列表、卡片或表格。第二类是后端接口直接返回 HTML 片段,前端将其插入已有节点。第三类是页面依赖复杂脚本、事件触发或用户交互,才会把数据渲染到可见区域。不同类型对应不同抓取入口,也决定了 BeautifulSoup 的介入时机。

BeautifulSoup 的角色应当放在整个抓取流程中理解。它负责把结构化或半结构化的 HTML 转成可查询的对象,支持选择器、属性过滤和文本提取。但它并不承担网络分析、脚本执行和事件模拟职责。因此,面对动态页面时,更稳妥的思路是先确认数据最终出现的位置,再决定是在接口层获取,还是在渲染后的页面源码层解析。

判断数据位置时,可以从页面表现入手。如果页面刚打开就出现内容,但源码中没有对应文本,说明内容大概率来自脚本执行后的网络请求。如果内容需要点击、翻页、滚动才出现,则可能涉及事件触发接口。如果页面嵌套了 <iframe>,还需要先确认目标内容是否位于子文档中。只有把加载链路梳理清楚,后续选择 BeautifulSoup 解析接口片段还是完整渲染结果,才会更有针对性。

  • 观察初始响应中是否已经包含目标文本。
  • 观察浏览器异步请求是否返回 JSON 或 HTML 片段。
  • 观察目标内容是否需要点击、滚动或切换分页才会出现。

优先分析网络请求:直接请求 AJAX 接口

在多数情况下,直接分析网络请求是优先级最高的方案。因为动态内容最终往往来自一个或多个数据接口,接口响应可能非常干净,例如 JSON 数组、分页对象或 HTML 片段。跳过页面渲染过程,直接请求接口,可以减少脚本执行开销,也能避免被复杂前端结构干扰。对于需要批量翻页、稳定采集的任务,这种方式通常更容易控制节奏和异常。

分析接口时,可以借助浏览器开发者工具观察异步请求。重点关注请求方法、查询参数、请求头、Cookie、Referer 以及响应格式。如果接口只依赖简单分页参数,直接模拟请求即可。如果接口带有签名、时间戳、设备标识或加密令牌,则需要评估能否在 Python 中稳定复现生成逻辑。若无法复现,就不宜强行逆向,而应考虑浏览器自动化方案。

当接口返回 JSON 时,BeautifulSoup 不一定参与核心解析,因为 JSON 本身已有明确结构。只有当接口返回 HTML 片段,或者返回内容中仍夹杂需要二次提取的标签结构时,BeautifulSoup 才继续发挥作用。下面示例展示如何请求一个带分页参数的接口,并根据响应类型分别处理 JSON 与 HTML 片段。

import requests
from bs4 import BeautifulSoup

# 模拟常见浏览器请求头,降低被拦截的概率
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
}

api_url = 'https://api.ipipp.com/list'
params = {'page': 1}

response = requests.get(api_url, headers=headers, params=params, timeout=10)
response.raise_for_status()

content_type = response.headers.get('Content-Type', '')

# 如果接口返回JSON,则直接按JSON处理
if 'application/json' in content_type:
    data = response.json()
    print(data)
else:
    # 如果接口返回HTML片段,则交给BeautifulSoup解析
    soup = BeautifulSoup(response.text, 'html.parser')
    for item in soup.select('.list-item'):
        print(item.get_text(strip=True))

实际使用时,还需要注意响应状态、超时、重试和空数据分支。接口可能返回空列表、错误码或需要登录的提示页,单纯假设返回格式固定会导致程序中断。将请求层与解析层分离,先校验响应,再交给 BeautifulSoup 或 JSON 解析器处理,可以提高脚本健壮性。

使用 Selenium 驱动真实浏览器并交给 BeautifulSoup 解析

当接口难以直接模拟时,Selenium 是更稳妥的替代方案。它可以驱动真实浏览器加载页面,让脚本、样式、异步请求和事件机制按正常流程执行。等到目标元素出现在文档中以后,再读取完整页面源码,交给 BeautifulSoup 做后续解析。这样既利用了浏览器环境处理复杂前端逻辑,又保留了 BeautifulSoup 在节点查询和文本清洗上的便利。

使用 Selenium 时,应尽量避免只靠固定睡眠等待内容。页面加载速度、网络延迟和脚本执行顺序都可能变化,固定等待时间太短会漏数据,太长会拖慢任务。显式等待更可靠,例如等待某个类名、属性或文本出现。对于列表内容,可以等待第一个列表项出现,再决定是否继续滚动或翻页。

如果动态内容依赖滚动加载,还需要模拟用户滚动行为。很多页面并不会一次性请求全部数据,而是在接近底部时继续调用下一页接口。此时可以先等待首个内容块出现,再多次滚动到底部,让浏览器持续触发加载。下面示例分别展示基础等待解析,以及滚动加载后的 BeautifulSoup 提取过程。

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from bs4 import BeautifulSoup

options = webdriver.ChromeOptions()
options.add_argument('--headless')

driver = webdriver.Chrome(options=options)

try:
    driver.get('https://www.ipipp.com/dynamic-page')

    # 等待动态内容出现,最多等待10秒
    wait = WebDriverWait(driver, 10)
    wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'dynamic-content')))

    # 浏览器渲染完成后,再取出完整页面源码
    soup = BeautifulSoup(driver.page_source, 'html.parser')

    for content in soup.select('.dynamic-content'):
        print(content.get_text(strip=True))
finally:
    driver.quit()
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from bs4 import BeautifulSoup

options = webdriver.ChromeOptions()
options.add_argument('--headless')

driver = webdriver.Chrome(options=options)

try:
    driver.get('https://www.ipipp.com/infinite-scroll-page')

    wait = WebDriverWait(driver, 10)
    wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'ajax-loaded-item')))

    # 模拟多次滚动到底部,触发后续异步加载
    for _ in range(3):
        driver.execute_script('window.scrollTo(0, document.body.scrollHeight);')
        time.sleep(2)

    soup = BeautifulSoup(driver.page_source, 'html.parser')

    for item in soup.select('.ajax-loaded-item'):
        print(item.get_text(strip=True))
finally:
    driver.quit()

在 Selenium 场景中,浏览器资源占用较高,因此要及时关闭浏览器实例,并尽量使用无头模式减少界面开销。同时,页面结构可能在加载过程中发生变化,解析前应确认目标节点已经稳定。若页面存在懒加载图片、骨架屏或占位文本,也可以结合属性判断,避免把未完成渲染的中间状态当作最终数据。

轻量渲染方案、策略对比与实践建议

除了 Selenium,也可以使用更轻量的渲染型请求库完成部分动态页面抓取。requests-html 将普通请求与脚本渲染能力结合在一起,适合页面逻辑不复杂、无需大量交互的场景。它先获取初始响应,再在内部执行页面脚本,待渲染完成后输出 HTML。此时再把结果交给 BeautifulSoup,就可以提取原本不在初始源码中的内容。

from requests_html import HTMLSession
from bs4 import BeautifulSoup

session = HTMLSession()

try:
    response = session.get('https://www.ipipp.com/dynamic-page')

    # 执行页面脚本,等待动态内容渲染
    response.html.render(timeout=10)

    soup = BeautifulSoup(response.html.html, 'html.parser')

    for item in soup.select('.ajax-loaded-item'):
        print(item.get_text(strip=True))
finally:
    session.close()

不同策略的选择,本质上是在效率、稳定性和复杂度之间取得平衡。直接请求接口速度最快,但前提是接口可被稳定复现。Selenium 适应性最强,但资源消耗和运行成本更高。轻量渲染方案介于两者之间,使用简单,却不一定能覆盖所有复杂脚本。实际项目中,通常建议先尝试接口分析,失败后再逐步升级到浏览器方案。

策略优势局限适用情况
直接请求接口速度快,资源占用低,便于批量翻页需要分析请求参数和响应结构,复杂签名较难复现接口清晰、参数简单、返回 JSON 或 HTML 片段
Selenium 渲染能执行脚本,支持等待、点击、滚动等交互启动浏览器成本较高,速度相对较慢接口校验严格、页面逻辑复杂或需要模拟用户行为
轻量渲染请求使用较简单,比完整浏览器更轻对复杂脚本和反制机制支持有限动态逻辑不复杂且无需大量交互的页面

在实施过程中,还应重视合规与稳定性。抓取前应查看目标网站的 robots.txt,确认采集范围是否允许。请求频率要控制在合理区间,避免短时间内大量访问造成服务器压力。对于需要登录、地域限制或会话保持的页面,应妥善管理 Cookie 和请求头。若动态内容位于 <iframe> 中,需要先获取其来源地址或切换到对应文档上下文,再决定解析方式。

综合来看,BeautifulSoup 并不是不能处理 AJAX 页面,而是需要放在正确的流程节点上使用。它可以解析接口返回的 HTML 片段,也可以解析浏览器渲染完成后的页面源码。真正决定抓取效果的是对加载机制的判断:优先寻找数据接口,必要时借助浏览器执行脚本,最后用合适的解析器完成结构化提取。掌握这套思路后,面对动态加载页面时就能更从容地设计方案,而不是在静态源码中反复寻找不存在的数据。

BeautifulSoupAJAX动态加载requestsselenium数据抓取修改时间:2026-07-01 00:21:43

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。