讲师中心 微信公众号

工具推荐

视频效率加速
剧云
剧云

中文短剧剧本制作平台

立刻MV
立刻MV

低成本歌曲 MV、视频生成

AniShort
AniShort

AI短剧协同制作平台

updream

一键生成高质量推广成片

JSDOM查询NodeList为空:动态内容抓取策略与Puppeteer实践

秋晨姑娘_7159

秋晨姑娘_7159

发布时间:2025-11-19 12:09:02

|

306人浏览过

|

来源于php中文网

原创

jsdom查询nodelist为空:动态内容抓取策略与puppeteer实践

在使用JSDOM和Axios进行网页抓取时,有时会遇到`querySelectorAll`返回空`NodeList`的问题,尤其当目标元素(如`

  • `)是网站动态加载时。这通常是因为JSDOM仅处理静态HTML,无法模拟浏览器执行JavaScript。本文将深入探讨此问题的原因,并提供使用Puppeteer这一无头浏览器工具的解决方案,以有效抓取动态渲染的网页内容,确保获取预期的DOM元素。

    网页抓取中NodeList为空的常见问题

    在使用axios获取网页HTML内容,并结合JSDOM解析DOM时,开发者可能会遇到一个令人困惑的现象:通过querySelector或querySelectorAll查询某个元素(例如ul下的li元素),尽管在浏览器开发者工具中这些元素清晰可见,但在代码中返回的NodeList却是空的,或者其length属性为0。

    例如,针对以下HTML结构:

    <div id="download-options">
        <div class="panel-body">
            <ul>
                <li><a href="url1"></a></li>
                <li><a href="url2"></a></li>
                <li><a href="url3"></a></li>
            </ul>
        </div>
    </div>

    尝试使用以下JSDOM代码抓取li元素:

    // 假设 res.data 包含了上述HTML
    const dom = new JSDOM(res.data);
    const ulist = dom.window.document.querySelector('#download-options > .panel-body > ul');
    // ulist 可能会正确返回 HTMLUListElement {}
    // ulist.childElementCount 可能会返回 1 (表示有一个子元素,即文本节点或注释)
    
    const lists = ulist.querySelectorAll('li');
    // 此时 lists.length 却返回 0,而非预期的 3

    这种情况下,ulist本身可能被正确选中,但其内部的li元素却无法通过querySelectorAll获取。

    问题根源:静态抓取与动态渲染

    这个问题的核心在于网页内容的加载方式。axios作为一个HTTP客户端,它只能获取服务器首次响应的原始HTML字符串。JSDOM则是一个纯JavaScript的DOM实现,它根据这个原始HTML字符串构建DOM树,但它不具备浏览器环境,无法执行页面中的JavaScript代码。

    阿拉丁·前端工程工坊|脚手架·组件·规范落地·构建优化·性能与可访问性一体
    阿拉丁·前端工程工坊|脚手架·组件·规范落地·构建优化·性能与可访问性一体

    阿拉丁·前端工程工坊把「前端只会写页面、规范停在文档里、脚手架手敲、构建靠抄、性能靠猜、可访问性靠忘」从「手动搭项目、抄配置、肉眼查规范」升级成一条本地工具链——多框架脚手架生成(React/Vue3/Svelte + Vite)、可复用组件生成(Props 类型+样式+示例)、规范落地检查(lint-lite:命名/未用变量/console残留/TS any/目录结构)、构建配置生成与产物体积预算、性能审计(依赖体积/重复/懒加载/Lighthouse 清单)、可访问性(a11y)校验(alt/aria

    下载

    许多现代网站会利用JavaScript在页面加载完成后动态地生成、修改或插入DOM元素。这些动态内容可能包括:

    • 通过AJAX请求获取数据后渲染列表项。
    • 基于用户行为或设备状态调整页面布局。
    • 通过前端框架(如React, Vue, Angular)进行客户端渲染。
    • 网站可能出于反爬虫目的,延迟加载关键内容,或依赖于特定的Cookie、Session或用户代理来显示完整内容。

    当axios获取到的是一个“骨架屏”HTML,而li元素是由后续JavaScript代码动态填充时,JSDOM处理的DOM树自然就不会包含这些动态生成的li元素,从而导致querySelectorAll返回空结果。在浏览器开发者工具中能看到这些元素,是因为浏览器完整执行了所有JavaScript,渲染出了最终的DOM。

    解决方案:使用Puppeteer处理动态内容

    为了解决JSDOM无法处理动态内容的问题,我们需要一个能够模拟真实浏览器环境的工具。Puppeteer是一个由Google开发的Node.js库,它提供了一套高级API来通过DevTools协议控制Chrome或Chromium浏览器。这意味着Puppeteer能够:

    1. 加载网页并执行所有JavaScript。
    2. 等待异步内容加载完成。
    3. 模拟用户交互(点击、输入等)。
    4. 截取屏幕截图或生成PDF。
    5. 获取最终渲染的DOM内容。

    Puppeteer实践示例

    以下代码展示了如何使用Puppeteer来抓取动态加载的li元素:

    const puppeteer = require('puppeteer');
    
    (async () => {
      // 1. 启动无头浏览器实例
      // headless: true 表示在后台运行浏览器,不显示UI界面
      const browser = await puppeteer.launch({ headless: true });
      const page = await browser.newPage();
    
      // 2. 访问网站首页 (可选,但可能解决某些网站的缓存/Cookie问题)
      // 某些网站会根据首次访问设置Cookie或Session,影响后续页面的内容
      await page.goto('http://example.com', { waitUntil: 'domcontentloaded' }); // 等待DOM加载完成
    
      // 3. 访问目标页面
      await page.goto('https://example.com/targetpage', { waitUntil: 'networkidle2' }); 
      // waitUntil: 'networkidle2' 会等待网络连接空闲2秒,通常意味着页面所有资源已加载完毕
      // 也可以使用 'domcontentloaded' 或 'load',具体取决于页面加载特性
    
      // 4. 等待目标元素出现
      // 这一步至关重要,确保动态加载的元素已经渲染到DOM中
      await page.waitForSelector('#download-options li', { timeout: 5000 }); // 最多等待5秒
    
      // 5. 查询元素并提取数据
      // page.$ 用于查询单个元素
      const ul = await page.$("#download-options ul"); 
    
      // page.$$ 用于查询多个元素
      const lis = await ul.$$("li");
    
      console.log(`找到 ${lis.length} 个 li 元素。`);
    
      // 6. 遍历并提取每个 li 内部的 a 标签的 href 属性
      for await (const li of lis) {
        const a = await li.$('a'); // 在每个 li 元素内部查询 a 标签
        if (a) {
          // 使用 evaluate 方法在浏览器环境中执行JS代码来获取属性值
          const hrefValue = await a.evaluate((el) => el.getAttribute('href'));
          console.log(`链接地址: ${hrefValue}`);
        }
      }
    
      // 7. 关闭浏览器实例
      await browser.close();
    })();

    代码解析与注意事项

    1. puppeteer.launch({ headless: true }): 启动一个Chromium实例。headless: true表示无头模式,浏览器在后台运行,没有图形界面。在开发调试阶段,可以设置为false来观察浏览器行为。
    2. page.goto(url, { waitUntil: 'networkidle2' }): 导航到指定URL。waitUntil参数非常重要,它决定了Puppeteer何时认为页面加载完成。
      • domcontentloaded: DOMContentLoaded事件触发时。
      • load: load事件触发时。
      • networkidle0: 当网络连接数变为0后持续至少500ms。
      • networkidle2: 当网络连接数变为2后持续至少500ms。 选择合适的waitUntil策略对于确保所有动态内容加载至关重要。networkidle2通常是一个比较稳妥的选择。
    3. page.waitForSelector('#download-options li', { timeout: 5000 }): 这是解决动态内容问题的关键。它会暂停代码执行,直到指定的CSS选择器对应的元素出现在DOM中。如果元素在timeout时间内未出现,则会抛出错误。这确保了在尝试查询元素之前,它们已经被JavaScript渲染到页面上。
    4. page.$ 和 page.$$:
      • page.$(selector): 类似于document.querySelector(),返回匹配的第一个ElementHandle对象。
      • page.$$(selector): 类似于document.querySelectorAll(),返回所有匹配的ElementHandle对象数组。 ElementHandle是Puppeteer对DOM元素的引用,它允许你在其上执行进一步的操作,如查询子元素或调用evaluate。
    5. element.evaluate((el) => el.getAttribute('href')): evaluate方法允许你在浏览器上下文(即页面内部)执行一段JavaScript代码。这对于获取元素的属性、文本内容或执行更复杂的DOM操作非常有用,因为这些操作是在真实的浏览器环境中进行的。
    6. 资源管理: 务必在抓取完成后调用browser.close()来关闭浏览器实例,释放系统资源。

    总结

    在进行网页抓取时,理解目标网站的内容加载机制至关重要。对于静态HTML内容,axios结合JSDOM是一个轻量且高效的选择。然而,一旦遇到由JavaScript动态渲染的内容,JSDOM就力不从心了。此时,Puppeteer作为无头浏览器自动化工具,能够完美模拟真实用户的浏览行为,执行页面JavaScript,并等待动态内容加载完成,从而成功抓取到完整的DOM结构和数据。正确选择工具并熟练运用page.waitForSelector等等待机制,是成功抓取动态网页内容的关键。

  • 热门AI工具

    更多
    PixTV
    PixTV Hot

    PixTV是一款面向AIGC内容创作的AI视频生成工具。

    豆包大模型

    豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

    DeepSeek

    DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

    Loomy
    Loomy Hot

    一款AI工具,主要用于科大讯飞发布的桌面级 AI 助理,比 OpenClaw 更易用、更安全!,适合需要提升相关任务效率的用户。

    火山引擎

    火山引擎是一款面向企业的云计算与AI服务平台。

    PixPix
    PixPix Hot

    PixPix是一款面向电商视觉生产的AI商品图生成工具。

    WorkBuddy

    一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

    UpDream
    UpDream Hot

    一款AI视频创作工具,主要用于哔哩哔哩推出的自研AI视频创作工具,适合需要提升相关任务效率的用户。

    Lovart
    Lovart Hot

    一款面向视觉设计创作的AI设计平台,可通过智能体和画布工作流辅助制作海报、Logo、网页、PPT及其他视觉内容。

    相关专题

    更多
    ajax教程
    ajax教程

    php中文网为大家带来ajax教程合集,Ajax是一种用于创建快速动态网页的技术。通过在后台与服务器进行少量数据交换,Ajax可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。php中文网还为大家带来ajax的相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

    3520

    2023.06.14

    ajax中文乱码解决方法
    ajax中文乱码解决方法

    ajax中文乱码解决方法有设置请求头部的字符编码、在服务器端设置响应头部的字符编码和使用encodeURIComponent对中文进行编码。本专题为大家提供ajax中文乱码相关的文章、下载、课程内容,供大家免费下载体验。

    360

    2023.08.31

    ajax传递中文乱码怎么办
    ajax传递中文乱码怎么办

    ajax传递中文乱码的解决办法:1、设置统一的编码方式;2、服务器端编码;3、客户端解码;4、设置HTTP响应头;5、使用JSON格式。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

    3333

    2023.11.15

    ajax网站有哪些
    ajax网站有哪些

    使用ajax的网站有谷歌、维基百科、脸书、纽约时报、亚马逊、stackoverflow、twitter、hacker news、shopify和basecamp等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

    1181

    2024.09.24

    chrome什么意思
    chrome什么意思

    chrome是浏览器的意思,由Google开发的网络浏览器,它在2008年首次发布,并迅速成为全球最受欢迎的浏览器之一。本专题为大家提供chrome相关的文章、下载、课程内容,供大家免费下载体验。

    3006

    2023.08.11

    chrome无法加载插件怎么办
    chrome无法加载插件怎么办

    chrome无法加载插件可以通过检查插件是否已正确安装、禁用和启用插件、清除插件缓存、更新浏览器和插件、检查网络连接和尝试在隐身模式下加载插件方法解决。更多关于chrome相关问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

    6279

    2023.11.06

    Chrome开启无痕模式
    Chrome开启无痕模式

    本专题整合了Chrome无痕模式开启相关内容,阅读专题下面的文章了解更多详细教程。

    4487

    2026.03.24

    cookie
    cookie

    Cookie 是一种在用户计算机上存储小型文本文件的技术,用于在用户与网站进行交互时收集和存储有关用户的信息。当用户访问一个网站时,网站会将一个包含特定信息的 Cookie 文件发送到用户的浏览器,浏览器会将该 Cookie 存储在用户的计算机上。之后,当用户再次访问该网站时,浏览器会向服务器发送 Cookie,服务器可以根据 Cookie 中的信息来识别用户、跟踪用户行为等。

    12979

    2023.06.30

    Go-Zero API开发使用教程
    Go-Zero API开发使用教程

    本专题聚焦Go-Zero的API开发,拆解.api描述文件的语法结构、路由与分组定义、参数绑定与校验规则,说明统一响应体、JWT鉴权、跨域与接口文档生成的落地方式,并给出网关聚合与接口测试的实践建议。

    100

    2026.11.12

    热门下载

    更多
    网站特效
    /
    网站源码
    /
    网站素材
    /
    前端模板

    精品课程

    更多
    相关推荐
    /
    热门推荐
    /
    最新课程
    关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
    php中文网:公益在线php培训,帮助PHP学习者快速成长!
    关注服务号
    PHP中文网订阅号
    每天精选资源文章推送

    Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn