使用 Puppeteer 抓取网页数据返回空数组的解决方案

使用 puppeteer 抓取网页数据返回空数组的解决方案

本文旨在解决在使用 Puppeteer 抓取网页数据时,遇到返回空数组的问题。通过分析问题代码,找到导致问题的原因,并提供修正后的代码示例,确保能正确抓取目标网站的数据,并清晰地呈现抓取结果。本文重点关注选择器的使用和异步操作的处理,帮助开发者避免类似问题。

在使用 Puppeteer 进行网页数据抓取时,返回空数组是一个常见的问题。通常,这与选择器错误、异步操作未正确处理或目标元素未加载有关。下面将分析一个实际案例,并提供解决方案。

问题分析

原始代码尝试从 https://naamhinaam.com/baby-girl-names-a 网站抓取婴儿名字和含义。代码存在以下潜在问题:

复杂的选择器: 使用了非常具体的 CSS 选择器 div.name-suggestion.mt-1 > div > div:nth-child(${i}) > div.nsg__name_meaning > a,这可能不够稳定,容易受到网站结构变化的影响。不必要的元素移除: 移除广告元素的代码可能会影响后续元素的选择,导致索引错误。重复的条件判断: if (await page.$(“div.name-suggestion.mt-1 > div > div:nth-child(22)”)) 出现了两次,意义不大。异步操作处理: 虽然使用了 await page.waitForTimeout(3000),但可能仍然不足以确保所有元素都已加载完成。循环中的异步操作: 在循环中使用 await page.$ 和 await page.evaluate,可能导致性能问题,并且增加了出错的可能性。

解决方案

以下是修正后的代码,它解决了上述问题:

怪兽AI数字人 怪兽AI数字人

数字人短视频创作,数字人直播,实时驱动数字人

怪兽AI数字人 44 查看详情 怪兽AI数字人

const puppeteer = require("puppeteer");const express = require("express");const cors = require("cors");const app = express();app.use(cors());let data = [];(async () => {  const browser = await puppeteer.launch({    headless: true, // 建议设置为 true,提高效率    defaultViewport: null,  });  const page = await browser.newPage();  for (let pageNumber = 1; pageNumber  i`);    // 循环遍历抓取数据    for (let i = 0; i  el.textContent, nameElements[i]);      let meaning = await page.evaluate(el => el.textContent, meaningElements[i]);      fullName = `${name.split(/[nt]/).join('').trim()}, ${meaning}`;      data.push({ fullName });    }  }  console.log(data);  await browser.close();})();app.get("/", (req, res) => {  res.status(200).json(data);});app.listen(3000, () => {  console.log("App is running...");});

代码解释:

简化选择器: 使用 a.nsg__name 和 div.nsg__meaning > i 作为选择器,更加简洁和稳定。移除不必要的代码: 移除了点击弹窗和移除广告元素的代码,因为它们与数据抓取没有直接关系。使用 page.$$ 获取所有元素: 使用 page.$$ 一次性获取所有名字和含义的元素,避免了在循环中多次进行 DOM 查询。清晰的数据提取: 使用 page.evaluate 提取每个元素的文本内容,并将名字和含义组合成 fullName。Headless 模式: 将 headless 设置为 true,可以在后台运行浏览器,提高效率。

注意事项:

网站结构变化: 网页结构可能会发生变化,导致选择器失效。需要定期检查和更新选择器。反爬机制: 网站可能会采取反爬机制,例如验证码、IP 封锁等。需要采取相应的措施来应对,例如使用代理 IP、设置 User-Agent 等。遵守 Robots.txt: 抓取网页数据时,务必遵守网站的 robots.txt 协议,避免抓取不允许抓取的页面。请求频率控制: 控制请求频率,避免对网站服务器造成过大的压力。

总结

通过简化选择器、移除不必要的代码、使用 page.$$ 获取所有元素以及清晰的数据提取,可以有效地解决 Puppeteer 抓取网页数据返回空数组的问题。同时,需要注意网站结构变化、反爬机制以及遵守 robots.txt 协议。通过不断学习和实践,可以更好地掌握 Puppeteer 的使用技巧,并高效地抓取所需的网页数据.

以上就是使用 Puppeteer 抓取网页数据返回空数组的解决方案的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/212703.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年11月3日 13:28:53
下一篇 2025年11月3日 13:29:39

相关推荐

  • FastAPI启动事件中AsyncGenerator依赖注入的正确实践

    本文探讨了在FastAPI应用的startup事件中直接使用Depends()与AsyncGenerator进行资源(如Redis连接)初始化时遇到的问题,并指出Depends()不适用于此场景。核心内容是提供并详细解释了如何通过FastAPI的lifespan上下文管理器来正确、优雅地管理异步生成…

    2025年12月14日
    000
  • 深入理解Python Enum 类的动态创建与命名机制

    本文详细探讨了Python中Enum类的动态创建方法,特别是通过Enum()工厂函数。我们将澄清Enum()仅创建类而非实例的常见误解,并深入解析其字符串参数的作用——定义Enum类的内部名称。文章还将通过代码示例,阐述如何正确地动态生成和使用Enum类,并将其与Python中类创建和变量赋值的基本…

    2025年12月14日
    000
  • 深入理解Python中Enum类的动态创建与命名机制

    本文旨在深入探讨Python中Enum类的动态创建方法及其命名机制。我们将澄清关于Enum工厂函数Enum(‘Name’, members)的常见误解,解释其仅用于创建Enum类而非实例,并阐明字符串参数在定义类内部名称中的作用。通过与type()函数和普通类赋值的对比,帮助…

    2025年12月14日
    000
  • Python中Enum类的动态生成与命名实践指南

    本文深入探讨Python中动态创建Enum类的方法及其核心机制。我们将澄清关于Enum()函数是否同时创建类和实例的常见误解,详细解释其字符串参数在命名类中的作用,并提供示例代码,帮助开发者更好地理解和运用动态Enum类。 动态创建Python Enum类 在python中,当我们需要根据运行时配置…

    2025年12月14日
    000
  • Python Selenium操作Cookie的方法

    Selenium中操作Cookie可实现免登录和会话维持。先访问目标域名,再用get_cookies()获取所有Cookie,get_cookie(name)获取指定Cookie,add_cookie(cookie_dict)添加Cookie,delete_cookie(name)删除指定Cooki…

    2025年12月14日
    000
  • Python 动态枚举 (Enum) 类的创建与命名机制解析

    本文旨在深入解析 Python 中动态创建 Enum 类的方法及其核心机制。我们将探讨如何利用 Enum 函数动态定义枚举类,澄清关于类与实例创建的常见误解,并阐释 Enum 函数中字符串参数的真正作用。此外,文章还将介绍 type() 函数在动态类创建中的应用,帮助读者全面理解 Python 类的…

    2025年12月14日
    000
  • 生成二值特征矩阵:使用Pandas crosstab与reindex的高效方法

    本教程旨在详细阐述如何将具有事务性记录(如用户-特征对)的原始数据转换为一个二值化的特征矩阵。我们将重点介绍如何利用Pandas库中的crosstab函数进行数据透视,并结合reindex方法确保所有指定用户都包含在输出中,同时为未使用的特征填充零值,从而高效、清晰地构建用户-特征关联矩阵。 1. …

    2025年12月14日
    000
  • 生成音频正弦波形:从频率与时长到可视化教程

    本教程旨在详细阐述如何根据给定的音频频率和录音时长生成并可视化正弦波形。文章将介绍两种核心方法:一是直接利用正弦函数公式构建信号,二是利用傅里叶逆变换从频域频谱重构信号。我们将提供Python代码示例,并探讨采样率、信号叠加、可视化工具选择及动画生成等关键考量,帮助读者理解和实践音频信号的基本合成与…

    2025年12月14日
    000
  • 音频正弦波生成与可视化:从频率到波形重构

    本教程详细阐述了两种基于音频频率和时长信息生成正弦波形图的方法。第一种是直接合成法,通过叠加单个正弦波来构建复杂波形;第二种是逆傅里叶变换法,利用频域谱数据重构时域信号。文章提供了Python示例代码,并讨论了采样率、相位信息等关键注意事项,旨在帮助用户将频域分析结果转化为直观的音频波形可视化。 引…

    2025年12月14日
    000
  • 使用 PostgreSQL 和 SQLAlchemy 查询嵌套 JSONB 字段

    本文档详细介绍了如何使用 PostgreSQL、SQLAlchemy 和 Python 查询包含深度嵌套对象的 JSONB 列。我们将探讨如何构建正确的 JSONPath 查询,以递归搜索 JSONB 对象,并提取具有特定键的对象。本文档提供了一个实用的解决方案,避免了常见的语法错误,并展示了如何有…

    2025年12月14日
    000
  • 使用 PostgreSQL 和 SQLAlchemy 查询嵌套 JSONB 列

    本文介绍了如何在 PostgreSQL 数据库中,使用 SQLAlchemy 和 Python 查询包含深度嵌套对象的 JSONB 列。我们将探讨如何使用 jsonb_path_query 函数以及 JSONPath 表达式来高效地检索所需数据,并解决常见的语法错误。通过本文,你将掌握一种更灵活、强…

    2025年12月14日
    000
  • 扩展 Django User 模型:添加自定义字段

    本文介绍如何在 Django 中扩展默认的 User 模型,无需使用一对一关联,直接添加自定义的布尔字段和选择字段。通过创建自定义 User 模型并配置 AUTH_USER_MODEL,可以轻松地在用户注册和管理界面中集成新的字段,并进行数据库迁移,从而满足特定业务需求。 扩展 Django Use…

    2025年12月14日
    000
  • python线程阻塞的解决

    使用多线程或异步编程可避免Python中因I/O、锁竞争等导致的线程阻塞。通过threading模块将耗时任务放入子线程,结合队列实现安全通信;对I/O密集型任务采用asyncio异步编程更高效。示例:创建子线程执行long_task,主线程继续运行。设置超时机制,如网络请求timeout、锁acq…

    2025年12月14日
    000
  • 使用 Python Socket 模块实现跨设备通信

    本文档旨在解决 Python Socket 编程中,服务器端绑定本地环回地址(127.0.0.1)导致客户端无法通过公网 IP 连接的问题。通过修改服务器端绑定的 IP 地址为机器的本地 IP 地址,并确保客户端连接服务器的公网 IP 地址,实现跨设备通信。同时,需要注意防火墙设置和端口转发配置,以…

    2025年12月14日
    000
  • 扩展 Django User 模型:自定义字段添加及管理

    本文介绍了如何在 Django 中扩展默认的 User 模型,通过创建自定义用户模型并添加额外的布尔字段和选择字段,无需使用一对一字段关联到其他模型。同时,本文还阐述了如何将自定义字段集成到 Django Admin 后台进行管理,提供完整的代码示例和操作步骤,帮助开发者更好地定制用户模型。 自定义…

    2025年12月14日
    000
  • 使用 SQLAlchemy 和 PostgreSQL 过滤 JSON 类型字段

    摘要:本文档介绍了如何使用 SQLAlchemy 和 PostgreSQL 过滤 JSON 类型字段中的数据。我们将探讨如何使用 cast() 函数将 JSON 类型转换为 JSONB 类型,并利用 has_any() 方法来高效地筛选出包含特定数组元素的记录。此外,还讨论了 JSONPath 的使…

    2025年12月14日
    000
  • 深入理解配置合并:从多个配置文件中选择性提取配置项

    本文旨在解决在配置管理中,如何从多个独立的配置文件中选择性地提取特定配置项进行合并的问题。通过引入命名默认值(Named Defaults)和值插值(Value Interpolation)机制,我们将演示一种灵活且强大的方法,允许用户精确控制配置的组合方式,从而实现模块化和可复用的配置管理。 1.…

    2025年12月14日
    000
  • Django 后端权限管理与前端视图控制:基于 Group 的最佳实践

    在构建 Django 后端与 Vue 前端应用时,如何高效地将用户权限信息同步至前端以实现视图控制是一个常见挑战。本文将探讨不同的权限数据传输策略,并强烈推荐利用 Django 内置的 Group 系统来管理和暴露用户权限,以实现灵活、可扩展且易于维护的权限控制方案,避免自定义角色字段或混合使用带来…

    2025年12月14日
    000
  • Langchain LCEL 链式调用:激活详细输出与调试指南

    本教程详细介绍了在Langchain使用LCEL构建链式调用时,如何获取并配置详细的中间步骤输出。通过引入回调处理器(如ConsoleCallbackHandler),用户可以观察链的内部执行流程,从而有效进行调试。文章还探讨了全局调试模式以及针对特定组件的配置方法,并提及了可视化调试工具。 在使用…

    2025年12月14日
    000
  • 解决PyTorch深度学习模型验证阶段CUDA内存不足(OOM)错误

    本教程旨在深入探讨PyTorch深度学习模型在验证阶段出现“CUDA out of memory”错误的常见原因及解决方案。重点关注训练阶段正常而验证阶段报错的特殊情况,提供包括GPU内存监控、显存缓存清理、数据加载优化及代码调整等一系列实用策略,帮助开发者有效诊断并解决显存溢出问题,确保模型顺利完…

    2025年12月14日
    000

发表回复

登录后才能评论
关注微信