3 votes

marionnettiste identifiant le contenu de l'élément après l'événement de clic

J'essaie d'extraire un élément particulier d'une page après avoir saisi une requête et cliqué sur un bouton. La page ne navigue pas vers une nouvelle URL : elle renvoie simplement un nouveau contenu HTML que je dois extraire.

Cela décrit la distance que j'ai parcourue :

const puppeteer = require('puppeteer');

function timeout(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
};

const input_val = 'some query text';

(async() => {
    const browser = await puppeteer.launch()
    const page = await browser.newPage()
    await page.goto('http://target.com', { waitUntil: 'networkidle2' })
    await page.waitFor('input[name=query]')

    await page.evaluate((input_val) => {
      document.querySelector('input[name=query]').value = input_val;
      document.querySelector('.Button').click();
    }, input_val)

    // Now I want to console.log the <strong> tag fields 
    // innerText (will be 0-3 matching elements).
    // The lines below describe in non-puppeteer what 
    // I need to do. But this has no effect.

    const strongs = await page.$$('strong')
    for(var i=0; i<strongs.length; i++) {
      console.log(strongs[i].innerText);
    }

    await timeout(2000)
    await page.screenshot({path: 'example.png'}) // this renders results page ok

    browser.close();
})();

Ainsi, la requête d'entrée est correctement saisie, le clic du bouton est déclenché et la capture d'écran montre que la page Web a répondu comme prévu. Je n'arrive pas à trouver comment extraire et rapporter les éléments pertinents.

J'ai essayé de me faire une idée de l'ensemble du paradigme asynchrone/attente, mais je suis encore assez novice en la matière. Toute aide est la bienvenue.


Edit - Erreur de la méthode Vaviloff :

(node:67405) UnhandledPromiseRejectionWarning: Error: Protocol error (Runtime.callFunctionOn): Cannot find context with specified id undefined
    at Promise (/Users/user/node_modules/puppeteer/lib/Connection.js:200:56)
    at new Promise (<anonymous>)
    at CDPSession.send (/Users/user/node_modules/puppeteer/lib/Connection.js:199:12)
    at ExecutionContext.evaluateHandle (/Users/user/node_modules/puppeteer/lib/ExecutionContext.js:79:75)
    at ExecutionContext.evaluate (/Users/user/node_modules/puppeteer/lib/ExecutionContext.js:46:31)
    at Frame.evaluate (/Users/user/node_modules/puppeteer/lib/FrameManager.js:326:20)
    at <anonymous>
    at process._tickCallback (internal/process/next_tick.js:160:7)
(node:67405) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:67405) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

3voto

Vaviloff Points 7930

Il existe un utilitaire d'aide utile page.$$eval :

Cette méthode fonctionne Array.from(document.querySelectorAll(selector)) dans la page et le passe comme premier argument à pageFunction.

Puisqu'elle transmet un tableau à la fonction évaluée, nous pouvons utiliser la méthode suivante .map() sur celui-ci pour extraire un attribut nécessaire :

const strongs = await page.$$eval('strong', items => items.map( item => item.innerText));

Mise à jour Voici un script complet et fonctionnel pour le test :

const puppeteer = require('puppeteer');

const input_val = '[puppeteer]';
const items_selector = '.question-hyperlink';

(async() => {

    const browser = await puppeteer.launch({
        headless: false,
    })
    const page = await browser.newPage()

    await page.goto('https://stackoverflow.com/', { waitUntil: 'networkidle2' })
    await page.waitFor('input[name=q]')
    await page.type('input[name=q]', input_val + '\r');
    await page.waitForNavigation();

    const items = await page.$$eval(items_selector, items => items.map( item => item.innerText));

    console.log(items);

    await browser.close();
})();

Mise à jour 2
Une version modifiée du script pour la sandbox à https://diplodata.shinyapps.io/puppeteer-test/

const puppeteer = require('puppeteer');
const input_val = 'puppeteer';

(async() => {

    const browser = await puppeteer.launch({
        headless: false,
    })
    const page = await browser.newPage()

    await page.goto('https://diplodata.shinyapps.io/puppeteer-test/', { waitUntil: 'networkidle2' })
    await page.waitFor('#query')
    await page.type('#query', input_val);
    await page.click('#go');
    await page.waitFor(500);
    const items = await page.$$eval('strong', items => items.map( item => item.innerText));

    console.log(items);

    await browser.close();
})();

Produit le résultat suivant :

[ 'On click below should read:', '<query>', 'puppeteer ' ]

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X