web-dev-qa-db-fra.com

Comment passer une fonction dans la méthode Puppeteers .evaluate ()?

Chaque fois que j'essaie de passer une fonction, comme ceci:

var myFunc = function() { console.log("lol"); };

await page.evaluate(func => {
 func();
 return true;
}, myFunc);

Je reçois:

(node:13108) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Evaluation failed: TypeError: func is not a function
at func (<anonymous>:9:9)
(node:13108) 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.

Pourquoi? Comment le faire correctement?

Je vous remercie!

€: permettez-moi de clarifier: je le fais de cette façon parce que je veux d'abord trouver certains éléments DOM et les utiliser à l'intérieur de cette fonction, plus comme ceci (simplifié):

var myFunc = function(element) { element.innerHTML = "baz" };

await page.evaluate(func => {
  var foo = document.querySelector('.bar');
  func(foo);
  return true;
}, myFunc);
12
chitzui

Des problèmes similaires ont été discutés dans un marionnettiste issue .

Il existe plusieurs façons de résoudre votre problème. La première règle est de rester simple.

Évaluer la fonction

C'est le moyen le plus rapide de faire les choses, vous pouvez simplement passer la fonction et l'exécuter.

await page.evaluate(() => {
  var myFunc = function(element) { element.innerHTML = "baz" };
  var foo = document.querySelector('.bar');
  myFunc(foo);
  return true;
});

Exposez la fonction au préalable

Vous pouvez exposer la fonction au préalable à l'aide d'un page.evaluate ou d'un page.addScriptTag

// add it manually and expose to window
await page.evaluate(() => {
  window.myFunc = function(element) { element.innerHTML = "baz" };
});

// add some scripts
await page.addScriptTag({path: "myFunc.js"});

// Now I can evaluate as many times as I want
await page.evaluate(() => {
  var foo = document.querySelector('.bar');
  myFunc(foo);
  return true;
});

Utiliser ElementHandle

page. $ (sélecteur)

Vous pouvez passer une poignée d'élément pour .évaluer et apporter des modifications comme bon vous semble.

const bodyHandle = await page.$('body');
const html = await page.evaluate(body => body.innerHTML, bodyHandle);

page. $ eval

Vous pouvez cibler un élément et apporter des modifications à votre guise.

const html = await page.$eval('.awesomeSelector', e => {
e.outerHTML = "whatever"
});

L'astuce consiste à lire la documentation et à rester simple.

12
Md. Abu Taher

Passer la fonction avec le paramètre

// l'ajouter manuellement et l'exposer à la fenêtre

 await page.evaluate(() => {
      window.myFunc = function(element) { element.innerHTML = "baz" };
    });

// puis appeler la fonction déclarée ci-dessus

 await page.evaluate((param) => {
         myFunc (param);
    }, param);
2
vnguyen

Création d'une fonction d'assistance qui enveloppe page.evaluate:

const evaluate = (page, ...params) => browserFn => {
    const fnIndexes = [];
    params = params.map((param, i) => {
        if (typeof param === "function") {
            fnIndexes.Push(i);
            return param.toString();
        }
        return param;
    });
    return page.evaluate(
        (fnIndexes, browserFnStr, ...params) => {
            for (let i = 0; i < fnIndexes.length; i++) {
                params[fnIndexes[i]] = new Function(
                    " return (" + params[fnIndexes[i]] + ").apply(null, arguments)"
                );
            }
            browserFn = new Function(
                " return (" + browserFnStr + ").apply(null, arguments)"
            );
            return browserFn(...params);
        },
        fnIndexes,
        browserFn.toString(),
        ...params
    );
};

export default evaluate;

Prend tous les paramètres et convertit les fonctions en chaîne.
Recrée ensuite les fonctions dans le contexte du navigateur.
Voir https://github.com/puppeteer/puppeteer/issues/1474

Vous pouvez utiliser cette fonction comme ceci:

const featuredItems = await evaluate(page, _getTile, selector)((get, s) => {
    const items = Array.from(document.querySelectorAll(s));
    return items.map(node => get(node));
});
0
Ryan Soury

Vous ne pouvez pas passer une fonction directement dans page.evaluate(), mais vous pouvez appeler une autre méthode spéciale (page.exposeFunction), Qui expose votre fonction en tant que fonction globale (également disponible en tant qu'attribut de votre page window object), vous pouvez donc l'appeler lorsque vous êtes à l'intérieur de page.evaluate():

var myFunc = function() { console.log("lol"); };
await page.exposeFunction("myFunc", myFunc);

await page.evaluate(async () => {
   await func();
   return true;
});

N'oubliez pas que page.exposeFunction() fera que votre fonction retournera un Promise, puis, vous devrez utiliser async et await. Cela se produit car votre fonction ne sera pas exécutée dans votre navigateur , mais dans votre application nodejs.

  1. exposeFunction () ne fonctionne pas après goto ()
  2. Pourquoi ne puis-je pas accéder à 'window' dans une fonction exposeFunction () avec Puppeteer?
  3. Comment utiliser assessOnNewDocument et exposeFunction?
  4. exposeFunction reste en mémoire?
  5. Marionnettiste: passer la variable dans .evaluate ()
  6. fonction d'évaluation des marionnettistes
  7. permet de passer une fonction paramétrée sous forme de chaîne à page.evaluate
  8. Les fonctions liées à page.exposeFunction () produisent des rejets de promesse non gérés
  9. la fonction exposée queryseldtcor ne fonctionne pas dans le marionnettiste
  10. Comment puis-je injecter dynamiquement des fonctions pour évaluer à l'aide de Puppeteer?
0
user

L'erreur est renvoyée car vous exécutez func(); mais func n'est pas une fonction. Je mets à jour ma réponse pour répondre à votre question mise à jour:

Option 1: exécutez votre fonction dans le contexte de la page:

var myFunc = function(element) { element.innerHTML = "baz" };
await page.evaluate(func => {
  var foo = document.querySelector('.bar');
  myFunc(foo);
  return true;
});

Option 2: passer le descripteur d'élément comme arguments

const myFunc = (element) => { 
    innerHTML = "baz";
    return true;
}
const barHandle = await page.$('.bar');
const result = await page.evaluate(myFunc, barHandle);
await barHandle.dispose();

"

0
Giang Nguyen