web-dev-qa-db-fra.com

Marionnettiste - faites défiler jusqu'à ce que vous ne puissiez plus

Je suis dans une situation où un nouveau contenu est créé lorsque je fais défiler vers le bas. Le nouveau contenu a un nom de classe spécifique.

Comment puis-je continuer à faire défiler l'écran jusqu'à ce que tous les éléments soient chargés? En d'autres termes, je veux atteindre le stade où, si je continue à faire défiler l'écran, rien de nouveau ne se charge.

J'utilisais du code pour faire défiler, couplé avec un

await page.waitForSelector('.class_name');

Le problème avec cette approche est qu’après que tous les éléments ont été chargés, le code continue à défiler, aucun nouvel élément n’est créé et j’obtiens finalement une erreur de dépassement de délai.

EDIT: Ceci est le code

await page.evaluate( () => {
                window.scrollBy(0, window.innerHeight);
            });
await page.waitForSelector('.class_name');
17
user1584421

Donnez un coup de feu:

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);
        });
    });
}

Source: https://github.com/chenxiaochun/blog/issues/38

32
Cory

Le défilement vers le bas de la page peut être effectué de deux manières:

  1. utilisez scrollIntoView (pour accéder à la partie de la page pouvant créer davantage de contenu en bas) et des sélecteurs (c'est-à-dire, document.querySelectorAll('.class_name').length pour vérifier si davantage de contenu a été généré)
  2. utilisez scrollBy (pour faire défiler la page de manière incrémentielle) et soit setTimeout ou setInterval (pour vérifier de manière incrémentielle si nous sommes au bas de la page)

Voici une implémentation utilisant scrollIntoView et un sélecteur (en supposant que .class_name est le sélecteur dans lequel nous faisons défiler pour plus de contenu) en JavaScript simple que nous pouvons exécuter dans le navigateur:

Méthode 1: utilisez scrollIntoView et les sélecteurs

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);

Dans cette méthode, nous comparons le nombre de .class_name sélecteurs avant le défilement (preCount) vs après le défilement (postCount) pour vérifier si nous sommes au bas de la page:

if (postCount > precount) {
  // NOT bottom of page
} else {
  // bottom of page
}

Et voici 2 implémentations possibles utilisant setTimeout ou setInterval avec scrollBy en JavaScript simple que nous pouvons exécuter dans la console du navigateur:

Méthode 2a: utilisez setTimeout avec 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); });
}

Méthode 2b: utilisez setInterval avec 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);

Dans cette méthode, nous comparons document.scrollingElement.scrollTop + window.innerHeight avec document.scrollingElement.scrollHeight pour vérifier si nous sommes au bas de la page:

if (document.scrollingElement.scrollTop + window.innerHeight < document.scrollingElement.scrollHeight) {
  // NOT bottom of page
} else {
  // bottom of page
}

Si l’un des codes JavaScript ci-dessus fait défiler la page de haut en bas, nous savons que cela fonctionne et nous pouvons l’automatiser à l’aide de Puppeteer.

Voici les exemples de scripts de Puppeteer Node.js qui défileront au bas de la page et attendront quelques secondes avant de fermer le navigateur.

Puppeteer Méthode 1: utilisez scrollIntoView avec le sélecteur (.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' });
  });
}

Méthode Marionnettiste 2a: utilisez setTimeout avec 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);
  }
}

Méthode Marionnettiste 2b: utilisez setInterval avec 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);
  });
}
3
kimbaudi