gpt4 book ai didi

node.js - 使用 puppeteer 单击不同链接时遇到问题

转载 作者:太空宇宙 更新时间:2023-11-03 22:57:37 25 4
gpt4 key购买 nike

我已经使用 puppeteer 在 Node 中编写了小脚本,以从 website 的登陆页面循环执行对不同帖子的链接的点击。

我的脚本中使用的站点链接是一个占位符。而且,它们不是动态的。所以, puppeteer 师可能有点过分了。然而,我的目的是学习点击的逻辑。

当我执行第一个脚本时,它单击一次并在退出源时抛出以下错误。

const puppeteer = require("puppeteer");

(async () => {
const browser = await puppeteer.launch({headless:false});
const [page] = await browser.pages();
await page.goto("https://stackoverflow.com/questions/tagged/web-scraping",{waitUntil:'networkidle2'});
await page.waitFor(".summary");
const sections = await page.$$(".summary");

for (const section of sections) {
await section.$eval(".question-hyperlink", el => el.click())
}

await browser.close();
})();

上述脚本遇到的错误:

(node:9944) UnhandledPromiseRejectionWarning: Error: Execution context was destroyed, most likely because of a navigation.

当我执行以下命令时,脚本假装单击一次(实际上并非如此)并遇到与之前相同的错误。

const puppeteer = require("puppeteer");

(async () => {
const browser = await puppeteer.launch({headless:false});
const [page] = await browser.pages();
await page.goto("https://stackoverflow.com/questions/tagged/web-scraping");

await page.waitFor(".summary .question-hyperlink");
const sections = await page.$$(".summary .question-hyperlink");

for (let i=0, lngth = sections.length; i < lngth; i++) {
await sections[i].click();
}

await browser.close();
})();

上面抛出的错误:

(node:10128) UnhandledPromiseRejectionWarning: Error: Execution context was destroyed, most likely because of a navigation.

如何让我的脚本循环执行点击?

最佳答案

问题:

Execution context was destroyed, most likely because of a navigation.

该错误表明您想要单击某个链接,或者在某个不再存在的页面上执行某些操作,很可能是因为您导航离开了。

逻辑:

将 puppeteer 脚本视为浏览真实页面的真人。

首先,我们加载网址 ( https://stackoverflow.com/questions/tagged/web-scraping )。

接下来,我们要检查该页面上提出的所有问题。为此,我们通常会做什么?我们会执行以下任一操作,

  • 新标签页中打开一个链接。专注于该新选项卡,完成我们的工作并返回到原始选项卡。继续下一个链接。
  • 我们点击链接,执行我们的操作,返回上一页,继续下一页。

所以它们都涉及离开和返回当前页面。

如果您不遵循此流程,您将收到上述错误消息。

解决方案

至少有 4 种或更多方法可以解决此问题。我会选择最简单和最复杂的。

方式:链接提取

首先我们提取当前页面上的所有链接。

const links = await page.$$eval(".hyperlink", element => element.href);

这给了我们一个 url 列表。我们可以为每个链接创建一个新选项卡。

for(let link of links){
const newTab = await browser.newPage();
await newTab.goto(link);
// do the stuff
await newTab.close();
}

这将一一浏览每个链接。我们可以通过使用promise.map和各种队列库来改进这一点,但你明白了。

方式:返回主页

我们需要以某种方式存储状态,以便我们知道上次访问的是哪个链接。如果我们访问了第三个问题并返回到标签页面,则下次我们需要访问第四个问题,反之亦然。

检查以下代码。

const puppeteer = require("puppeteer");

(async () => {
const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();

await page.goto(
`https://stackoverflow.com/questions/tagged/web-scraping?sort=newest&pagesize=15`
);

const visitLink = async (index = 0) => {
await page.waitFor("div.summary > h3 > a");

// extract the links to click, we need this every time
// because the context will be destryoed once we navigate
const links = await page.$$("div.summary > h3 > a");
// assuming there are 15 questions on one page,
// we will stop on 16th question, since that does not exist
if (links[index]) {
console.log("Clicking ", index);

await Promise.all([

// so, start with the first link
await page.evaluate(element => {
element.click();
}, links[index]),

// either make sure we are on the correct page due to navigation
await page.waitForNavigation(),
// or wait for the post data as well
await page.waitFor(".post-text")
]);

const currentPage = await page.title();
console.log(index, currentPage);

// go back and visit next link
await page.goBack({ waitUntil: "networkidle0" });
return visitLink(index + 1);
}
console.log("No links left to click");
};

await visitLink();

await browser.close();
})();

结果: enter image description here

编辑:有多个与此类似的问题。如果您想了解更多信息,我将引用它们。

关于node.js - 使用 puppeteer 单击不同链接时遇到问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56345544/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com