Кукольник - прокрутите вниз, пока вы не сможете больше
Я в ситуации, когда новый контент создается при прокрутке вниз. Новое содержимое имеет определенное имя класса.
Как я могу продолжать прокручивать до тех пор, пока все элементы не загрузятся? Другими словами, я хочу выйти на сцену, где, если я продолжу прокрутку вниз, ничего нового не будет загружено.
Я использовал код для прокрутки вниз, в сочетании с
await page.waitForSelector('.class_name');
Проблема с этим подходом заключается в том, что после того, как все элементы загружены, код продолжает прокручиваться, никаких новых элементов не создается, и в итоге я получаю ошибку тайм-аута.
EDIT: это код
await page.evaluate( () => {
window.scrollBy(0, window.innerHeight);
});
await page.waitForSelector('.class_name');
Ответы
Ответ 1
Дайте этому шанс:
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({
headless: false
});
const page = await browser.newPage();
await page.goto('https://www.yoursite.com');
await page.setViewport({
width: 1200,
height: 800
});
await autoScroll(page);
await page.screenshot({
path: 'yoursite.png',
fullPage: true
});
await browser.close();
})();
async function autoScroll(page){
await page.evaluate(async () => {
await new Promise((resolve, reject) => {
var totalHeight = 0;
var distance = 100;
var timer = setInterval(() => {
var scrollHeight = document.body.scrollHeight;
window.scrollBy(0, distance);
totalHeight += distance;
if(totalHeight >= scrollHeight){
clearInterval(timer);
resolve();
}
}, 100);
});
});
}
Источник: https://github.com/chenxiaochun/blog/issues/38
Ответ 2
Прокрутить вниз до нижней части страницы можно двумя способами:
- используйте scrollIntoView (для прокрутки до той части страницы, которая может создать больше контента внизу) и селекторы (т.е.
document.querySelectorAll('.class_name').length
чтобы проверить, было ли сгенерировано больше контента) - используйте scrollBy (чтобы постепенно прокручивать страницу вниз) и либо setTimeout, либо setInterval (чтобы постепенно проверить, находимся ли мы в нижней части страницы)
Вот реализация, использующая scrollIntoView
и селектор (при условии, что .class_name
- это селектор, в который мы прокручиваемся для получения большего количества контента) в простом JavaScript, который мы можем запустить в браузере:
Способ 1: использовать scrollIntoView и селекторы
const delay = 3000;
const wait = (ms) => new Promise(res => setTimeout(res, ms));
const count = async () => document.querySelectorAll('.class_name').length;
const scrollDown = async () => {
document.querySelector('.class_name:last-child')
.scrollIntoView({ behavior: 'smooth', block: 'end', inline: 'end' });
}
let preCount = 0;
let postCount = 0;
do {
preCount = await count();
await scrollDown();
await wait(delay);
postCount = await count();
} while (postCount > preCount);
await wait(delay);
В этом методе мы сравниваем количество селекторов .class_name
перед прокруткой (preCount
) с прокруткой (postCount
), чтобы убедиться, что мы находимся внизу страницы:
if (postCount > precount) {
// NOT bottom of page
} else {
// bottom of page
}
И вот 2 возможных реализации, использующих либо setTimeout
либо setInterval
с scrollBy
в простом JavaScript, который мы можем запустить в консоли браузера:
Способ 2a: использовать setTimeout с scrollBy
const distance = 100;
const delay = 100;
while (document.scrollingElement.scrollTop + window.innerHeight < document.scrollingElement.scrollHeight) {
document.scrollingElement.scrollBy(0, distance);
await new Promise(resolve => { setTimeout(resolve, delay); });
}
Способ 2b: использовать setInterval с scrollBy
const distance = 100;
const delay = 100;
const timer = setInterval(() => {
document.scrollingElement.scrollBy(0, distance);
if (document.scrollingElement.scrollTop + window.innerHeight >= document.scrollingElement.scrollHeight) {
clearInterval(timer);
}
}, delay);
В этом методе мы сравниваем document.scrollingElement.scrollTop + window.innerHeight
с document.scrollingElement.scrollHeight
чтобы проверить, находимся ли мы в нижней части страницы:
if (document.scrollingElement.scrollTop + window.innerHeight < document.scrollingElement.scrollHeight) {
// NOT bottom of page
} else {
// bottom of page
}
Если какой-либо из приведенных выше JavaScript-кодов прокручивает страницу до самого низа, то мы знаем, что она работает, и мы можем автоматизировать это с помощью Puppeteer.
Вот примеры скриптов Puppeteer Node.js, которые прокрутятся вниз до конца страницы и подождут несколько секунд, прежде чем закрыть браузер.
Метод кукловода 1: использовать scrollIntoView с селектором (.class_name
)
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({
headless: false,
defaultViewport: null,
args: ['--window-size=800,600']
});
const page = await browser.newPage();
await page.goto('https://example.com');
const delay = 3000;
let preCount = 0;
let postCount = 0;
do {
preCount = await getCount(page);
await scrollDown(page);
await page.waitFor(delay);
postCount = await getCount(page);
} while (postCount > preCount);
await page.waitFor(delay);
await browser.close();
})();
async function getCount(page) {
return await page.$$eval('.class_name', a => a.length);
}
async function scrollDown(page) {
await page.$eval('.class_name:last-child', e => {
e.scrollIntoView({ behavior: 'smooth', block: 'end', inline: 'end' });
});
}
Метод кукловода 2a: использовать setTimeout с scrollBy
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({
headless: false,
defaultViewport: null,
args: ['--window-size=800,600']
});
const page = await browser.newPage();
await page.goto('https://example.com');
await scrollToBottom(page);
await page.waitFor(3000);
await browser.close();
})();
async function scrollToBottom(page) {
const distance = 100; // should be less than or equal to window.innerHeight
const delay = 100;
while (await page.evaluate(() => document.scrollingElement.scrollTop + window.innerHeight < document.scrollingElement.scrollHeight)) {
await page.evaluate((y) => { document.scrollingElement.scrollBy(0, y); }, distance);
await page.waitFor(delay);
}
}
Метод кукловода 2b: использовать setInterval с scrollBy
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({
headless: false,
defaultViewport: null,
args: ['--window-size=800,600']
});
const page = await browser.newPage();
await page.goto('https://example.com');
await page.evaluate(scrollToBottom);
await page.waitFor(3000);
await browser.close();
})();
async function scrollToBottom() {
await new Promise(resolve => {
const distance = 100; // should be less than or equal to window.innerHeight
const delay = 100;
const timer = setInterval(() => {
document.scrollingElement.scrollBy(0, distance);
if (document.scrollingElement.scrollTop + window.innerHeight >= document.scrollingElement.scrollHeight) {
clearInterval(timer);
resolve();
}
}, delay);
});
}