我正试图找出一种方法来刮下一页链接从网页使用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,因此您不需要进行连接。一般来说,除了提供绝对路径和相对路径之外,行为是不同的,所以最好了解这两种选择。