0

0

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

花韻仙語

花韻仙語

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

|

286人浏览过

|

来源于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代码。

    Nanonets
    Nanonets

    基于AI的自学习OCR文档处理,自动捕获文档数据

    下载

    许多现代网站会利用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工具

    更多
    DeepSeek
    DeepSeek

    幻方量化公司旗下的开源大模型平台

    豆包大模型
    豆包大模型

    字节跳动自主研发的一系列大型语言模型

    WorkBuddy
    WorkBuddy

    腾讯云推出的AI原生桌面智能体工作台

    腾讯元宝
    腾讯元宝

    腾讯混元平台推出的AI助手

    文心一言
    文心一言

    文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

    讯飞写作
    讯飞写作

    基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

    即梦AI
    即梦AI

    一站式AI创作平台,免费AI图片和视频生成。

    ChatGPT
    ChatGPT

    最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

    相关专题

    更多
    ajax教程
    ajax教程

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

    166

    2023.06.14

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

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

    170

    2023.08.31

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

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

    124

    2023.11.15

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

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

    258

    2024.09.24

    chrome什么意思
    chrome什么意思

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

    1059

    2023.08.11

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

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

    840

    2023.11.06

    cookie
    cookie

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

    6500

    2023.06.30

    document.cookie获取不到怎么解决
    document.cookie获取不到怎么解决

    document.cookie获取不到的解决办法:1、浏览器的隐私设置;2、Same-origin policy;3、HTTPOnly Cookie;4、JavaScript代码错误;5、Cookie不存在或过期等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

    368

    2023.11.23

    Python异步编程与Asyncio高并发应用实践
    Python异步编程与Asyncio高并发应用实践

    本专题围绕 Python 异步编程模型展开,深入讲解 Asyncio 框架的核心原理与应用实践。内容包括事件循环机制、协程任务调度、异步 IO 处理以及并发任务管理策略。通过构建高并发网络请求与异步数据处理案例,帮助开发者掌握 Python 在高并发场景中的高效开发方法,并提升系统资源利用率与整体运行性能。

    37

    2026.03.12

    热门下载

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

    精品课程

    更多
    相关推荐
    /
    热门推荐
    /
    最新课程
    Sass 教程
    Sass 教程

    共14课时 | 0.9万人学习

    Bootstrap 5教程
    Bootstrap 5教程

    共46课时 | 3.6万人学习

    CSS教程
    CSS教程

    共754课时 | 42.7万人学习

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

    Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号