我是puppeteer的新手,他试图通过编写简单的抓取作业来了解其工作原理。
计划很简单:
<li>
标签下提取所有<ul>
链接<li>
链接,然后为目标页面截图。代码如下,
await page.goto('http://some.url.com'); // step-1
const a_elems = await page.$$('li.some_css_class a'); // step-2
for (var i=0; i<a_elems.length; i++) { // step-3
const elem = a_elems[i];
await Promise.all([
elem.click(),
page.waitForNavigation({waitUntil: 'networkidle0'}) // click each link and wait page loading
]);
await page.screenshot({path: `${IMG_FOLDER}/${txt}.png`});
await page.goBack({waitUntil: 'networkidle0'}); // go back to previous page so that we could click next link
console.log(`clicked link = ${txt}`);
}
但是,以上代码仅适用于a_elems
中的第一个链接,并且当for-loop
到达第二个链接时,该代码会以错误提示
(node:40606) UnhandledPromiseRejectionWarning: Error: Node is detached from document
at ElementHandle._scrollIntoViewIfNeeded (.../.npm-packages/lib/node_modules/puppeteer/lib/JSHandle.js:203:13)
at processTicksAndRejections (internal/process/task_queues.js:93:5)
at async ElementHandle.click (.../.npm-packages/lib/node_modules/puppeteer/lib/JSHandle.js:282:5)
at async Promise.all (index 0)
at async main (.../test.js:34:5)
-- ASYNC --
at ElementHandle.<anonymous> (.../.npm-packages/lib/node_modules/puppeteer/lib/helper.js:111:15)
at main (.../test.js:35:12)
at processTicksAndRejections (internal/process/task_queues.js:93:5)
我怀疑单击第一个链接后page
的执行上下文已经更改,即使我在上一页中调用了page.goBack
,但它没有给我上一个执行上下文。
不确定我的猜测是对还是错,并且找不到任何类似的问题,希望我能在这里得到一些帮助,谢谢!
如果有更好的实施方案来实现我的计划,请告诉我。
答案 0 :(得分:1)
在goBack
时元素丢失其上下文是正确的。那是行不通的。
但是,正如您评论的那样,您可以从元素中抓取href
并从那里开始:
for (var i=0; i<a_elems.length; i++) { // step-3
const elem = a_elems[i];
const href = await page.evaluate(e => e.href, elem); //Chrome will return the absolute URL
const newPage = await browser.newPage();
await newPage.goto(href);
await newPage.screenshot({path: `${IMG_FOLDER}/${txt}.png`});
await newPage.close();
console.log(`clicked link = ${txt}`);
}
尽管有一个内部屏幕快照队列,您甚至可以并行执行此操作。