使用 puppeteer 和 puppeteer-cluster 出现“尝试使用分离框架”

问题描述 投票:0回答:1

因此,我正在构建一个 express.js 应用程序,该应用程序使用 puppeteer 和 puppeteer-cluster 来访问一个乌克兰测试平台。我想做的事情是使用这个工具来解决测试。

所以,流程是这样的:

  1. 进入用户柜
  2. 搜索测试
  3. 进入测试
  4. 解决它。

当我已经进入测试并回答了几个问题时,问题就出现了,并且在某些时候我收到了这样的错误:

Attempted to use detached Frame 'D78184744F4CA70F50307B66DDF53250'
。我的错误表明,获取以类“.v-test-questions-title”命名的元素时出现问题,而该元素确实必须存在。

async solveSingleAnswerQuestion() {
        const pageElement = new PageElement(this.page)
        const question = await pageElement.getContent('.v-test-questions-title') -> error says the problem is here

        const variants = await pageElement.getContents(
            '.v-test-questions-radio-block',
            '.v-test-questions-checkbox-block'
        )
        console.log({ question, variants })
        const answerIndex = await generateResponseIndex(
            question || '',
            variants
        )
        console.log({ answerIndex })

        const variantsElements = await pageElement.getElements(
            '.v-test-questions-radio-block',
            '.v-test-questions-checkbox-block'
        )
        await variantsElements[answerIndex - 1].click()

        const submitButton = await pageElement.getElement('.v-blue-button-test')

        await submitButton.click()

        await waitFor(5000)
    }

下面是 PageElement 的代码(使所有代码更清晰的类)

import { cleanString, waitFor } from '@/utils'
    import type { ElementHandle, Page } from 'puppeteer'
    
        export class PageElement {
            constructor(private readonly page: Page) {}
        
            async loadAllElements() {
                const pageElement = new PageElement(this.page)
                const button = await pageElement.getElement('.vo-btn-blue')
        
                if (button) {
                    await button.click()
                    await waitFor(5000)
        
                    await this.loadAllElements()
                }
            }
        
            async getElementsByUniqueSelector(selector: string, fallback?: string) {
                const elements = await this.getElements(selector, fallback)
        
                const filteredElements = (
                    await Promise.all(elements.map(this.isElementWithSingleClass))
                ).filter((element) => element !== null)
        
                return filteredElements
            }
        
            async getContentsByUniqueSelector(selector: string, fallback?: string) {
                const elements = await this.getElementsByUniqueSelector(
                    selector,
                    fallback
                )
        
                const contents = await Promise.all(
                    elements.map((element) => element.evaluate((el) => el.textContent))
                )
        
                return this.cleanContents(contents)
            }
        
            async getContents(selector: string, fallback?: string) {
                const elements = await this.getElements(selector, fallback)
        
                const contents = await Promise.all(
                    elements.map((element) => element.evaluate((el) => el.textContent))
                )
        
                return this.cleanContents(contents)
            }
        
            async getElements(selector: string, fallback?: string) {
                const elements = await this.waitForAndGetElements(selector)
        
                if (elements.length > 0) {
                    return elements
                }
        
                if (fallback) {
                    return await this.waitForAndGetElements(fallback)
                }
        
                return []
            }
        
            async getContent(selector: string, fallback?: string) {
                const element = await this.getElement(selector, fallback)
        
                const content = await element?.evaluate((el) => el.textContent)
                const cleanedContent = cleanString(content || '')
        
                return cleanedContent
            }
        
            async getElement(selector: string, fallback?: string) {
                const elements = await this.getElements(selector, fallback)
        
                return elements[0]
            }
        
            private async waitForAndGetElements(selector: string) {
                const el = await this.page
                    .waitForSelector(selector, {
                        visible: true,
                        timeout: 5000,
                    })
                    .catch(() => null)
        
                const elContent = await el?.evaluate((el) => el.textContent)
                console.log({ elContent })
        
                return await this.page.$$(selector) -> error says that the problem is here. Puppeteer can't get the ".v-test-questions-title" element
            }
        
            private async isElementWithSingleClass(element: ElementHandle) {
                const className = await element.getProperty('className')
                const classList = (await className.jsonValue()).toString().split(' ')
        
                return classList.length > 1 ? null : element
            }
        
            private async cleanContents(contents: (string | null)[]) {
                return contents.map((content) => cleanString(content || ''))
            }
        }

还有我的集群初始化

import { Cluster } from 'puppeteer-cluster'

export const cluster = await Cluster.launch({
    concurrency: Cluster.CONCURRENCY_CONTEXT,
    maxConcurrency: 1000,
    // monitor: true,
    puppeteerOptions: {
        headless: true,
        dumpio: true,
        args: [
            '--no-sandbox',
            '--disable-setuid-sandbox',
            '--disable-dev-shm-usage',
        ],
    },
})

这是服务代码

async solveTestByTitle(testTitle: string) {
        await this.enterCabinet()

        const test = new Test(this.page)
        const pageElement = new PageElement(this.page)
        await test.startSolvingTestByTitle(testTitle)

        const question = await pageElement.getContent('.v-test-questions-title')
        console.log({ questionInService: question })

        while (question) {
            await test.solveSingleAnswerQuestion()
        }
    }

我一直在尝试很多事情,例如更改 puppeteer 选项、在容器中运行代码、更改浏览器、更改代码、在某些地方使用 page.waitForNavigation()、page.waitForNetworkIdle,但没有任何帮助,但有些方法只是更改了错误名称。

值得注意的是,当机器人回答问题时,网址不会改变。

javascript puppeteer puppeteer-cluster
1个回答
0
投票

我还没有找到任何解决方案。相反,我只是实现了重试逻辑。

© www.soinside.com 2019 - 2024. All rights reserved.