#javascript #node.js #parsing #puppeteer
Вопрос:
У меня есть большой массив адресов, которые мне нужно открыть одновременно и получить данные. из-за ограничений сервера я не могу открыть более 10 вкладок одновременно. Как дождаться появления новой бесплатной страницы в сериалеnumbers.forEach? Я понимаю, что могу проверить, есть ли browser.pages () Но как заставить цикл подождать на одной итерации свободной вкладки и не переходить на следующую итерацию?
const puppeteer = require('puppeteer');
let numberOfOpenPages;
let serialNumbers = ['FVFDT2GCQ6L7', 'DLXFG3X2DFJ1', 'FVFDT2GCQ6L7', 'DLXFG3X2DFJ1', 'FVFDT2GCQ6L7', 'DLXFG3X2DFJ1'];
async function processArray() {
const browser = await puppeteer.launch({ headless: true });
serialNumbers.forEach(async (item, i) => {
// new page and then get data
const page = await browser.newPage();
await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36');
await page.goto(`https://support.apple.com/en_US/specs/${item}`);
await page.waitForSelector('.article_link');
await page.click('.article_link');
await page.waitForSelector('#article');
const specs = await page.evaluate(() => {
let article = document.querySelector('h1').innerHTML;
return `${article}`;
});
console.log(specs);
await page.close();
// close browser when all pages is closed
numberOfOpenPages = (await browser.pages()).length;
console.log(numberOfOpenPages);
if (numberOfOpenPages <= 1) {
await browser.close();
}
})
}
processArray()
Комментарии:
1. Я сделал это с помощью setTimeout, но иногда он запускает больше вкладок одновременно, чем нужно. Но ошибка невелика. Если есть более правильные решения, я буду рад узнать
2. разве вы не подумывали об использовании
puppeteer-cluster
? он используется для очень схожих целей
Ответ №1:
Может быть, что-то вроде этого?
const browser = await puppeteer.launch({ headless: true });
const serialNumbers = ['FVFDT2GCQ6L7', 'DLXFG3X2DFJ1', 'FVFDT2GCQ6L7', 'DLXFG3X2DFJ1', 'FVFDT2GCQ6L7', 'DLXFG3X2DFJ1'];
const pageLimit = 10;
for (let i = 0; i < pageLimit; i ) {
processPage(await browser.newPage());
}
async function processPage(page) {
if (serialNumbers.length === 0) {
await page.close();
if ((await browser.pages()).length <= 1) await browser.close();
return;
}
const serialNumber = serialNumbers.shift();
await page.goto(`https://support.apple.com/en_US/specs/${serialNumber}`);
// Process the page...
processPage(page);
}
Ответ №2:
Я сделал это с помощью setTimeout, но иногда он запускает больше вкладок одновременно, чем нужно. Но ошибка невелика.
Если есть более правильные решения, я буду рад узнать
// const { copyFileSync } = require('fs');
const puppeteer = require('puppeteer');
let numberOfOpenPages;
let i = 0;
let serialNumbers = ['FVFDT2GCQ6L7', 'DLXFG3X2DFJ1', 'FVFDT2GCQ6L7', 'DLXFG3X2DFJ1', 'FVFDT2GCQ6L7', 'DLXFG3X2DFJ1', 'FVFDT2GCQ6L7', 'DLXFG3X2DFJ1', 'FVFDT2GCQ6L7'];
async function newPage(serial, browser) {
numberOfOpenPages = (await browser.pages()).length;
console.log(numberOfOpenPages);
if (numberOfOpenPages < 10) {
// new page and then get data
const page = await browser.newPage();
await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36');
await page.goto(`https://support.apple.com/en_US/specs/${serialNumbers[serial]}`);
await page.waitForSelector('.article_link');
await page.click('.article_link');
await page.waitForSelector('#article');
const specs = await page.evaluate(() => {
let article = document.querySelector('h1').innerHTML;
return `${article}`;
});
console.log(specs);
await page.close();
// close browser when all pages is closed
numberOfOpenPages = (await browser.pages()).length;
// console.log(numberOfOpenPages);
// if (numberOfOpenPages <= 1) {
// await browser.close();
// console.log('браузер закрыт!')
// }
} else {
setTimeout(() => {
newPage(serial, browser);
}, 3000); // не ставить меньше 1 сек чтобы не совпадало сразу в один свободный слот
}
}
async function processArray() {
const browser = await puppeteer.launch({ args: ['--no-sandbox', '--disable-setuid-sandbox'], headless: true });
// set your counter to 1
function myLoop () { // create a loop function
setTimeout(function () { // call a 3s setTimeout when the loop is called
console.log('запускаем', i);
newPage(i, browser); // your code here
i ; // increment the counter
if (i < serialNumbers.length) { //if the counter < 10, call the loop function
myLoop(); // .. again which will trigger another
} else console.log('end loop'); // .. setTimeout()
}, 500)
}
myLoop();
}
processArray()