”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 用 puppeteer 抓取网络!

用 puppeteer 抓取网络!

发布于2024-11-06
浏览:802

Scrape the web with puppeteer!

木偶师完整指南 pt.1

Puppeteer:Web 自动化的强大工具

在当今快节奏的 Web 开发环境中,自动化是关键,这就是 Puppeteer 的用武之地。Puppeteer 由 Google 开发,是一个功能强大的 Node.js 库,允许开发人员使用 JavaScript 控制 Chrome 浏览器。无论您是在无头模式下浏览网络以提高效率,还是在完整的浏览器中获得视觉反馈,Puppeteer 都可以让您比以往更轻松地自动执行网页抓取、测试等任务。有了 Puppeteer,曾经需要手动完成的工作现在只需一个脚本即可完成。

为什么要进行网页抓取?

在最近的一个项目中,我与一位客户合作,他的外汇交易社区需要一个登陆页面。他想要类似于您在 MarketWatch 或雅虎财经上看到的股票行情的东西,但他想要的不是股票,而是在网站上显示 1 美元的实时货币兑换率。

虽然有可用的 API 可以提供数据(具有使用限制和月费),但我看到了使用 Puppeteer 创建自定义解决方案的机会。通过预先投入一些时间,我能够免费抓取和显示数据,最终为我的客户节省了经常性成本。

客户网站:Majesticpips.com

设置 puppeteer 变得简单

在我们开始抓取网络以实现其所有荣耀之前,我们必须将 puppeteer 安装到我们的应用程序中。

正如文档中所述

步骤1

使用您选择的 npm、yarn 或 pnpm 安装库。

  • npm 我木偶师

  • 纱线添加傀儡师

  • pnpm 添加木偶操纵者

这将在安装过程中下载 Chrome 的兼容版本,这对于初学者来说更容易快速启动和运行。

如果您是一位经验丰富的开发人员并且有您想要使用的特定 chrome/chromium 版本;然后安装这些软件包

  • npm i puppeteer-core

  • 纱线添加 puppeteer-core

  • pnpm 添加 puppeteer-core

最适合您,该软件包将是轻量级的,因为它只安装 puppeteer,而 chrome 版本则由您决定。

安装“puppeteer”对于初次测试者来说是更好的选择。它简化了设置并确保您拥有 Chromium 的工作版本,使您能够专注于编写脚本。

步骤2

现在在您的 JS 文件中,您需要为使用 ES 模块系统(ES6 标准)且节点版本为 12 及更高版本的应用程序导入 puppeteer。

从 'puppeteer' 导入 puppeteer; (受到推崇的)
或者
从 'puppeteer-core' 导入 puppeteer;

或者您可以使用 Node.js 的 commonJs 模块系统的 require 语法,该语法也与旧版本的 Node.js 兼容。

const puppeteer = require('puppeteer');
或者
const puppeteer = require('puppeteer-core');

步骤3

导入Puppeteer后,我们就可以开始编写执行网页抓取的命令了。下面的代码显示了您需要使用的内容。

我们使用库提供的这些方法启动浏览器。

const browser = await puppeteer.launch();

const page = await browser.newPage();

await browser.close();

puppeteer.launch() = 此方法启动一个新的浏览器实例。

browser.newPage() = 此方法在浏览器实例中创建一个新页面(或选项卡)。

browser.close() = 此方法关闭浏览器实例。

在 puppeteer.launch() 中,我们可以传递参数来根据我们的喜好自定义浏览器启动。我们将在第 2 部分中更详细地介绍这一点。但是,默认情况下,puppeteer.launch() 具有预设值,例如将无头模式设置为 true。

步骤4

浏览器已经启动,现在我们有了一个可以上网的页面。让我们导航到我们将抓取一些数据的网站。

在此示例中,我们将从 qoutes 网站抓取数据。

 await page.goto(https://quotes.toscrape.com/)

 await page.screenshot({ path: 'screenshot.png' })

我添加了await page.screenshot({path:'screenshot.png'})。这是一个很好的工具,可以确保一切按计划进行。执行此代码时,您的项目目录中将有一个图像文件,用于捕获您正在抓取的网站的当前状态。您还可以根据自己的喜好调整文件名。

如果一切正常,则继续执行步骤 5。

步骤5

现在我们的脚本已经成型,让我们深入研究从网页提取数据的关键部分。这是我们的脚本到目前为止的样子:

const puppeteer = require('puppeteer');

(async () => {

const browser = await puppeteer.launch();

const page = await browser.newPage();

await page.goto(https://quotes.toscrape.com/)

await page.screenshot({ path: 'screenshot.png' })

 const quotesScraper = await page.evaluate(() => {

const quotes = document.querySelectorAll(".quote"); 
    const quotesArray = [];

   for (const quote of quotes) { 
       const texts = quote.querySelector(".text").innerText; 
         const author = quote.querySelector(".author").innerText;  

        quotesArray.push({
           quote: texts,
           author
         });

     }
     return quotesArray;
});

console.log(quotesScraper);

await browser.close();

})();

要验证数据是否已成功抓取,我们可以在 CLI 中运行节点“server-file-name”,数据将使用 console.log(quotesScraper);.
显示在控制台中

[
  {
    quote: '“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”',
    author: 'Albert Einstein'
  },
  {
    quote: '“It is our choices, Harry, that show what we truly are, far more than our abilities.”',
    author: 'J.K. Rowling'
  },
  {
    quote: '“There are only two ways to live your life. One is as though nothing is a miracle. The other is as though everything is a miracle.”',
    author: 'Albert Einstein'
  },
  {
    quote: '“The person, be it gentleman or lady, who has not pleasure in a good novel, must be intolerably stupid.”',
    author: 'Jane Austen'
  },
  {
    quote: "“Imperfection is beauty, madness is genius and it's better to be absolutely ridiculous than absolutely boring.”",
    author: 'Marilyn Monroe'
  }
....
]

await page.evaluate(() => { ... }):这就是奇迹发生的地方。 evaluate 方法允许我们在正在抓取的页面上下文中运行 JavaScript 代码。这就好像您打开浏览器的开发者控制台并直接在页面上运行代码。

const quote = document.querySelectorAll(".quote");:在这里,我们选择页面上与 .quote 类匹配的所有元素。这给了我们一个引用元素的 NodeList。

constquotesArray = [];:我们初始化一个空数组来存储我们提取的引号。

for (const quote of quote) { ... }:此循环迭代每个引号元素。对于每一个,我们都会提取引用文本和作者。

quotesArray.push({ quote: texts,author });:对于每个引用,我们创建一个包含引用文本和作者的对象,然后将该对象推入quotesArray。

returnquotesArray;:最后,我们返回引号数组,然后将其存储在 Node.js 环境中的quotesScraper中。

这种提取数据的方法非常强大,因为它允许您像用户一样与页面交互,但是以自动化和编程的方式。

关闭浏览器

await browser.close();:抓取数据后,关闭浏览器以释放资源非常重要。此行确保我们启动的浏览器实例正确关闭。

展望第二部分

通过此脚本,您已成功使用 Puppeteer 从网站抓取数据。但我们只是触及了可能性的表面。在第 2 部分中,我们将探索更高级的技术,例如处理动态内容并使用 Express.JS 创建报废数据的 API 功能。 请继续关注,我们将深入探索 Puppeteer 的世界!

版本声明 本文转载于:https://dev.to/cedsengine/scrape-the-web-with-puppeteer-2hmh?1如有侵犯,请联系[email protected]删除
最新教程 更多>
  • Android如何向PHP服务器发送POST数据?
    Android如何向PHP服务器发送POST数据?
    在android apache httpclient(已弃用) httpclient httpclient = new defaulthttpclient(); httppost httppost = new httppost(“ http://www.yoursite.com/script.p...
    编程 发布于2025-04-24
  • 人脸检测失败原因及解决方案:Error -215
    人脸检测失败原因及解决方案:Error -215
    错误处理:解决“ error:( - 215)!empty()in Function openCv in Function MultSiscale中的“检测”中的错误:在功能检测中。”当Face Cascade分类器(即面部检测至关重要的组件)未正确加载时,通常会出现此错误。要解决此问题,必须...
    编程 发布于2025-04-24
  • 如何使用FormData()处理多个文件上传?
    如何使用FormData()处理多个文件上传?
    )处理多个文件输入时,通常需要处理多个文件上传时,通常是必要的。 The fd.append("fileToUpload[]", files[x]); method can be used for this purpose, allowing you to send multi...
    编程 发布于2025-04-24
  • JavaScript计算两个日期之间天数的方法
    JavaScript计算两个日期之间天数的方法
    How to Calculate the Difference Between Dates in JavascriptAs you attempt to determine the difference between two dates in Javascript, consider this s...
    编程 发布于2025-04-24
  • C++中如何将独占指针作为函数或构造函数参数传递?
    C++中如何将独占指针作为函数或构造函数参数传递?
    在构造函数和函数中将唯一的指数管理为参数 unique pointers( unique_ptr [2启示。通过值: base(std :: simelor_ptr n) :next(std :: move(n)){} 此方法将唯一指针的所有权转移到函数/对象。指针的内容被移至功能中,在操作...
    编程 发布于2025-04-24
  • 为什么PYTZ最初显示出意外的时区偏移?
    为什么PYTZ最初显示出意外的时区偏移?
    与pytz 最初从pytz获得特定的偏移。例如,亚洲/hong_kong最初显示一个七个小时37分钟的偏移: 差异源利用本地化将时区分配给日期,使用了适当的时区名称和偏移量。但是,直接使用DateTime构造器分配时区不允许进行正确的调整。 example pytz.timezone(...
    编程 发布于2025-04-24
  • 在程序退出之前,我需要在C ++中明确删除堆的堆分配吗?
    在程序退出之前,我需要在C ++中明确删除堆的堆分配吗?
    在C中的显式删除 在C中的动态内存分配时,开发人员通常会想知道是否需要手动调用“ delete”操作员在heap-exprogal exit exit上。本文深入研究了这个主题。 在C主函数中,使用了动态分配变量(HEAP内存)的指针。当应用程序退出时,此内存是否会自动发布?通常,是。但是,即使在这...
    编程 发布于2025-04-24
  • 为什么使用固定定位时,为什么具有100%网格板柱的网格超越身体?
    为什么使用固定定位时,为什么具有100%网格板柱的网格超越身体?
    网格超过身体,用100%grid-template-columns 为什么在grid-template-colms中具有100%的显示器,当位置设置为设置的位置时,grid-template-colly修复了?问题: 考虑以下CSS和html: class =“ snippet-code”> g...
    编程 发布于2025-04-24
  • Python中何时用"try"而非"if"检测变量值?
    Python中何时用"try"而非"if"检测变量值?
    使用“ try“ vs.” if”来测试python 在python中的变量值,在某些情况下,您可能需要在处理之前检查变量是否具有值。在使用“如果”或“ try”构建体之间决定。“ if” constructs result = function() 如果结果: 对于结果: ...
    编程 发布于2025-04-24
  • 在C#中如何高效重复字符串字符用于缩进?
    在C#中如何高效重复字符串字符用于缩进?
    在基于项目的深度下固定字符串时,重复一个字符串以进行凹痕,很方便有效地有一种有效的方法来返回字符串重复指定的次数的字符串。使用指定的次数。 constructor 这将返回字符串“ -----”。 字符串凹痕= new String(' - ',depth); console.Wr...
    编程 发布于2025-04-24
  • 版本5.6.5之前,使用current_timestamp与时间戳列的current_timestamp与时间戳列有什么限制?
    版本5.6.5之前,使用current_timestamp与时间戳列的current_timestamp与时间戳列有什么限制?
    在时间戳列上使用current_timestamp或MySQL版本中的current_timestamp或在5.6.5 此限制源于遗留实现的关注,这些限制需要对当前的_timestamp功能进行特定的实现。 创建表`foo`( `Productid` int(10)unsigned not n...
    编程 发布于2025-04-24
  • 在PHP中如何高效检测空数组?
    在PHP中如何高效检测空数组?
    在PHP 中检查一个空数组可以通过各种方法在PHP中确定一个空数组。如果需要验证任何数组元素的存在,则PHP的松散键入允许对数组本身进行直接评估:一种更严格的方法涉及使用count()函数: if(count(count($ playerList)=== 0){ //列表为空。 } 对...
    编程 发布于2025-04-24
  • 如何修复\“常规错误:2006 MySQL Server在插入数据时已经消失\”?
    如何修复\“常规错误:2006 MySQL Server在插入数据时已经消失\”?
    How to Resolve "General error: 2006 MySQL server has gone away" While Inserting RecordsIntroduction:Inserting data into a MySQL database can...
    编程 发布于2025-04-24
  • Java中如何使用观察者模式实现自定义事件?
    Java中如何使用观察者模式实现自定义事件?
    在Java 中创建自定义事件的自定义事件在许多编程场景中都是无关紧要的,使组件能够基于特定的触发器相互通信。本文旨在解决以下内容:问题语句我们如何在Java中实现自定义事件以促进基于特定事件的对象之间的交互,定义了管理订阅者的类界面。以下代码片段演示了如何使用观察者模式创建自定义事件: args)...
    编程 发布于2025-04-24
  • 如何在php中使用卷发发送原始帖子请求?
    如何在php中使用卷发发送原始帖子请求?
    如何使用php 创建请求来发送原始帖子请求,开始使用curl_init()开始初始化curl session。然后,配置以下选项: curlopt_url:请求 [要发送的原始数据指定内容类型,为原始的帖子请求指定身体的内容类型很重要。在这种情况下,它是文本/平原。要执行此操作,请使用包含以下标头...
    编程 发布于2025-04-24

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3