web-dev-qa-db-fra.com

Comment faire défiler vers le bas avec Phantomjs pour charger du contenu dynamique

J'essaie de gratter les liens d'une page qui génère du contenu dynamiquement lorsque l'utilisateur défile vers le bas (défilement infini). J'ai essayé de faire différentes choses avec Phantomjs mais je n'ai pas réussi à rassembler des liens au-delà de la première page. Disons que l'élément en bas qui charge le contenu a la classe .has-more-items. Il est disponible jusqu'à ce que le contenu final soit chargé pendant le défilement, puis devient indisponible dans DOM (affichage: aucun). Voici les choses que j'ai essayées-

  • Définition de viewportSize à une grande hauteur juste après var page = require('webpage').create();

page.viewportSize = {largeur: 1600, hauteur: 10000,};

  • Utiliser page.scrollPosition = { top: 10000, left: 0 } À l'intérieur de page.open Mais sans effet comme-
page.open('http://example.com/?q=houston', function(status) {
   if (status == "success") {
      page.scrollPosition = { top: 10000, left: 0 };  
   }
});
  • J'ai également essayé de le mettre dans la fonction page.evaluate Mais cela donne

Erreur de référence: impossible de trouver la page des variables

  • Essayé en utilisant jQuery et le code JS dans page.evaluate Et page.open Mais en vain

$ ("html, body"). animate ({scrollTop: $ (document) .height ()}, 10, function () {//console.log('check for execution ');});

tel quel et aussi à l'intérieur de document.ready. De même pour le code JS-

window.scrollBy(0,10000)

tel quel et aussi à l'intérieur window.onload

Je suis vraiment frappé dessus depuis 2 jours maintenant et je n'arrive pas à trouver un moyen. Toute aide ou indice serait apprécié.

Mise à jour

J'ai trouvé un morceau de code utile sur https://groups.google.com/forum/?fromgroups=#!topic/phantomjs/8LrWRW8ZrA

var hitRockBottom = false; while (!hitRockBottom) {
    // Scroll the page (not sure if this is the best way to do so...)
    page.scrollPosition = { top: page.scrollPosition + 1000, left: 0 };

    // Check if we've hit the bottom
    hitRockBottom = page.evaluate(function() {
        return document.querySelector(".has-more-items") === null;
    }); }

.has-more-items Est la classe d'élément à laquelle je veux accéder qui est disponible au bas de la page au départ et pendant que nous faisons défiler vers le bas, elle descend plus bas jusqu'à ce que toutes les données soient chargées puis deviennent indisponibles.

Cependant, lorsque j'ai testé, il est clair qu'il fonctionne en boucles infinies sans défilement vers le bas (je rend les images pour vérifier). J'ai également essayé de remplacer page.scrollPosition = { top: page.scrollPosition + 1000, left: 0 }; Par des codes ci-dessous (un à la fois)

window.document.body.scrollTop = '1000';
location.href = ".has-more-items";
page.scrollPosition = { top: page.scrollPosition + 1000, left: 0 };
document.location.href=".has-more-items";

Mais rien ne semble fonctionner.

46
Puneet Saini

J'ai trouvé un moyen de le faire et j'ai essayé de m'adapter à votre situation. Je n'ai pas testé la meilleure façon de trouver le bas de la page parce que j'avais un contexte différent, mais vérifiez-le. Le problème est que vous devez attendre un peu que la page se charge et que javascript fonctionne de manière asynchrone, vous devez donc utiliser setInterval ou setTimeout ( voir ).

page.open('http://example.com/?q=houston', function () {

  // Checks for bottom div and scrolls down from time to time
  window.setInterval(function() {
      // Checks if there is a div with class=".has-more-items" 
      // (not sure if this is the best way of doing it)
      var count = page.content.match(/class=".has-more-items"/g);

      if(count === null) { // Didn't find
        page.evaluate(function() {
          // Scrolls to the bottom of page
          window.document.body.scrollTop = document.body.scrollHeight;
        });
      }
      else { // Found
        // Do what you want
        ...
        phantom.exit();
      }
  }, 500); // Number of milliseconds to wait between scrolls

});
45
João Pesce

Je sais qu'il a été répondu il y a longtemps, mais j'ai également trouvé une solution à mon scénario spécifique. Le résultat est un morceau de javascript qui défile vers le bas de la page. Il est optimisé pour réduire le temps d'attente.

Il n'est pas écrit pour PhantomJS par défaut, il faudra donc le modifier. Cependant, pour un débutant ou quelqu'un qui n'a pas d'accès root, un Iframe avec du javascript injecté (exécutez Google Chrome avec le paramètre --disable-javascript) est une bonne méthode alternative pour gratter un plus petit ensemble de pages ajax. Le principal avantage est qu'il est facilement débogable, car vous avez un aperçu visuel de ce qui se passe avec votre grattoir.

function ScrollForAjax () {

    scrollintervals = 50;
    scrollmaxtime = 1000;

    if(typeof(scrolltime)=="undefined"){
        scrolltime = 0;
    }

    scrolldocheight1 = $(iframeselector).contents().find("body").height();

    $("body").scrollTop(scrolldocheight1);
    setTimeout(function(){

        scrolldocheight2 = $("body").height();

        if(scrolltime===scrollmaxtime || scrolltime>scrollmaxtime){
            scrolltime = 0;
            $("body").scrollTop(0);
            ScrapeCurrentPage(iframeselector);
        }

        else if(scrolldocheight2>scrolldocheight1){
            scrolltime = 0;
            ScrollForAjax (iframeselector);
        }

        else if(scrolldocheight1>=scrolldocheight2){
            ScrollForAjax (iframeselector);
        }

    },scrollintervals);

    scrolltime += scrollintervals;
}

scrollmaxtime est une variable de temporisation. J'espère que cela est utile à quelqu'un :)

La solution "correcte" n'a pas fonctionné pour moi. Et, d'après ce que j'ai lu, CasperJS n'utilise pas window (mais je peux me tromper à ce sujet), ce qui me fait douter que window fonctionne.

Ce qui suit fonctionne pour moi dans la console Firefox/Chrome; mais, ne fonctionne pas dans CasperJS (dans la fonction casper.evaluate).

$(document).scrollTop($(document).height());

Ce qui a fonctionné pour moi dans CasperJS était:

casper.scrollToBottom();
casper.wait(1000, function waitCb() {
  casper.capture("loadedContent.png");
});

Ce qui a également fonctionné lors du déplacement de casper.capture Dans la fonction then de Casper.

Cependant, la solution ci-dessus ne fonctionnera pas sur certains sites comme Twitter; jQuery semble rompre la fonction casper.scrollToBottom(), et j'ai dû supprimer la référence clientScripts à jQuery lorsque je travaillais dans Twitter.

var casper = require('casper').create({
    clientScripts: [
       // 'jquery.js'
    ]
});

Certains sites Web (par exemple BoingBoing.net) semblent fonctionner correctement avec jQuery et CasperJS scrollToBottom(). Je ne sais pas pourquoi certains sites fonctionnent et d'autres non.

2
tfmontague

L'extrait de code ci-dessous fonctionne très bien pour Pinterest. J'ai beaucoup cherché pour gratter pinterest sans phantomjs mais il est impossible de trouver le lien de déclenchement de défilement infini. Je pense que le code ci-dessous aidera une autre page Web à défilement infini à gratter.

page.open(pageUrl).then(function (status) {
              var count = 0;
                // Scrolls to the bottom of page
              function scroll2btm(){
                if(count <500) {
                  page.evaluate(function(limit) {
                    window.scrollTo(0, document.body.scrollHeight || document.documentElement.scrollHeight);
                    return document.getElementsByClassName('pinWrapper').length; //use desired contents(eg. pin) selector for count presence number
                  }).then(function(c){
                    count=c;
                    console.log(count)//print no of content found to check
                  });
                  setTimeout(scroll2btm,3000);
                }
              else { // required number of item found
                }
              }
              scroll2btm();
            })
1
Suben Saha