#javascript #node.js #twitter #web-scraping #puppeteer
#javascript #node.js #Twitter #очистка веб-страниц #кукловод
Вопрос:
У меня возникли проблемы с очисткой всех URL-адресов твитов на временной шкале пользователя с помощью puppeteer.
С помощью puppeteer предполагается, что скрипт будет прокручивать временную шкалу вниз на каждой итерации цикла while в scrollToEnd
функции, пока она не достигнет дна. Чтобы отслеживать прогресс, я заставил скрипт выводить значение previousHeight
переменной, которая является текущей scrollheight
из document.body
, вычисляемой каждый раз перед выполнением прокрутки.
Однако прокрутка прекращается, как только выходное значение становится 285,834. Что вызывает недоумение, так это то, что скрипт не выходит из цикла while и page.waitForFunction
метод не выдает ошибку тайм-аута.
Как я должен переписать scrollToEnd
функцию или любую другую часть скрипта, чтобы функция завершилась должным образом?
Вот фрагмент моего кода. Для краткости не относящиеся к делу функции исключены.
const puppeteer = require('puppeteer');
var UserUrls = ['https://twitter.com/someuser'];
// more functions here
async function scrollToEnd(
page,
ScrollDelay = 1000
) {
try {
let previousHeight = 0;
let notEnd = await page.waitForFunction(`document.body.scrollHeight > ${previousHeight}`);
while (notEnd) {
previousHeight = await page.evaluate('document.body.scrollHeight');
await page.evaluate('window.scrollBy(0, document.body.scrollHeight)');
await page.waitFor(ScrollDelay);
notEnd = await page.waitForFunction(`document.body.scrollHeight > ${previousHeight}`);
console.log(previousHeight)
};
return;
} catch (e) {
return;
};
};
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
var tweetUrls = [];
for (let UserUrl of UserUrls) {
await page.goto(UserUrl);
await page.evaluate((async () => {
await scrollToEnd(page);
})());
await page.screenshot({ path: 'PageEnd.png' });
tweetUrls = await getTweetUrls(page, extractItems, 100);
};
await browser.close();
console.log(tweetUrls);
})();
Ответ №1:
Не могли бы вы попробовать один из этих двух подходов? Этот скрипт пытается прокрутить страницу вниз, сравнивая высоту прокрутки (как вы делали) или ожидая, пока станет видимым элемент, обозначающий конец потока. Вся логика прокрутки помещается внутри функций, оцениваемых в контексте браузера. Обе функции возвращают количество твитов на всю страницу, чтобы сравнить результат с количеством твитов пользователя, объявленным в верхней части временной шкалы. Кроме того, я изменил задержку на 3 секунды для первого подхода, поскольку иногда кажется, что 1 сек — это слишком мало для изменения высоты прокрутки.
'use strict';
const puppeteer = require('puppeteer');
(async function main() {
try {
const browser = await puppeteer.launch({ headless: false });
const [page] = await browser.pages();
await page.goto('https://twitter.com/GHchangelog');
const data1 = await page.evaluate(scrollToBottomByMaxHeight);
console.log(`Tweets: ${data1}`);
await page.goto('https://twitter.com/GHchangelog');
const data2 = await page.evaluate(scrollToBottomByEndElement);
console.log(`Tweets: ${data2}`);
// await browser.close();
} catch (err) {
console.error(err);
}
})();
async function scrollToBottomByMaxHeight() {
try {
let previousHeight = 0;
let currentHeight = document.scrollingElement.scrollHeight;
while (previousHeight < currentHeight) {
previousHeight = document.scrollingElement.scrollHeight;
window.scrollBy(0, previousHeight);
await new Promise((resolve) => { setTimeout(resolve, 3000); });
currentHeight = document.scrollingElement.scrollHeight;
}
return document.querySelectorAll('a.js-permalink').length;
} catch (err) {
return err;
}
}
async function scrollToBottomByEndElement() {
try {
const endElement = document.querySelector('div.stream-end');
while (endElement.clientHeight === 0) {
window.scrollBy(0, document.scrollingElement.scrollHeight);
await new Promise((resolve) => { setTimeout(resolve, 1000); });
}
return document.querySelectorAll('a.js-permalink').length;
} catch (err) {
return err;
}
}
Комментарии:
1.
scrollToBottomByMaxHeight
функция вернула 40, в то время какscrollToBottomByEndElement
функция вернула 186. Прав ли я, заключая, что последний подход является более надежным, посколькуclientHeight
должен оставаться равным 0, покаdiv.stream-end
элемент не будет загружен?2. @figment У меня постоянно было 186 от обоих, но, похоже, первый подход более хрупкий, поскольку зависит от скорости реагирования сети (вы можете попробовать увеличить задержку до 10 секунд, чтобы посмотреть, изменится ли что-то). Так что я думаю, да, второй подход более надежный.
3. @figment
div.stream-end
уже загружен в начальном состоянии страницы, он просто скрыт до достижения конца потока, а до тех пор егоclientHeight
значение равно 0.