无法在木偶器中使用 xpath 提取下一页链接



我正试图找出一种方法来刮下一页链接从网页使用xpath内木偶。当我执行脚本时,可以看到即使xpath是正确的,脚本也会得到乱码的结果。我该怎么修理它?

const puppeteer = require("puppeteer");
const base = "https://www.timesbusinessdirectory.com";
let url = "https://www.timesbusinessdirectory.com/company-listings";
(async () => {
const browser = await puppeteer.launch({headless:false});
const [page] = await browser.pages();
await page.goto(url,{waitUntil: 'networkidle2'});
page.waitForSelector(".company-listing");
const nextPageLink = await page.$x("//a[@aria-label='Next'][./span[@aria-hidden='true'][contains(.,'Next')]]", item => item.getAttribute("href"));
url = base.concat(nextPageLink);
console.log("========================>",url)
await browser.close();
})();

当前输出:

https://www.timesbusinessdirectory.comJSHandle@node

预期输出:

https://www.timesbusinessdirectory.com/company-listings?page=2

首先,page.waitForSelector(".company-listing");上缺少一个await。如果不等待这一点,就完全破坏了调用的意义,但它可能偶然有效,因为非常严格的waitUntil: "networkidle2"覆盖了您感兴趣的选择器,或者xpath是静态存在的(我没有费心检查)。

一般来说,如果你在page.goto之后使用waitForSelector,waitUntil: "networkidle2"只会减慢你的速度。只有当页面上有waitForSelector目标以外的内容时才保留它,否则您将等待不相关的请求,这些请求会拉下可能与您的主要目标无关的图像、脚本和数据。如果这是一个缓慢加载的页面,那么增加waitFor...上的超时是典型的下一步。

另一个注意事项是,在某些CSS目标上使用waitForSelector有点奇怪,然后尝试立即选择xpath。对于waitForXPath似乎更精确,然后在完全相同的xpath模式上调用$x两次。

接下来,让我们看看page.$x: 的文档

page.$x(expression)

expression<string>求值表达式

返回:<Promise<Array<ElementHandle>>>

该方法计算相对于页面文档的XPath表达式作为其上下文节点。如果没有这样的元素,该方法解析为一个空数组。

page.mainFrame().$x(expression)的快捷方式

因此,与evaluate,$eval$$eval不同,$x接受一个参数并解析为一个elementHandle数组。你的第二个参数回调并没有像你想的那样得到href——这只适用于eval族函数。

除了查阅文档之外,您还可以console.log返回值来确认行为。您在URL中看到的JSHandle@node不是乱码,它是jhandle对象的字符串化形式,并提供您可以对照文档进行交叉检查的信息。

解决方案是从函数返回的数组中获取第一个元素handle,然后使用原始回调在该句柄上获取evaluate:

const puppeteer = require("puppeteer");
const url = "https://www.timesbusinessdirectory.com/company-listings";
let browser;
(async () => {
browser = await puppeteer.launch({headless: true});
const [page] = await browser.pages();
await page.goto(url);
const xp = `//a[@aria-label='Next']
[./span[@aria-hidden='true'][contains(.,'Next')]]`;
await page.waitForXPath(xp);
const [nextPageLink] = await page.$x(xp);
const href = await nextPageLink.evaluate(el => el.getAttribute("href"));
console.log(href); // => /company-listings?page=2
})()
.catch(err => console.error(err))
.finally(() => browser?.close())
;

顺便说一下,还有el => el.href用于获取href属性。.href包含这里的基本URL,因此您不需要进行连接。一般来说,除了提供绝对路径和相对路径之外,行为是不同的,所以最好了解这两种选择。

相关内容

  • 没有找到相关文章

最新更新