1
votes

Page.evaluate () ne s'exécutera pas dans une chaîne Promise

Je viens de commencer à utiliser Puppeteer. Essayer d'analyser une page mais la méthode d'évaluation ne fonctionnera pas.

Browser Created
Creating Blank Page
Page Created
Visiting URL
Website Loaded
undefined
Done! Exiting

Résultat:

var Browser
var Page
var Result
puppeteer.launch()
  .then(function (browser) {
    console.log('Browser Created\nCreating Blank Page')
    Browser = browser
    return Browser.newPage()
  })
  .then(function (page) {
    console.log('Page Created\nVisiting URL')
    Page = page
    return Page.goto(URL)
  })
  .then(function (resp) {
    console.log('Website Loaded')
    return Page.evaluate(function () {
      // Completely Sync Stuff
      console.log('Evaluating Selectors')
      var myElems = document.getElementsByClassName('challenge-type light')
      Result = myElems
    })
  })
  .then(function (val) {
    console.log(Result)
    console.log('Done! Exiting')
    Browser.close()
    process.exit()
  })
  .catch(function (err) {
    Browser.close()
    console.log(err)
    process.exit(1)
  })

Quelle pourrait être l'erreur? Je préférerais une solution sans async / await.

EDIT: "Evaluating Selectors" n'est pas non plus connecté à la console, donc le code n'y parvient jamais, c'est ma préoccupation.


4 commentaires

êtes-vous sûr que document.getElementsByClassName ('challenge-type light') renvoie réellement un résultat?


N'utilisez pas ces variables globales Navigateur , Page , Résultat . Il existe de bien meilleures façons d'accéder aux résultats des promesses précédentes dans une chaîne .then () !


La dernière fois que j'ai vérifié, page.evaluate ne prend pas en charge les fermetures. Essayez de ne pas attribuer à Résultat , à la place renvoyez une valeur.


... renvoie une valeur sérialisable . Si la fonction passée à page.evaluate () renvoie une valeur non sérialisable, alors page.evaluate () se résout en undefined. Ref


3 Réponses :


0
votes

Je revérifierais que

document.getElementsByClassName('challenge-type light') 

renvoie un résultat.

Je crois que vous utilisez un navigateur sans tête, donc parfois les éléments peuvent ne pas se charger comme vous vous en doutez .


1 commentaires

Je comprends, mais si vous remarquez, "Evaluating Selectors" n'est pas non plus connecté à la console. Il n'exécute jamais ce code.



0
votes

Les choses fonctionnent enfin.

  1. La console à l'intérieur de l'évaluation sera dans le contexte de la page, c'est donc la page de la console de chrome.
  2. Nous devons renvoyer quelque chose de la fonction d'évaluation. Les éléments DOM ne seront pas retournés tels quels car ils perdent leur contexte en dehors de l'évaluation.

Cela a fonctionné:

.then(function (resp) {
    console.log('Website Loaded')
    return Page.evaluate(function () {
      return document.querySelector('.cover-heading').innerText
    })
  })


0 commentaires

0
votes

OK, vous êtes sur le bon chemin mais vous avez quelques problèmes.

De votre propre réponse: vous avez noté que les journaux de la console exécutés dans le contexte de la page lorsqu'ils sont exécutés dans le evaluer méthode. Vous avez raison de dire cela, mais vous avez tort de dire que vous ne pouvez pas retourner d'éléments DOM à partir de la méthode evaluer . Vous pouvez juste que votre code n'est pas tout à fait correct.

Voici donc ce que vous avez:

.then(function () {
  return Page.evaluate(function () {
    // Return the array of elements from inside the evaluate method
    return document.getElementsByClassName('challenge-type light')
  });
})
.then(function (elements) {
  console.log(elements) // Will be your array of elements
});

Cela ne fonctionnera pas puisque vous essayez pour affecter myElems à la variable Result dans la méthode evaluer . La méthode evaluer est exécutée dans le navigateur. Il n'a aucune idée qu'une variable Result existe dans votre script marionnettiste . C'est pourquoi votre variable est sortie comme undefined à la fin.

Pour résoudre ce problème, procédez comme suit:

.then(function (resp) {
  console.log('Website Loaded')
  return Page.evaluate(function () {
    // Completely Sync Stuff
    console.log('Evaluating Selectors')
    var myElems = document.getElementsByClassName('challenge-type light')
    Result = myElems
  })
})
.then(function (val) {
  console.log(Result)
  console.log('Done! Exiting')
});

J'espère cela aide!


2 commentaires

J'ai fait cela et j'ai obtenu un objet vide pour un sélecteur connu. J'ai essayé exactement ce que vous avez écrit avant d'écrire ma réponse, alors que je ne retournais pas le texte intérieur et que je ne comptais pas sur la prochaine promesse pour le faire, mais tout ce que cela pouvait jamais obtenir était un objet vide. La requête de sélection a renvoyé le type HTMLDivElement qui n'avait aucune signification ailleurs en dehors de l'évaluation, c'est pourquoi j'ai conclu cela. N'hésitez pas à me corriger si je me trompe.


OK si vous obtenez un objet vide, je suggérerais que les noms de classe que vous utilisez dans getElementsByClassName ne correspondent à aucun élément de l'interface utilisateur. L'autre chose déroutante est que votre question d'origine tente de renvoyer la liste de tous les éléments avec les noms de classe que vous avez spécifiés, mais la réponse que vous avez publiée utilise un nom de classe pas dans votre message d'origine et renvoie également le innerText qui, encore une fois, est quelque chose de nouveau que vous avez introduit.