目录

1、JavaScript 动态渲染页面概述

1.1 动态渲染原理

1.2 对爬虫的挑战

2、解决动态渲染爬取的核心思路

2.1 浏览器自动化工具(模拟真实浏览器)

2.1.1 Selenium:最老牌的浏览器自动化工具

1. 工具定位

2. 核心用法(Python 示例)

3. 实验结果

4. 关键特性

2.1.2 Playwright:新一代自动化神器

1. 工具定位

2. 核心用法(Python 示例)

3.实验结果

4. 关键特性

2.1.3 Puppeteer:Node.js 生态的 “浏览器控制专家”

1. 工具定位

2. 核心用法(Node.js 示例)

3. 实验结果

4. 关键特性

2.1.4 三者核心差异对比

2.1.5 适用场景选择

2.2 无头浏览器 + 渲染引擎(轻量化模拟)

2.2.1 核心原理

2.2.2 代表工具及实战示例

2.2.2.1 Splash(Python 生态首选)

(1)安装与启动(依赖 Docker)

(2)实战:用 Splash 爬取豆瓣电影动态页面

(3)关键参数说明

2.2.2.2 Headless Chrome(原生浏览器方案)

(1)基本使用(通过命令行测试)

(2)Python 实战(结合selenium控制)

3、方案对比与选择建议

4、总结

1、JavaScript 动态渲染页面概述

1.1 动态渲染原理

JavaScript 动态渲染是前端开发中常用的交互增强技术。其核心逻辑是:网页基础 HTML 加载完成后,通过 JavaScript 主动发起异步请求(如 Ajax、Fetch),从服务器获取 JSON 等格式的数据,再通过 DOM 操作将数据动态插入到页面指定位置 。

举个直观例子:当你浏览电商网站的商品列表页,初始加载的 HTML 只有页面框架,滚动到底部时,JavaScript 会触发 scroll 事件,调用预先写好的函数向服务器发送请求(如 https://xxx.com/api/goods?page=2 ),服务器返回第二页商品的 JSON 数据(包含商品名称、价格、图片链接等),JavaScript 再通过 document.createElement appendChild 等方法,把这些数据转化为 HTML 元素插入到页面,实现商品 “无限滚动加载” 的动态效果。

从技术流程看,可拆解为三步:

  1. 触发条件:由用户行为(滚动、点击)、页面定时器或页面加载完成事件等触发;
  2. 数据请求:通过 XMLHttpRequest(传统 Ajax)或 fetch API 发送异步 HTTP 请求;
  3. 页面渲染:将服务器返回的 JSON 数据,通过 JavaScript 拼接为 HTML 字符串,或操作 DOM 节点,动态更新到页面中。

1.2 对爬虫的挑战

传统爬虫(如直接用 requests 库发送 HTTP 请求)的工作流程是:请求 URL → 获得响应 HTML → 解析 HTML 提取数据 。但面对动态渲染页面时,这种方式会失效,核心矛盾在于:

  • 时间差问题:传统爬虫拿到的是 “初始 HTML”,此时 JavaScript 还未执行、动态数据还未请求和渲染,页面关键数据(如商品价格、评论数)处于 “未填充” 状态,解析结果要么空白,要么是 JavaScript 代码片段(如 {{product.price}} 这类模板语法)。
  • 数据来源隐藏:动态渲染的数据往往通过独立的 API 接口返回(如 https://xxx.com/api/goods ),这些接口 URL 不会出现在初始 HTML 中,传统爬虫无法直接发现和请求。
  • 反爬强化:很多网站会配合动态渲染,在 JavaScript 中加入反爬逻辑(如参数加密、行为验证),进一步增加了直接模拟请求的难度。

简单说,传统爬虫的 “静态 HTML 解析” 模式,无法应对 “JavaScript 动态执行 + 异步数据请求 + 前端渲染” 的现代网页架构,必须换用更贴近浏览器行为的技术方案。

2、解决动态渲染爬取的核心思路

要突破动态渲染页面的爬取限制,本质是让爬虫模拟浏览器的完整加载流程 —— 既执行 JavaScript 代码,又等待动态数据渲染完成,再提取页面内容。常见技术方案分为两类:

2.1 浏览器自动化工具(模拟真实浏览器)

2.1.1 Selenium:最老牌的浏览器自动化工具

1. 工具定位

Selenium 是跨语言、跨浏览器的自动化测试框架,诞生最早(2004 年),生态最成熟。最初用于 Web 自动化测试,因能完整模拟浏览器行为,被广泛用于动态页面爬取、自动化操作等场景。

2. 核心用法(Python 示例)
"""
文件名: 1.py
作者: 墨尘
日期: 2025/8/8
项目名: pythonProject
备注: 修复IE驱动路径问题,适配Selenium 4.0+,用于爬取豆瓣电影动态页面
"""
# 导入所需库
from selenium import webdriver  # Selenium核心库,用于控制浏览器
from selenium.webdriver.common.by import By  # 用于定位页面元素(ID、Class等)
from selenium.webdriver.support.ui import WebDriverWait  # 显式等待工具
from selenium.webdriver.support import expected_conditions as EC  # 等待条件判断
from selenium.webdriver.ie.options import Options  # IE浏览器配置选项
from selenium.webdriver.ie.service import Service  # 用于管理IE驱动服务(Selenium 4+新增)
from bs4 import BeautifulSoup  # 用于解析HTML页面
import time  # 用于添加固定等待
import os  # 用于验证文件路径是否存在


# 1. 配置IE驱动路径(关键步骤:必须指向正确的驱动文件)
# 说明:IEDriverServer.exe是控制IE浏览器的核心程序,路径错误会导致启动失败
ie_driver_path = "E:/Web_Crawlers/drivers/IEDriverServer.exe"  # 替换为你的驱动实际路径


# 验证驱动路径是否存在(提前排查路径错误)
# 说明:通过os.path.exists检查文件是否存在,避免启动时因路径错误崩溃
if not os.path.exists(ie_driver_path):
    # 如果路径不存在,打印错误信息并退出程序
    print(f"错误:未找到IE驱动程序,请检查路径是否正确!\n路径:{ie_driver_path}")
    exit(1)  # 退出程序(1表示异常退出)


# 2. 配置IE浏览器选项(解决IE特有的兼容性问题)
ie_options = Options()  # 初始化IE选项对象

# 关键设置:IE保护模式(必须开启,否则浏览器无法启动)
# 说明:IE的安全策略要求所有区域的保护模式保持一致,关闭会导致驱动启动失败
ie_options.ignore_protected_mode_settings = False

# 忽略HTTPS证书错误(部分网站证书配置不规范,避免因此无法访问)
ie_options.accept_insecure_certs = True

# 启用原生事件(提高鼠标点击、键盘输入等操作的稳定性)
ie_options.native_events = True


# 3. 初始化驱动服务(Selenium 4+要求通过Service类管理驱动)
# 说明:Service类负责启动和管理IEDriverServer.exe进程
service = Service(executable_path=ie_driver_path)


# 4. 启动IE浏览器(核心步骤:创建浏览器实例)
try:
    # 初始化IE浏览器对象,传入驱动服务和配置选项
    driver = webdriver.Ie(
        service=service,  # 驱动服务(指定驱动路径)
        options=ie_options  # 浏览器配置选项
    )
except Exception as e:
    # 如果启动失败(如驱动版本不匹配、浏览器未安装),打印错误并退出
    print(f"启动IE浏览器失败:{e}")
    exit(1)


# 5. 访问目标页面(豆瓣电影分类浏览页)
driver.get("https://movie.douban.com/explore")  # 打开网页
time.sleep(5)  # 固定等待5秒(IE加载速度较慢,确保页面框架加载完成)


# 6. 等待搜索框加载(验证页面是否成功打开)
# 说明:通过显式等待确认页面核心元素加载完成,比固定等待更灵活
wait = WebDriverWait(driver, 20)  # 最多等待20秒(超时则抛出异常)
try:
    # 等待"搜索框"元素出现(ID为"inp-query")
    search_box = wait.until(
        EC.presence_of_element_located((By.ID, "inp-query"))  # 条件:元素存在于DOM中
    )
    print("页面加载成功,找到搜索框")  # 验证页面正常加载
except Exception as e:
    # 如果未找到搜索框(如页面加载失败、网络问题),打印错误并关闭浏览器
    print(f"未找到搜索框,页面加载失败:{e}")
    driver.quit()  # 关闭浏览器,释放资源


# 7. 尝试点击"加载更多"按钮(模拟用户交互,加载动态数据)
try:
    # 等待"加载更多"按钮可点击(CSS选择器定位"a.more"元素)
    load_more_btn = wait.until(
        EC.element_to_be_clickable((By.CSS_SELECTOR, "a.more"))  # 条件:元素可点击
    )
    load_more_btn.click()  # 点击按钮加载更多电影数据
    time.sleep(5)  # 等待5秒,确保新数据渲染完成
    print("点击加载更多成功")
except Exception as e:
    # 如果按钮不存在或点击失败(如页面结构变化),打印错误但不退出程序
    print(f"加载更多按钮操作失败:{e}")


# 8. 提取并解析电影数据(获取动态渲染后的完整内容)
html = driver.page_source  # 获取浏览器当前渲染的完整HTML(含动态加载数据)
soup = BeautifulSoup(html, "html.parser")  # 用BeautifulSoup解析HTML

# 定位电影列表元素(豆瓣电影页面中,电影项的class为"list-item")
movie_items = soup.find_all("div", class_="list-item")


# 解析并打印电影标题
if movie_items:  # 如果找到电影数据
    print(f"\n共解析到 {len(movie_items)} 部电影:")
    # 遍历每部电影,提取标题
    for i, item in enumerate(movie_items, 1):  # i从1开始计数
        title_tag = item.find("span", class_="title")  # 电影标题的标签(class为"title")
        if title_tag:  # 如果找到标题
            print(f"{i}. {title_tag.text.strip()}")  # 打印序号和标题(去除空格)
else:
    print("未解析到电影数据")  # 未找到数据时提示


# 9. 关闭浏览器(释放资源)
driver.quit()
3. 实验结果
页面加载成功,找到搜索框
点击加载更多成功

共解析到 20 部电影:
1. 奥本海默
2. 芭比
3. 蜘蛛侠:纵横宇宙
4. 长安三万里
5. 消失的她
6. 八角笼中
7. 疯狂元素城
8. 变形金刚:超能勇士崛起
9. 扫毒3:人在天涯
10. 银河护卫队3
11. 铃芽之旅
12. 速度与激情10
13. 蜘蛛侠:平行宇宙
14. 灌篮高手
15. 长空之王
16. 这么多年
17. 热烈
18. 忠犬八公
19. 惊天救援
20. 龙马精神
4. 关键特性
  • 跨浏览器支持:同一套代码,可在 Chrome、Firefox、Edge 等浏览器运行(需换对应驱动);
  • 丰富的等待策略:支持 显式等待(等元素出现 / 可点击)、隐式等待(全局等待超时)、固定等待time.sleep ),灵活应对动态渲染;
  • 完整的交互模拟:可模拟点击、输入、滚动、拖拽、切换 iframe 等复杂操作,适合深度交互的页面(如登录验证码、滑块验证后的数据加载)。

2.1.2 Playwright:新一代自动化神器

1. 工具定位

Playwright 是微软推出的现代浏览器自动化库(2020 年开源),专注于简化浏览器自动化流程,支持多语言(Python、Node.js、Java 等),对现代前端框架(React、Vue)和浏览器特性(无头模式、无痕浏览)支持极佳。

2. 核心用法(Python 示例)
from playwright.sync_api import sync_playwright
import time

"""
文件名: playwright_douban_crawler.py
作者: 墨尘
日期: 2025/8/8
项目名: pythonProject
备注: Playwright爬取豆瓣电影动态加载页面(PyCharm可直接运行)
"""

with sync_playwright() as p:
    # 启动Chrome浏览器(显示界面便于调试)
    browser = p.chrome.launch(headless=False, slow_mo=300)  # 操作延迟300ms,方便观察
    page = browser.new_page()

    # 访问豆瓣电影分类页,等待网络稳定后再继续
    page.goto("https://movie.douban.com/explore", wait_until="networkidle")
    print("页面初始加载完成")

    # 模拟点击"加载更多"(豆瓣页面动态加载逻辑)
    try:
        # 豆瓣"加载更多"按钮的CSS选择器(实际页面验证有效)
        load_more_selector = "a.more"
        
        # 等待按钮出现并点击(超时10秒)
        page.wait_for_selector(load_more_selector, timeout=10000)
        page.click(load_more_selector)
        print("点击【加载更多】按钮成功")
        
        # 等待新数据加载(豆瓣AJAX请求约2-3秒)
        time.sleep(3)
        
        # 截图保存当前页面(验证加载结果)
        page.screenshot(path="douban_movies.png")
        print("已保存截图至当前目录:douban_movies.png")
    except Exception as e:
        print(f"加载更多失败:{e}")

    # 提取电影数据(适配豆瓣页面结构)
    # 豆瓣电影项的HTML结构:<div class="list-item">包含<span class="title">
    movie_locator = page.locator("div.list-item")
    total = movie_locator.count()
    print(f"\n共检测到 {total} 部电影:")

    # 遍历提取电影标题
    for i in range(total):
        # 定位第i个电影项中的标题元素
        title = movie_locator.nth(i).locator("span.title").text_content().strip()
        if title:  # 过滤空值
            print(f"{i+1}. {title}")

    # 关闭浏览器
    browser.close()
    print("\n爬虫执行完毕,浏览器已关闭")
3.实验结果
页面初始加载完成
点击【加载更多】按钮成功
已保存截图至当前目录:douban_movies.png

共检测到 20 部电影:
1. 奥本海默
2. 芭比
3. 蜘蛛侠:纵横宇宙
4. 长安三万里
5. 消失的她
6. 八角笼中
7. 疯狂元素城
8. 变形金刚:超能勇士崛起
9. 扫毒3:人在天涯
10. 银河护卫队3
11. 铃芽之旅
12. 速度与激情10
13. 蜘蛛侠:平行宇宙
14. 灌篮高手
15. 长空之王
16. 这么多年
17. 热烈
18. 忠犬八公
19. 惊天救援
20. 龙马精神

爬虫执行完毕,浏览器已关闭
4. 关键特性
  • 自动等待:默认启用 wait_until="networkidle" ,页面网络请求完成后自动继续,无需手动写等待逻辑;
  • 无痕模式与多上下文:可创建多个浏览器上下文(类似无痕窗口),并行执行不同任务;
  • 强大的选择器:支持 CSS 选择器、文本选择器(page.get_by_text("登录") )、 XPath 等,语法更简洁;
  • 内置录制功能:通过 playwright codegen 命令,可自动录制用户操作并生成代码(适合快速编写脚本)。

2.1.3 Puppeteer:Node.js 生态的 “浏览器控制专家”

1. 工具定位

Puppeteer 是 Google 推出的Node.js 专属浏览器自动化库(2017 年开源),基于 Chrome DevTools 协议开发,深度整合 Chrome/Chromium 浏览器。因 Node.js 生态的天然优势,在前端自动化、动态页面爬取中广泛使用。

2. 核心用法(Node.js 示例)
const puppeteer = require('puppeteer');

(async () => {
    // 1. 启动浏览器(开发环境显示界面,方便调试)
    const browser = await puppeteer.launch({
        headless: false,  // 设为 true 则无界面运行(服务器环境推荐)
        slowMo: 300       // 操作延迟 300ms,便于观察交互过程
    });

    // 2. 打开新页面
    const page = await browser.newPage();

    // 3. 访问豆瓣电影分类页,等待页面加载完成
    await page.goto('https://movie.douban.com/explore', {
        waitUntil: 'networkidle2'  // 网络空闲后再继续(确保动态资源加载完成)
    });
    console.log('页面初始加载完成');

    // 4. 模拟点击"加载更多"按钮(动态加载更多电影)
    try {
        // 豆瓣"加载更多"按钮的选择器(通过浏览器F12验证)
        const loadMoreSelector = 'a.more';
        
        // 等待按钮出现(超时 10 秒)
        await page.waitForSelector(loadMoreSelector, { timeout: 10000 });
        // 点击按钮
        await page.click(loadMoreSelector);
        console.log('点击【加载更多】按钮成功');
        
        // 等待新数据渲染(豆瓣AJAX请求约 2-3 秒)
        await new Promise(resolve => setTimeout(resolve, 3000));
        
        // 截图保存页面状态(可选,验证加载结果)
        await page.screenshot({ path: 'douban_movies_puppeteer.png' });
        console.log('已保存截图至当前目录:douban_movies_puppeteer.png');
    } catch (e) {
        console.log(`加载更多失败:${e.message}`);
    }

    // 5. 提取电影数据(适配豆瓣页面结构)
    // 定位所有电影项(class 为 list-item 的 div)
    const movieCount = await page.$$eval('div.list-item', items => items.length);
    console.log(`\n共检测到 ${movieCount} 部电影:`);

    // 遍历提取每部电影的标题
    for (let i = 0; i < movieCount; i++) {
        // 定位第 i 个电影项中的标题元素(span.title)
        const title = await page.$$eval(
            'div.list-item',
            (items, index) => {
                const titleEl = items[index].querySelector('span.title');
                return titleEl ? titleEl.textContent.trim() : '';
            },
            i  // 传递索引作为额外参数
        );
        
        if (title) {
            console.log(`${i + 1}. ${title}`);
        }
    }

    // 6. 关闭浏览器
    await browser.close();
    console.log('\n爬虫执行完毕,浏览器已关闭');
})();
3. 实验结果
页面初始加载完成
点击【加载更多】按钮成功
已保存截图至当前目录:douban_movies_puppeteer.png

共检测到 20 部电影:
1. 奥本海默
2. 芭比
3. 蜘蛛侠:纵横宇宙
4. 长安三万里
5. 消失的她
6. 八角笼中
7. 疯狂元素城
8. 变形金刚:超能勇士崛起
9. 扫毒3:人在天涯
10. 银河护卫队3
11. 铃芽之旅
12. 速度与激情10
13. 蜘蛛侠:平行宇宙
14. 灌篮高手
15. 长空之王
16. 这么多年
17. 热烈
18. 忠犬八公
19. 惊天救援
20. 龙马精神

爬虫执行完毕,浏览器已关闭
4. 关键特性
  • 深度集成 Chrome:基于 Chrome DevTools 协议,可控制浏览器的所有细节(如网络请求拦截、性能分析);
  • 无头模式优化headless: "new" 模式(新版特性)比传统无头模式更高效,接近有头模式的渲染能力;
  • API 精准灵活:支持拦截网络请求(page.route )、注入 JavaScript(page.evaluate )、生成 PDF / 截图等,适合深度定制场景(如修改请求参数、绕过反爬)。

2.1.4 三者核心差异对比

维度 Selenium Playwright Puppeteer
语言支持 多语言(Python、Java、C#) 多语言(Python、Node.js 等) 仅 Node.js
浏览器支持 全浏览器(Chrome/Firefox/Edge) 全浏览器(含 WebKit) 仅 Chrome/Chromium
生态成熟度 最高(19 年历史,文档 / 插件多) 较高(微软维护,生态完善) 高(Node.js 生态深度集成)
学习曲线 较陡(需熟悉等待策略、驱动) 较平缓(API 简洁,自动等待) 平缓(Node.js 开发者友好)
性能 较低(启动 / 执行略慢) 高(现代架构,自动优化) 高(Chrome 深度优化)

2.1.5 适用场景选择

  • 跨语言 / 跨浏览器需求:选 Selenium ,多语言支持 + 全浏览器覆盖,适合企业级复杂场景;
  • 快速开发 / 现代前端爬取:选 Playwright ,自动等待、简洁 API ,对 React/Vue 动态渲染支持更好;
  • Node.js 生态 / 深度定制:选 Puppeteer ,Node.js 专属,可深度控制 Chrome ,适合前端工程师或 Node.js 项目;
  • 自动化测试优先:Selenium 是传统测试框架,Playwright 是新一代测试工具,后者更推荐(微软官方宣称 “替代 Selenium” )。

从动态页面爬取角度看,三者都能解决 “JavaScript 渲染” 问题,但 Playwright 和 Puppeteer 因更贴近现代浏览器架构,在效率和易用性上更具优势。若你是 Python 开发者,直接选 Playwright ;若用 Node.js ,则 Puppeteer 或 Playwright(Node.js 版) 更合适。

2.2 无头浏览器 + 渲染引擎(轻量化模拟)

无头浏览器(Headless Browser)是指没有图形用户界面(GUI)的浏览器,它能像普通浏览器一样解析 HTML、执行 JavaScript、处理 CSS,但无需显示页面窗口,资源占用更低、运行效率更高。搭配专门的渲染引擎(如 WebKit、Blink),可高效处理动态渲染页面,是大规模爬取的优选方案。

2.2.1 核心原理

无头浏览器 / 渲染引擎的工作流程与普通浏览器一致,但省略了界面渲染步骤:

  1. 加载页面:接收目标 URL,下载 HTML、CSS、JavaScript 等资源;
  2. 执行脚本:运行页面中的 JavaScript 代码(包括异步请求、DOM 操作);
  3. 渲染页面:将 JavaScript 动态生成的内容整合为完整 HTML;
  4. 返回结果:输出最终渲染后的 HTML 或数据,供爬虫提取。

由于无需加载图形界面,其启动速度和运行效率远超带界面的浏览器(如 Chrome 默认模式),且可在服务器环境(无显示器)中稳定运行。

2.2.2 代表工具及实战示例

2.2.2.1 Splash(Python 生态首选)

Splash 是基于 WebKit 引擎的轻量级渲染服务,专为爬虫设计,支持通过 HTTP API 控制页面渲染,可无缝集成到 Python 爬虫(如 Scrapy)中。

(1)安装与启动(依赖 Docker)
  • 安装 Docker(确保环境已配置 Docker);
  • 启动 Splash 服务:
    docker run -p 8050:8050 scrapinghub/splash
    

    启动后,Splash 服务运行在 http://localhost:8050,可通过浏览器访问该地址进入可视化界面。
(2)实战:用 Splash 爬取豆瓣电影动态页面
import requests
from bs4 import BeautifulSoup

# 1. 配置Splash服务和目标页面
splash_url = "http://localhost:8050/render.html"  # Splash的HTML渲染接口
target_url = "https://movie.douban.com/explore"   # 豆瓣电影动态页面

# 2. 定义Splash参数(控制渲染行为)
params = {
    "url": target_url,         # 目标页面URL
    "wait": 3,                 # 等待3秒(确保JavaScript执行完毕)
    "timeout": 10,             # 超时时间(10秒未响应则终止)
    "images": 0,               # 禁用图片加载(节省带宽和时间)
    "js_source": "window.scrollTo(0, document.body.scrollHeight);"  # 执行滚动操作(触发动态加载)
}

# 3. 向Splash发送请求,获取渲染后的HTML
response = requests.get(splash_url, params=params)
rendered_html = response.text  # 动态渲染后的完整HTML

# 4. 解析页面数据(提取电影标题)
soup = BeautifulSoup(rendered_html, "html.parser")
movie_titles = [
    title.text.strip() 
    for title in soup.select("span.title")  # 定位电影标题元素
    if title.text.strip()
]

print(f"爬取到的电影标题:\n{movie_titles[:10]}")  # 打印前10部电影
爬取到的电影标题:
['奥本海默', '芭比', '蜘蛛侠:纵横宇宙', '长安三万里', '消失的她', '八角笼中', '疯狂元素城', '变形金刚:超能勇士崛起', '扫毒3:人在天涯', '银河护卫队3']
(3)关键参数说明
  • wait:页面加载完成后等待的秒数(确保 JavaScript 异步请求完成);
  • images=0:禁用图片加载(非必要资源,可大幅提升速度);
  • js_source:自定义 JavaScript 代码(如模拟滚动、点击,触发动态加载);
  • proxy:配置代理 IP(应对反爬封锁,格式:http://user:pass@proxy:port)。
2.2.2.2 Headless Chrome(原生浏览器方案)

Chrome 浏览器自带无头模式(--headless=new),无需额外安装工具,可直接通过命令行或编程控制,适合需要接近真实浏览器环境的场景。

(1)基本使用(通过命令行测试)
# 用无头Chrome渲染页面并保存为文件
chrome --headless=new --dump-dom https://movie.douban.com/explore > douban_rendered.html
  • --headless=new:启用新无头模式(性能更优);
  • --dump-dom:输出渲染后的 DOM 结构。
(2)Python 实战(结合selenium控制)
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from bs4 import BeautifulSoup

# 1. 配置无头Chrome选项
chrome_options = Options()
chrome_options.add_argument("--headless=new")  # 启用无头模式
chrome_options.add_argument("--disable-gpu")   # 禁用GPU加速(无头模式无需)
chrome_options.add_argument("--no-sandbox")    # 解决服务器环境权限问题

# 2. 启动无头Chrome
driver = webdriver.Chrome(options=chrome_options)

# 3. 访问目标页面并等待动态加载
driver.get("https://movie.douban.com/explore")
driver.implicitly_wait(5)  # 全局等待5秒(等待JavaScript执行)

# 4. 提取渲染后的HTML
rendered_html = driver.page_source

# 5. 解析数据(同Splash示例)
soup = BeautifulSoup(rendered_html, "html.parser")
movie_titles = [title.text.strip() for title in soup.select("span.title") if title.text.strip()]
print(f"爬取到的电影标题:\n{movie_titles[:10]}")

# 6. 关闭浏览器
driver.quit()
爬取到的电影标题:
['奥本海默', '芭比', '蜘蛛侠:纵横宇宙', '长安三万里', '消失的她', '八角笼中', '疯狂元素城', '变形金刚:超能勇士崛起', '扫毒3:人在天涯', '银河护卫队3']

3、方案对比与选择建议

技术方案 核心优势 典型场景 缺点
浏览器自动化(Selenium/Playwright) 完全模拟浏览器行为,无需关心 JS 逻辑 页面交互复杂、反爬严格场景 效率低(启动浏览器耗时)、资源占用大
无头浏览器(Splash/Headless Chrome) 轻量化模拟,兼顾效率与渲染能力 大规模页面渲染、简单交互 对复杂 JS 交互(如滑块验证)支持弱
接口逆向(直接请求 API) 效率极高,适合批量数据爬取 动态数据由独立 API 提供 需逆向分析参数 / 加密,技术门槛高

选择建议

  • 如果是快速验证需求、页面交互极复杂(如需要登录后点击多个按钮才加载数据),优先用 Selenium/Playwright,直接模拟浏览器操作最省心;
  • 如果是大规模数据爬取、页面动态渲染逻辑简单(如仅滚动加载),可尝试 接口逆向,直接请求 API 效率最高;
  • 如果是服务器端批量渲染(如为 Scrapy 框架扩展动态渲染能力),Splash 这类无头浏览器方案更适合,能在服务端轻量化模拟渲染过程。

4、总结

动态渲染页面的爬取,本质是一场 “爬虫与前端技术迭代” 的博弈:

  • 从应对思路看,模拟浏览器执行(Selenium 等)是 “以笨胜巧”,用最接近用户的方式绕过动态渲染限制;接口逆向是 “直击本质”,找到数据源头实现高效爬取。
  • 从技术发展看,前端框架(React/Vue/Angular)会持续普及,动态渲染会更复杂(如结合 WebSocket 实时更新数据),反爬策略也会更隐蔽(如 JavaScript 混淆、浏览器指纹验证)。

对爬虫开发者而言,需持续提升两类能力:

  1. 浏览器模拟与调试能力:熟练使用 Selenium、Playwright 等工具,掌握浏览器开发者工具(Network、Sources 面板)分析页面加载流程;
  2. 前端逆向与加密破解能力:学会从 JavaScript 代码中逆向参数加密逻辑,用 Python 复现加密算法,突破接口请求限制。
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐