node.js - Puppeteer 从 elementHandle 获取元素导致协议错误
问题描述
我正在尝试为某个用户撰写的帖子抓取某个 Facebook 页面,并以某个单词开头。
const puppeteer = require('puppeteer');
async function findPosts(page) {
const USERNAME = 'test123';
const posts = await page.$$('.userContentWrapper');
return posts.filter(async post => {
try {
let usernameElement = await post.$('.fwb');
let username = await page.evaluate(element => element.textContent, usernameElement);
if (username === USERNAME) {
let postElement = await post.$('[data-testid="post_message"] p');
let postContent = page.evaluate(element => element.textContent, postElement);
return /\[test \d+\]/.test(postContent);
}
return false;
} catch(e) {
console.log(e);
return false;
}
});
}
(async () => {
const browser = await puppeteer.launch({
headless: false
});
const page = await browser.newPage();
await page.goto('https://www.facebook.com/groups/groupid/');
const pageTitle = await page.title();
console.log(pageTitle);
const posts = await findPosts(page);
console.log(posts);
await browser.close();
})();
我越来越
错误:协议错误(Runtime.callFunctionOn):目标已关闭。当我试图获取用户名元素时
在这一行:
让 usernameElement = await post.$('.fwb');
不知道这里出了什么问题,有什么建议吗?
解决方案
问题是该filter
函数不适用于 Promises。所以return posts.filter(...)
会立即返回,然后浏览器关闭。因此,当您尝试在页面上运行该$
功能时,该页面不再存在并且您收到Target closed
错误消息。
要使其与 async/await 语法一起使用,您可以使用一个简单的循环来代替:
async function findPosts(page) {
const USERNAME = 'test123';
const posts = await page.$$('.userContentWrapper');
const postsToReturn = [];
for (let post of posts) {
/* ... if else logic */
postsToReturn.push(post); // instead of return true
}
return postsToReturn;
}
推荐阅读
- ffmpeg - 为什么带有 libfdk_aac 编码的 ffmpeg 会在音频文件的开头减少 25 毫秒?
- java - Android 是否支持第三方库的设备相关实现?
- excel - 是否有一个函数可以让我根据另一个单元格中的值范围用文本填充单元格
- python - 如何复制数组元素
- c# - 在 c# 中使用 office interop 时得到的格式代码 (\r\a) 是什么?
- java - 从 Vaadin 事件监听器更新组件
- java - 如何点击按钮
- python - 我无法通过 USB 从 arduino 获取数据到树莓派
- html - 我有一个引导导航栏,它不会与按钮和搜索框保持一致 - 我如何使其保持一致?
- javascript - PM2 - 如何从日志文件名中删除标识符