在 Node.js 中使用无头 Google Chrome

大家好,
我是开发团队野生队的成员 Mandai。

之前写了一篇题为“
Google Chrome 59 现在支持无头模式,我要试用一下”的文章 | Beyond Co., Ltd. Chrome 会在后台自动更新,所以您可能不会注意到,但我还是想定期检查一下。

这次,我将尝试从 Node.js 以无头模式启动 Google Chrome,并通过 chrome-remote-interface 模块控制它。

示例程序无法运行!

在上一篇文章中,我们探讨了如何在命令行以无头模式启动 Google Chrome 并捕获屏幕,但由于仅使用 shell 脚本很难与其他系统集成,我们将从 Node.js 启动它并直接获取内容。

我基本上Google Developers 网站上的文章“Getting started with headless Chrome | Web | Google Developers”进行操作的,但我就是无法让它正常工作,所以我根据那篇文章中的代码做了一些修改,得到了以下源代码。

const ChromeLauncher = require('chrome-launcher'); const CDP = require('chrome-remote-interface'); const url = 'https://beyondjapan.com'; var launcherKill = (client, launcher, args = null) => { launcher.kill(); console.log(args); } ChromeLauncher.launch({ port: 9222, chromeFlags: [ // '--disable-gpu', // 如果需要启用 '--headless', // '--no-sandbox', // 如果需要启用 ], }).then(launcher => { CDP(client => { const {Page, DOM} = client; Promise.all([ Page.enable(), DOM.enable(), ]).then(() => { Page.navigate({url : url}); Page.loadEventFired(() => { DOM.getDocument((error, params) => { if (error){ console.log(params); launcher.kill(); return; } const opts = { nodeId : params.root.nodeId, selector : 'a' }; DOM.querySelectorAll(opts, (error, params) => { if (error){ console.log(params); launcher.kill(); return; } var promises = []; var getDomAttribute = (DOM, nodeId, count) => { return new Promise((resolve, reject)=>{ const opts = { nodeId : nodeId }; DOM.getAttributes(opts, (error, params) => { if (!error) console.log(count, params.attributes[1]); resolve(); }) }) }; console.log(params.nodeIds.length); params.nodeIds.forEach(elm => { promises.push(getDomAttribute(DOM, elm, promises.length)); }); Promise.all(promises).then(()=>{ launcher.kill(); }) }) }) }) }).on('error', error => { console.error(error) launcher.kill(); }) })

 

处理流程如下:

  1. 使用 chrome-launcher 模块启动 Google Chrome 浏览器
  2. 启动后,使用 chrome-remote-interface 模块连接到 DevTools 协议。
  3. 从 DevTools 客户端对象导航到指定的 URL 并检索数据。
  4. 从 DOM 中获取所有 A 标签,并将 href 值显示到标准输出。

这个问题
,但看起来第 49 行附近的 `DOM.getAttributes` 方法是异步运行的,如果我在运行 `forEach` 循环后立即停止 Google Chrome,就无法读取 DOM 内容。
这次,我使用了一个 Promise 来等待 DOM 全部读取完毕后再停止 Google Chrome。

 

发生错误

如果在启动脚本时出现以下错误,则需要调整 Google Chrome 的启动选项。

无法使用沙箱!请更新内核或访问 https://chromium.googlesource.com/chromium/src/+/master/docs/linux_suid_sandbox_development.md 获取更多关于使用 SUID 沙箱进行开发的信息。如果您想冒险尝试并需要一个临时解决方案,可以尝试使用 `--no-sandbox` 参数。.

 

似乎用于使用 Google Chrome 沙盒环境的库中,Google Chrome 可执行文件的路径是硬编码的,导致沙盒无法正常工作。
要彻底解决此错误,似乎需要修改 sandbox/linux/suid/sandbox.cc 文件中的硬编码路径,然后重新构建应用程序。

此外,在紧急情况下或作为临时解决方案,您可以通过取消注释启动选项“--no-sandbox”来启动它。

在这种情况下,请注意,Google Chrome 将在不使用沙盒的环境中启动,这会增加安全风险。

 

那么,它是用来做什么的呢?(总结)

由于可以通过开发者工具直接与谷歌浏览器交互,因此看起来您将能够执行比以往任何时候都更加逼真的网络爬虫操作。

似乎也可以测试 JavaScript 行为,因此如果能够使用代码库在后台自动运行此类测试,将会非常方便。

由于网站的结构,或许可以创建一个系统来监控那些无法使用 curl 等工具完全监控的内容是否正常运行。

就这样。

如果您觉得这篇文章有用,请点击【点赞】!
0
加载中...
0票,平均分:0.00/10
2,220
X Facebook Hatena书签 口袋

这篇文章的作者

关于作者

万代洋一

我的主要工作是开发社交游戏的Web API,但我也很荣幸能够从事其他各种工作,包括市场营销。
我在Beyond中的肖像权采用CC0协议。