【问题标题】:Grab all hrefs with Puppeteer使用 Puppeteer 获取所有 href
【发布时间】:2021-06-04 08:23:17
【问题描述】:
const href = await page.evaluate(() => {
let array = Array.from(document.querySelectorAll("table tr td a").href);
return array.map((array) => array.innerText);
});
我一直在尝试使用这个 JS 块来执行此操作,但它不起作用,它只是不断返回 undefined。
但是当我做document.querySelector("table tr td a").href; 时它可以工作,但它只给出第一个(有多个)!
我该如何正确操作?
【问题讨论】:
标签:
javascript
html
node.js
web-scraping
puppeteer
【解决方案1】:
在调试注入驱动浏览器的 Puppeteer 序列化代码时,请记住:
- 代码在浏览器上下文中运行
- 状态不与 Node 环境共享,除非通过序列化参数和返回值(您无法在浏览器中访问 Node 函数或 ElementHandles)
- 默认情况下,页面
console.logs 在 Node 环境中不可见
考虑到这些,您可以attach console.log handlers 帮助您在 Node.js 中调试浏览器代码。在许多情况下,您可以简单地在 Puppeteer 之外在抓取页面上的控制台中手动执行它,以验证它是否有效,如下所示。
这里的问题是querySelector(返回匹配 CSS 选择器的第一个元素)和 querySelectorAll(返回匹配选择器的所有元素的 NodeList)之间存在差异。 .href 不是 NodeList 对象的属性;此属性访问需要使用map 应用于NodeList 中的每个元素,将NodeList 转换为数组后可用。
一旦您赋予自己console.log 的能力,就可以轻松地进行调试,只需打印每个函数调用的返回值以查看存在哪些属性。
下面的代码说明了这两个函数之间的区别,并且在 Puppeteer 中就像在堆栈 sn-p 中一样工作得很好:
// print first element's href
console.log(document.querySelector("table tr td a").href);
// print all elements' hrefs
console.log([...document.querySelectorAll("table tr td a")].map(e => e.href));
<table>
<tr>
<td>
<a href="foo.html">foo</a>
<a href="bar.html">bar</a>
<a href="baz.html">baz</a>
</td>
</tr>
</table>