首页 > 解决方案 > 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');

不知道这里出了什么问题,有什么建议吗?

标签: node.jsweb-scrapingpuppeteer

解决方案


问题是该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;
}

推荐阅读