当我在无头模式下运行脚本时,它只是在 page.goto(url)
上超时。当我使用 headless:false
运行它并让它做它的事情时,您可以看到 URL 开始加载片刻,然后进入某种重定向和无限加载。
但是,如果在 headless:false
中,我打开一个新标签并手动导航到 URL,那么原始标签将正常加载。我已经采取了很多措施来避免在这里被发现;
const puppeteer = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth')
const userAgent = require('user-agents');
await puppeteer.use(StealthPlugin())
var browser = await puppeteer.launch({headless: false});
let page = await browser.newPage();
page.setViewport({
width: 1200,
height: 800,
deviceScaleFactor: 1,
hasTouch: false,
isLandscape: true,
isMobile: false,
});
var agent = userAgent.random()
await page.setUserAgent(agent.toString());
await page.setJavaScriptEnabled(true);
// Pass the Webdriver Test.
await page.evaluateOnNewDocument(() => {
Object.defineProperty(navigator, 'webdriver', {
get: () => false,
});
});
// Pass the Chrome Test.
await page.evaluateOnNewDocument(() => {
// We can mock this in as much depth as we need for the test.
window.navigator.chrome = {
runtime: {},
// etc.
};
});
// Pass the Permissions Test.
await page.evaluateOnNewDocument(() => {
const originalQuery = window.navigator.permissions.query;
return window.navigator.permissions.query = (parameters) => (
parameters.name === 'notifications' ?
Promise.resolve({ state: Notification.permission }) :
originalQuery(parameters)
);
});
// Pass the Plugins Length Test.
await page.evaluateOnNewDocument(() => {
// Overwrite the `plugins` property to use a custom getter.
Object.defineProperty(navigator, 'plugins', {
// This just needs to have `length > 0` for the current test,
// but we could mock the plugins too if necessary.
get: () => [1, 2, 3, 4, 5],
});
});
// Pass the Languages Test.
await page.evaluateOnNewDocument(() => {
// Overwrite the `plugins` property to use a custom getter.
Object.defineProperty(navigator, 'languages', {
get: () => ['en-US', 'en'],
});
});
const session = await page.target().createCDPSession();
await session.send("Page.enable");
await session.send("Page.setWebLifecycleState", { state: "active" });
await page.bringToFront();
await page.goto(url, {waitUntil: "networkidle2"} );
除非我手动打开一个新选项卡并在地址栏中键入内容,否则我仍然告诉他们我正在运行 puppeteer 有什么想法吗?或者,有没有办法在浏览器中强制进行更人性化的交互,以打开新标签页,并允许我无头地执行此操作?
编辑:当我说“进入某种重定向和无限加载”时,要清楚的是,我看到页面渲染的短暂闪烁,然后它转到一个空白的白色页面。地址栏中没有发现任何变化,但加载图标指示器似乎显示了某种类型的重定向或刷新。无论我在 puppeteer 创建的选项卡之前、期间还是之后手动打开新选项卡,只要手动选项卡开始加载 URL,puppeteer 创建的选项卡就会突然开始工作。
答案 0 :(得分:0)
问题出在 waitUntil
和 networkidle2
上,这是因为有时 puppeteer 遵循的规则比我们认为的“完全加载的网页”要严格得多。即使你作为人类可以决定你想要的元素是否已经在 DOM 中(因为你看到了实际的元素)或者它不存在(因为你没有看到它),puppeteer 可能会等待别的东西。例如:即使背景图片仍在后台加载,您也会看到您的元素已经存在。
注意:未正确选择 waitUntil
选项可能导致空白页,我通过将 puppeteer 的 default timeout 修改为更短的时间来重现您的问题。
(1) 如果您的任务不需要每个网络连接,您可以通过将 waitUntil: 'networkidle2'
替换为 waitUntil: 'domcontentloaded'
来加速页面加载,因为此事件通常发生得更早。
await page.goto(url, { waitUntil: 'domcontentloaded' })
可能的 waitUntil
选项是:
load
:触发 load
事件时。domcontentloaded
:触发 DOMContentLoaded
事件时。networkidle0
:当至少 500 毫秒内没有超过 0 个网络连接时。networkidle2
:当至少 500 毫秒的网络连接不超过 2 个时。(2) 如果你正在处理一个单页应用并且你不能依赖 load
和 domcontentloaded
事件,但是网络空闲的会超时,那么你可以尝试 {{3 }},一个键选择器,确保加载所需的 JavaScript 包并且页面正常运行:
page.goto(url) // not await-ed
await page.waitForSelector(keySelector) // ensures the page is functional
免责声明:即使问题不同但答案与waiting for a selector rather than an event
相似