返回博客
指南
Mihnea-Octavian ManolacheLast updated on Mar 31, 20262 min read

如何使用 Puppeteer 创建爬虫并提交表单

如何使用 Puppeteer 创建爬虫并提交表单

你在进行网页抓取时,是否曾需要处理 POST 请求?我相信你一定遇到过!而且大多数时候,我们需要处理的都是表单。正因如此,今天我将探讨如何使用 Puppeteer 提交表单。如果你还不了解 Puppeteer,别担心。 马上你就会知道。在此之前,让我先为今天的文章设定一些预期目标。如果你一直跟着我的学习路径,今天你应该能够学会:

  • 在网页抓取中,Puppeteer是什么
  • 如何搭建一个简单的 Puppeteer 项目
  • Puppeteer 中如何处理表单提交

那么,废话不多说,让我们开始吧!

什么是 Puppeteer,它为何对网页抓取如此重要?

通常来说,网页抓取是指从各种服务器中自动提取数据的过程。早些时候,一个简单的 HTTP 客户端就足以完成这项任务。但如今,网站越来越依赖 JavaScript。而传统的 HTTP 客户端无法渲染 JavaScript 文件。这就是 Puppeteer 发挥作用的地方。

Puppeteer 是一个 Node.js 库,允许您通过 DevTools 协议控制无头版 Chrome 或 Chromium 浏览器。简而言之,它提供了一个用于自动化控制 Chrome 的高级 API。

在网页抓取方面,Puppeteer 特别适用于抓取那些需要渲染 JavaScript 的网站。此外,它还能像人类一样与网页进行交互,例如点击按钮,或者我们今天要重点探讨的——填写表单。这使得它成为抓取采用反抓取技术的网站的理想工具。

搭建一个简单的 Puppeteer 项目

我认为放慢节奏有助于更好地理解整体流程。在探讨如何使用 Puppeteer 提交表单之前,让我们先了解基础的 Puppeteer。在本节中,我将向您展示如何创建 Node 项目、安装 Puppeteer 以及使用它进行数据抓取。 那么,首先,让我们创建一个新文件夹,并在我们喜欢的 IDE 中打开它。我个人偏好 Visual Studio Code,但您也可以自由选择任何您喜欢的工具。

你知道吗?

  • 您可以在终端中输入 `mkdir` 命令,通过“编程方式”创建新文件夹。
  • 你可以使用 `npm init -y` 命令来创建 Node 项目并接受默认值
  • 你可以使用 `touch` 命令创建新文件。
  • 此外,你还可以通过 `code .` 命令直接打开 VSCode。

如果你愿意,可以将这四条命令结合起来,像这样在几秒钟内启动一个项目:

~ » mkdir scraper && cd scraper && npm init -y && code .

在 IDE 中打开一个新终端(Terminal > New Terminal),然后安装 Puppeteer。在终端中输入 `npm i puppeteer --save`。另外,我更倾向于使用 JS 模块而非 CommonJS。您可以在此处查看两者的区别。如果您也想使用模块,请打开 `package.json` 文件,并在 JSON 对象中添加 `"type": "module"`。

现在一切就绪,我们可以开始编写代码了。创建一个新的 `index.js` 文件并在 IDE 中打开它。这次无需通过终端操作,但作为提示,你可以使用 `touch` 命令。现在让我们添加代码:

import puppeteer, { executablePath } from 'puppeteer'

const scraper = async (url) => {

   const browser = await puppeteer.launch({

       headless: false,

       executablePath: executablePath(),

   })

   const page = await browser.newPage()

   await page.goto(url)

   const html = await page.content()

   await browser.close()

   return html

}

让我们看看具体做了什么:

  • 我们将 Puppeteer 和 `executablePath` 导入到项目中
  • 我们定义了一个新函数,该函数接受一个 `url` 参数
  • 我们使用 `puppeteer.launch` 启动一个新浏览器 a. 我们指定以全屏模式运行 b. 我们使用 `executablePath` 获取 Chrome 的路径
  • 我们打开一个新页面并导航至 `url`
  • 我们将 `page.content()` 保存到一个常量中
  • 我们关闭了浏览器实例
  • 最后,返回刚刚抓取的页面的 `html` 输出

到目前为止,操作并不复杂。这是使用 Node.js 和 Puppeteer 实现网页抓取的最基本示例。若要运行代码,只需向 `scraper` 函数传入目标页面,并记录其返回值即可:

console.log(await scraper('https://webscrapingapi.com/'))

但请记住,我们的目标是在提交表单时提取数据。这意味着我们需要设法使用 Puppeteer 提交表单。幸运的是,我之前做过,知道这并不难。那么,让我们看看你如何也能做到。

如何使用 Puppeteer 提交表单

不妨将 Puppeteer 视为在特定网站上模拟人类行为的工具。 我们人类是如何提交表单的呢?通常,我们会找到表单,填写内容,然后点击按钮。Puppeteer 提交表单的逻辑与此完全相同。唯一的区别在于执行这些操作的方式。因为人类依赖感官,而 Puppeteer 是软件,所以我们将通过编程方式,利用 Puppeteer 的内置方法来实现,如下所示:

#1:使用 Puppeteer 提交简单表单

首先,我们需要“可视化”表单。在网站中,所有元素都归类在 HTML 块中,且每个元素都有一个标识符。标识符通常由元素的 CSS 属性组成。不过,您可能会遇到没有此类选择器的网站。在这种情况下,您可以使用 xPath 等方法。但这属于另一个话题。让我们专注于使用 CSS 在 Puppeteer 中识别元素。

为了便于理解,假设我们要自动化执行 Stack Overflow 的登录操作。目标页面是 https://stackoverflow.com/users/login。打开浏览器,访问登录页面,并开启开发者工具。你可以右键点击页面并选择“检查”。此时你应该看到如下内容:

左侧是图形界面,右侧是 HTML 结构。仔细观察右侧,你会看到我们的表单。它主要由两个输入框和一个按钮组成。这三个元素就是我们的目标。如你所见,这三个元素都带有 `id` 作为 CSS 标识符。现在让我们将迄今所学的内容转化为代码:

import puppeteer, { executablePath } from 'puppeteer'

const scraper = async (target) => {

   const browser = await puppeteer.launch({

       headless: false,

       executablePath: executablePath(),

   })

   const page = await browser.newPage()

   await page.goto(target.url,{waitUntil: 'networkidle0'})

   await page.type(target.username.selector, target.username.value)

   await page.type(target.password.selector, target.password.value)

   await page.click(target.buttonSelector)

   const html = await page.content()

   await browser.close()

   return html

}

为了保持代码的功能性和可复用性,我选择将函数的参数替换为一个对象。该对象包含目标 URL、输入框的选择器及其值,以及提交按钮的选择器。因此,要运行代码,只需创建一个包含您数据的新 `TARGET` 对象,并将其传递给您的 `scraper` 函数:

const TARGET = {

   url: 'https://stackoverflow.com/users/login',

   username: {

       selector: 'input[id=email]',

       value: '<YOUR_USERNAME>'

   },

   password: {

       selector: 'input[id=password]',

       value: '<YOUR_PASSWORD>'

   },

   buttonSelector: 'button[id=submit-button]'

}

console.log(await scraper(TARGET))

#2:使用 Puppeteer 上传文件

有时,Web自动化需要我们上传文件,而非仅提交简单的表单。若遇到此类任务,且需要在通过Puppeteer提交表单前附加文件,建议使用Puppeteer的`uploadFile`方法。为简化操作,建议为此操作创建一个新函数:

const upload = async (target) => {

   const browser = await puppeteer.launch({

       headless: false,

       executablePath: executablePath(),

   })

   const page = await browser.newPage()

   await page.goto(target.url,{waitUntil: 'networkidle0'})

   const upload = await page.$(target.form.file)

   await upload.uploadFile(target.file);

   await page.click(target.form.submit)

  

   await browser.close()

}

请注意,这次我使用 `page.$` 先定位元素。只有在此之后,我才调用 `uploadFile` 方法——该方法仅适用于 `ElementHandle` 类型。在参数方面,与之前一样,我使用一个对象将所有数据一次性传递给函数。若要测试脚本,只需添加以下代码,并在终端中运行 `node index.js`:

const TARGET = {

   url: 'https://ps.uci.edu/~franklin/doc/file_upload.html',

   form: {

       file: 'input[type=file]',

       submit: 'input[type=submit]'

   } ,

   file: './package.json'

}

upload(TARGET)

结论

总而言之,我认为使用 Puppeteer 提交表单相当简单。此外,我发现与其他替代方案相比,Puppeteer 能完全胜任这一操作。基本上,用户只需正确识别元素即可。

不过需要说明的是,实际应用中的爬虫要高效运行还需更多条件。大多数情况下,若在短时间内提交过多表单而“滥用”服务器,很可能会被封禁。因此,若您想自动化表单提交流程,建议使用专业的爬虫服务。 在 Web Scraping API,我们确实提供了发送 POST 和 PUT 请求的选项。您可以在我们的文档中了解更多相关信息。

关于作者
Mihnea-Octavian Manolache, 全栈开发工程师 @ WebScrapingAPI
Mihnea-Octavian Manolache全栈开发工程师

Mihnea-Octavian Manolache 是 WebScrapingAPI 的全栈及 DevOps 工程师,负责开发产品功能并维护确保平台平稳运行的基础设施。

开始构建

准备好扩展您的数据收集规模了吗?

加入2,000多家企业,使用WebScrapingAPI在无需任何基础设施开销的情况下,以企业级规模提取网络数据。