如果页面中不存在 DOM 元素,我该如何移动到下一次迭代?
How can I move to the next iteration if a DOM element is not present in the page?
我想用 puppeteer 测试网页的几个子页面。该网页有一些针对机器人的保护措施。我有一个数组中的 url,我遍历这个数组。
我不知道应该如何重写我的代码,因为我遇到了几个问题:由于机器人保护,页面在实际加载之前向浏览器发送了一些 "fake loaded" 状态真实的内容。因此,我认为我必须等待一些 DOM 个元素。
await page.waitForSelector('div.site__content');
确保内容已加载。 (等待 page.evaluate 由于机器人保护而无法正常工作,它会在第一个 "fake loaded" 标志上触发)。
但是还有另一个问题:如果页面加载不正确(例如由于连接超时),我会遇到未处理的承诺拒绝错误并且迭代停止,程序的执行将停止。
我的目标是,如果在加载页面时出现任何类型的错误,则跳过当前迭代并移至下一个迭代,而不会导致程序崩溃。但我必须保留
await page.waitForSelector
部分也是。
我怎样才能做到这一点?
(async function filterIds() {
let filteredIds = ['url1', 'url2', '...', 'url200'];
const browser = await puppeteer.launch({ headless: false });
const context = await browser.createIncognitoBrowserContext();
const page = await context.newPage();
await tuneUserAgent(page);
for (let id in filteredIds) {
let errorPage = null;
let url = filteredIds[id];
await page.goto(url, { waitUntil: 'load', timeout: 120000 });
await page.waitForSelector('div.site__content'); // to be sure that the content has been loaded
errorPage = await page.evaluate(() => {
return document.querySelector('div.errorpage');
});
if (errorPage != null || errorPage === undefined) {
continue;
}
await page.waitForSelector('div.dialog');
let noGallery = await page.evaluate(() => {
return document.querySelector('div[class="is-not-photo-uploaded-text"]');
});
if (noGallery != null || noGallery === undefined) {
openOrNot = 5;
}
if (openOrNot < 4) {
await openGallery(page);
}
let html = await page.content();
await fs.writeFile(`./saved_items/${filteredIds[id].substring(filteredIds[id].lastIndexOf('/') + 1)}.html`, html, function (err) {
if (err) throw err;
});
await page.waitFor(400);
}
await browser.close();
})();
当 promise 被拒绝且未被捕获时抛出 "unhandled promise rejection error"。如果像您的情况一样在异步代码块内抛出异常,则隐含这种情况。
要捕获抛出的异常,您只需在循环中使用 try..catch
块。
代码示例
for (let id in filteredIds) {
try {
// your code
} catch (err) {
console.log(`Iteration for ${id} failed with error: ${err.message}`);
}
}
您的代码产生的所有错误都应该被此代码捕获,fs.writeFile
中的 if (err) throw err;
除外,因为此回调是异步调用的,因此在您的 try..catch
之外执行堵塞。但是您可以简单地使用新的 fs.promises.writeFile
甚至捕获该错误。
如果出现错误,将调用脚本的 catch (err) { ... }
部分,记录错误消息和发生错误的 id
部分。由于脚本不再崩溃,循环将继续进行下一次迭代。
我想用 puppeteer 测试网页的几个子页面。该网页有一些针对机器人的保护措施。我有一个数组中的 url,我遍历这个数组。
我不知道应该如何重写我的代码,因为我遇到了几个问题:由于机器人保护,页面在实际加载之前向浏览器发送了一些 "fake loaded" 状态真实的内容。因此,我认为我必须等待一些 DOM 个元素。
await page.waitForSelector('div.site__content');
确保内容已加载。 (等待 page.evaluate 由于机器人保护而无法正常工作,它会在第一个 "fake loaded" 标志上触发)。
但是还有另一个问题:如果页面加载不正确(例如由于连接超时),我会遇到未处理的承诺拒绝错误并且迭代停止,程序的执行将停止。
我的目标是,如果在加载页面时出现任何类型的错误,则跳过当前迭代并移至下一个迭代,而不会导致程序崩溃。但我必须保留
await page.waitForSelector
部分也是。 我怎样才能做到这一点?
(async function filterIds() {
let filteredIds = ['url1', 'url2', '...', 'url200'];
const browser = await puppeteer.launch({ headless: false });
const context = await browser.createIncognitoBrowserContext();
const page = await context.newPage();
await tuneUserAgent(page);
for (let id in filteredIds) {
let errorPage = null;
let url = filteredIds[id];
await page.goto(url, { waitUntil: 'load', timeout: 120000 });
await page.waitForSelector('div.site__content'); // to be sure that the content has been loaded
errorPage = await page.evaluate(() => {
return document.querySelector('div.errorpage');
});
if (errorPage != null || errorPage === undefined) {
continue;
}
await page.waitForSelector('div.dialog');
let noGallery = await page.evaluate(() => {
return document.querySelector('div[class="is-not-photo-uploaded-text"]');
});
if (noGallery != null || noGallery === undefined) {
openOrNot = 5;
}
if (openOrNot < 4) {
await openGallery(page);
}
let html = await page.content();
await fs.writeFile(`./saved_items/${filteredIds[id].substring(filteredIds[id].lastIndexOf('/') + 1)}.html`, html, function (err) {
if (err) throw err;
});
await page.waitFor(400);
}
await browser.close();
})();
当 promise 被拒绝且未被捕获时抛出 "unhandled promise rejection error"。如果像您的情况一样在异步代码块内抛出异常,则隐含这种情况。
要捕获抛出的异常,您只需在循环中使用 try..catch
块。
代码示例
for (let id in filteredIds) {
try {
// your code
} catch (err) {
console.log(`Iteration for ${id} failed with error: ${err.message}`);
}
}
您的代码产生的所有错误都应该被此代码捕获,fs.writeFile
中的 if (err) throw err;
除外,因为此回调是异步调用的,因此在您的 try..catch
之外执行堵塞。但是您可以简单地使用新的 fs.promises.writeFile
甚至捕获该错误。
如果出现错误,将调用脚本的 catch (err) { ... }
部分,记录错误消息和发生错误的 id
部分。由于脚本不再崩溃,循环将继续进行下一次迭代。