javascript - Puppeteer 和错误处理中的评估失败错误

标签 javascript node.js puppeteer

我使用 Puppeteer 开发解析应用程序,它运行良好。但问题是这个应用有时会出错,我不知道为什么会出现这个错误。

我必须捕获大约 90,000 个数据。

错误似乎是由于没有读取类列表引起的,但即使我将 Headless 选项设置为 False 并检查,类列表仍然存在。

起初,它运行良好并随机产生错误。

在我看来,有时页面不会在网站本身上加载并继续停在加载栏上,这就是原因。

即使我在 waitUntil 值中给出一个 networkidle0 或 2,如果这个预测是正确的,我也不知道如何检测它。

[完整代码]

'use strict';

const puppeteer = require('puppeteer'); // Puppeteer 모듈 Load
(async () => {
    const browser = await puppeteer.launch({ // Puppeteer 모듈을 사용하지 않고 기존의 크롬 사용자 정보를 사용 (Auth 인증을 패스하기 위하여)
        executablePath: 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe',
        userDataDir: 'C:\\User\\AppData\\Local\\Google\\Chrome\\User Data', // 설치시 개인 크롬 Directory로 수정하여야함
        headless: true
    });
    const page = await browser.newPage(); // Broswer Open
    await page.setViewport({ // Viewport 설정 가로의 경우 일반적으로 최대 1920, 새로의 경우 예상되는 최대 px를 지정해주면됨
        width: 800,
        height: 6000
    });
    page.on('dialog', async dialog => { // 삭제된 게시글의 경우 Band에서 Dialog를 띄우는데 이를 제거하기 위하여 필요
        console.log(dialog.message());
        await dialog.dismiss(); // Dialog 창 닫음
        await postNumber++; // 삭제된 게시글의 경우 Dialog 창이 닫힌후에 이전 URL로 돌아가므로 postNumber 1증가 시켜줌
        await page.goto(`https://band.us/band/58075840/post/${postNumber}`, {
            waitUntil: 'networkidle0'
        });
    })
    let postNumber = 14565; // 시작되는 PostNumber * 이 부분 부터 시작 *
    while (postNumber <= 90000) { // PostNumber 끝값 * 이 부분은 마지막 값 *
        await page.goto(`https://band.us/band/58075840/post/${postNumber}`, {
            waitUntil: 'networkidle0' // 페이지가 완전히 Load된후 작동
        });

        let by = await page.evaluate(() => document.getElementsByClassName('text')[0].innerText); // 게시글 작성자 Text 파싱
        let date = await page.evaluate(() => document.getElementsByClassName('time')[0].innerText); // 게시글 작성일 Text 파싱
        let element = await page.$('.boardList'); // 게시글, 댓글 전체 Class
        await element.screenshot({ // ScreenShot Function
            path: `./image/${postNumber}-${by}-${date.replace(":","_")}.png` // 파일 저장 위치 & 파일이름 지정, replace 메소드의 경우 Windows 탐색기에서 :를 파일명으로 지원하지 않기때문
        });
        console.log(`${postNumber}-${by}-${date.replace(":","_")}.png`) // Console.log에서 파일 확인
        await postNumber++; // 최종 성공시 postnumber 증가
    }
    await browser.close(); // 종료
})();

[错误消息]


(node:16880) UnhandledPromiseRejectionWarning: Error: Evaluation failed: TypeError: Cannot read property 'innerText' of undefined
    at __puppeteer_evaluation_script__:1:50
    at ExecutionContext.evaluateHandle (C:\Users\\Downloads\Projects\Bander-Statistics\node_modules\puppeteer\lib\ExecutionContext.js:121:13)
    at process._tickCallback (internal/process/next_tick.js:68:7)
  -- ASYNC --
    at ExecutionContext.<anonymous> (C:\Users\\Downloads\Projects\Bander-Statistics\node_modules\puppeteer\lib\helper.js:108:27)
    at ExecutionContext.evaluate (C:\Users\\Downloads\Projects\Bander-Statistics\node_modules\puppeteer\lib\ExecutionContext.js:48:31)
    at ExecutionContext.<anonymous> (C:\Users\\Downloads\Projects\Bander-Statistics\node_modules\puppeteer\lib\helper.js:109:23)
    at DOMWorld.evaluate (C:\Users\\Downloads\Projects\Bander-Statistics\node_modules\puppeteer\lib\DOMWorld.js:105:20)
    at process._tickCallback (internal/process/next_tick.js:68:7)
  -- ASYNC --
    at Frame.<anonymous> (C:\Users\\Downloads\Projects\Bander-Statistics\node_modules\puppeteer\lib\helper.js:108:27)
    at Page.evaluate (C:\Users\\Downloads\Projects\Bander-Statistics\node_modules\puppeteer\lib\Page.js:809:43)
    at Page.<anonymous> (C:\Users\\Downloads\Projects\Bander-Statistics\node_modules\puppeteer\lib\helper.js:109:23)
    at C:\Users\\Downloads\Projects\Bander-Statistics\band.js:29:29
    at process._tickCallback (internal/process/next_tick.js:68:7)
(node:16880) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:16880) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

最佳答案

错误

根据你的错误信息,错误发生在这一行:

let by = await page.evaluate(() => document.getElementsByClassName('text')[0].innerText); // 게시글 작성자 Text 파싱

当您向网站发出大约 75,000 个请求时,我可以想象该网站正在采取保护措施来禁止您的机器人进行抓取。或者,您尝试抓取的帖子可能不存在。

修复

要解决您的问题,您可以像这样更改您的evaluate 函数。如果元素不存在,这将返回 undefined(而不是抛出错误)。它还通过仅使用一个 page.evaluate 调用来改进您的代码。

let [by, date] = await page.evaluate(() => {
    const textNode = document.getElementsByClassName('text')[0];
    const timeNode = document.getElementsByClassName('time')[0];
    return [
        textNode && textNode.innerText,
        timeNode && timeNode.innerText,
    ];
});
if (!by || !date) {
    // by or date is undefined
    console.log(`Not working for ID: ${postNumber}`);
    await element.screenshot({ path: `error-${postNumber}.png` });
}

这将生成发生错误的页面的屏幕截图。也许您会看到网站发生了变化(也许他们正在向您显示验证码?)或者您尝试抓取的帖子根本不存在。

如果屏幕截图没有帮助,您还可以使用 page.content() 将 HTML 保存在错误情况下并查看它。

关于javascript - Puppeteer 和错误处理中的评估失败错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55467333/

相关文章:

javascript - 像 Babel 这样的转译器在本身不支持的情况下如何实现尾调用优化?

javascript - 如何在网站链接前添加文本,fx store.mywebsite.com

javascript - JavaScript 中数字减法和加法有什么区别?

javascript - 遍历 DOM 以选择特定的 child 进行 e2e 测试

javascript - 如何使用 Puppeteer 从 XHR 请求中获取 body/json 响应

javascript - OAuthException "(#210) Subject must be a page."错误

node.js - 无法重新启动 redis-server.service : Unit redis-server. 找不到服务

javascript - 使用 Firestore 查询的信息响应 Dialogflow

javascript - 如何正确地将用户名和密码从reactjs传递到后端进行身份验证?

javascript - 当使用 ng-click 指令单击按钮时,如何防止在使用 puppeteer 抓取期间打开新选项卡?