如何获取单页应用(SPA)中动态渲染完成的HTML内容
如何获取SPA(如LeetCode)完全渲染后的HTML
你说得太对了——fetch本身确实只能拿到服务器返回的初始静态HTML,完全处理不了浏览器端JavaScript动态渲染的内容,而LeetCode刚好是用React构建的单页应用(SPA),大部分核心内容都是客户端JS跑起来之后才生成的。要拿到#app里填充好的完整内容,你有两个主要方向可选:
1. 用无头浏览器模拟完整渲染流程(最直接)
既然fetch没有浏览器的JS执行能力,那我们就直接用工具模拟一个真实浏览器环境,让页面完整加载、执行所有JS后再抓取HTML。最常用的两个工具是:
Puppeteer(Chrome官方无头浏览器)
它能完全模拟Chrome的行为,等待页面渲染完成后再获取完整DOM。示例代码如下:
const puppeteer = require('puppeteer'); async function fetchRenderedLeetCodeHTML() { // 启动无头浏览器 const browser = await puppeteer.launch({ headless: 'new' }); const page = await browser.newPage(); // 加载页面,等待网络空闲(确保动态内容渲染完成) await page.goto('https://leetcode.com', { waitUntil: 'networkidle2' }); // 获取完全渲染后的完整HTML const fullRenderedHTML = await page.content(); await browser.close(); return fullRenderedHTML; } // 调用函数并处理结果 fetchRenderedLeetCodeHTML().then(html => { console.log(html); // 这里的HTML会包含#app里的所有动态内容 });
注:waitUntil: 'networkidle2'表示等待页面加载后,只有2个以内的网络请求活跃时再继续,能有效确保大部分动态内容都渲染完毕。
Playwright(多浏览器支持)
和Puppeteer类似,但支持Chrome、Firefox、Safari等多种浏览器,API设计更现代化,用法也大同小异,适合需要跨浏览器兼容的场景。
2. 直接调用LeetCode的API(更高效)
如果你只是想爬取具体数据(比如题目列表、用户提交记录等),其实完全没必要渲染整个页面——LeetCode的所有动态内容都是通过后端API获取的。你可以:
- 打开浏览器的开发者工具(F12),切换到Network面板
- 刷新页面或操作你要爬取的内容,观察XHR/fetch请求
- 找到对应的API接口(比如题目列表接口、题目详情接口),直接用
fetch或其他HTTP工具调用这些接口,拿到结构化的JSON数据
这种方式不仅效率更高,还能避免渲染页面带来的性能开销,也更不容易触发反爬机制。
再明确下为什么fetch不行
简单来说:
fetch只是发送HTTP请求,拿到的是服务器返回的初始静态HTML(也就是你在浏览器里右键“查看页面源代码”看到的内容),这时候#app确实是空的,因为React还没在客户端执行渲染。- 浏览器的“检查元素”看到的是DOM树,是JS执行后动态生成的内容,
fetch没有浏览器的渲染引擎和JS执行环境,根本触达不了这个阶段。
内容的提问来源于stack exchange,提问作者Louie Holbrook




