Javascript 木偶演员的行为与开发人员控制台中的不同
我正在尝试使用Puppeter提取此页面的标题: 我有下面的代码Javascript 木偶演员的行为与开发人员控制台中的不同,javascript,node.js,web-scraping,puppeteer,Javascript,Node.js,Web Scraping,Puppeteer,我正在尝试使用Puppeter提取此页面的标题: 我有下面的代码 (async () => { const browser = await puppet.launch({ headless: true }); const page = await browser.newPage(); await page.goto(req.params[0]); //this is the url
(async () => {
const browser = await puppet.launch({ headless: true });
const page = await browser.newPage();
await page.goto(req.params[0]); //this is the url
title = await page.evaluate(() => {
Array.from(document.querySelectorAll("meta")).filter(function (
el
) {
return (
(el.attributes.name !== null &&
el.attributes.name !== undefined &&
el.attributes.name.value.endsWith("title")) ||
(el.attributes.property !== null &&
el.attributes.property !== undefined &&
el.attributes.property.value.endsWith("title"))
);
})[0].attributes.content.value ||
document.querySelector("title").innerText;
});
我已经使用浏览器控制台测试过了,甚至使用了Puppeter的{headless:false}选项。它在浏览器中按预期工作,但当我实际使用node运行它时,会出现以下错误
10:54:21 AM web.1 | (node:10288) UnhandledPromiseRejectionWarning: Error: Evaluation failed: TypeError: Cannot read property 'attributes' of undefined
10:54:21 AM web.1 | at __puppeteer_evaluation_script__:14:20
因此,当我在浏览器中运行相同的Array.from…querySelectorAll(“meta”)…
查询时,我得到了预期的字符串:
"Zella High Waist Studio Pocket 7/8 Leggings | Nordstrom"
我开始认为我在异步承诺方面做错了什么,因为这是不同的部分。谁能给我指出正确的方向吗
编辑:正如建议的那样,我使用document.title进行了测试,它应该在那里,但它也返回null。请参阅下面的代码和日志:
console.log(
"testing the return",
(async () => {
const browser = await puppet.launch({ headless: true });
const page = await browser.newPage();
await page.goto(req.params[0]); //this is the url
try {
title = await page.evaluate(() => {
const title = document.title;
const isTitleThere = title == null ? false : true;
//recently read that this checks for undefined as well as null but not an
//undeclared var
return {
title: title,
titleTitle: title.title,
isTitleThere: isTitleThere,
};
});
} catch (error) {
console.log(error, "There was an error");
}
编辑:进步!!
感谢大卫伯顿。看来无头是假的吗?有人知道原因吗?导航到页面时,请等待页面加载
await page.goto(req.params[0], { waitUntil: "networkidle2" }); //this is the url
你能试试这个吗
try {
title = await page.evaluate(() => {
const title = document.title;
const isTitleThere = title == null? false: true
//recently read that this checks for undefined as well as null but not an
//undeclared var
return {"title":title,"isTitleThere" :isTitleThere }
})
} catch (error) {
console.log(error, 'There was an error');
}
还是这个
如果您只需要
title
的内部文本,您可以使用Puppeter方法来实现相同的结果:
const title = await page.$eval('title', el => el.innerText)
console.log(title)
输出:
Zella High Waist Studio Pocket 7/8 Leggings | Nordstrom
page.$$eval(选择器,pageFunction[,…args])
page.$eval方法在页面内运行Array.from(document.querySelectorAll(selector))
,并将其作为第一个参数传递给pageFunction
但是:您的主要问题是,您正在访问的页面是React.Js中制作的单页应用程序(SPA),其
标题
由JavaScript包动态填充。因此,当
的内容仅为:“”
(空字符串)时,您的木偶演员会在
中找到一个有效的title
元素
通常,您应该在SPA的情况下使用,以确保DOM由实际的JS框架正确填充,并且功能齐全:
await page.goto('https://www.nordstrom.com/s/zella-high-waist-studio-pocket-7-8-leggings/5460106', {
waitUntil: 'networkidle0'
})
不幸的是,对于这个特定的网站,它抛出了一个超时错误,因为网络连接直到30000毫秒的默认超时才会关闭,网页前端似乎有点不正常(webworker处理?)
作为一种解决方法,在尝试检索标题之前,您可以使用:等待页面。waitFor(8000)
:强制木偶演员睡眠8秒钟,届时将正确填充该标题。实际上,当您在DevTools控制台中运行脚本时,它会工作,因为您没有立即运行脚本:此时页面已完全加载,DOM已填充。
此脚本将返回预期的标题:
异步函数fn(){
const browser=wait puppeter.launch({headless:false})
const page=wait browser.newPage()
等待页面。转到('https://www.nordstrom.com/s/zella-high-waist-studio-pocket-7-8-leggings/5460106', {
waitUntil:'networkidle2'
})
等待页面。等待(8000)
const title=等待页面。$eval('title',el=>el.innerText)
console.log(标题)
等待浏览器关闭()
}
fn()
可能
const browser=wait puppeter.launch({headless:false})
也会影响结果。我尝试了第一个。结果是真的:(但我正在查看的页面中肯定有一个文档标题。你可以像这样访问标题。标题我不是。我应该是吗?:0我只希望这一个函数是异步的。我想,它可以在等待时完成其余的工作。这错了吗?我应该将我的整个代码包装在一个异步函数中吗?为什么networkidle2 specifically,而不是networkidle0或1?当我遇到该问题时,我使用了此url的解决方案。即使使用networkidle和8000,它仍然返回空。是否可能在这些等待之后它仍未完全加载?或者我是否做了其他错误?如何使用networkidle?如果使用networkidle0,整个脚本可能会失败。我的脚本仅为这3行(在page.goto之后)现在它返回了标题。我尝试了networkidle2和networkidle0。请参见编辑。相同的结果。如果你说你的代码正在返回标题,那么可能是我的代码的其他部分搞乱了,因为我们有相同的东西。我将清除它们,看看它是否仍然会导致问题。谢谢你的帮助!@QrowSaki我已添加我的整个脚本最后都很清晰。我认为游戏规则的改变者是{headless:true}
变为{headless:false}
。值得调查一下为什么它会产生不同的结果。很高兴我能帮上一点忙。是的,这是“令人头痛的”chrome。问题是:只有在浏览器不是无头的情况下(至少到目前为止,这似乎是限制因素)。你可以尝试使用Puppeter extra和其他名为隐形的插件来假装你的chrome是一个有头的实例,而不启动UI:如果你值得这么做的话(以及对项目的其他依赖项)。
try {
title = await page.evaluate(() => {
const title = document.querySelector('meta[property="og:title"]');
const isTitleThere = title == null? false: true
//recently read that this checks for undefined as well as null but not an
//undeclared var
return {"title":title,"isTitleThere" :isTitleThere }
})
} catch (error) {
console.log(error, 'There was an error');
}
const title = await page.$eval('title', el => el.innerText)
console.log(title)
Zella High Waist Studio Pocket 7/8 Leggings | Nordstrom
await page.goto('https://www.nordstrom.com/s/zella-high-waist-studio-pocket-7-8-leggings/5460106', {
waitUntil: 'networkidle0'
})