web-dev-qa-db-ja.com

Puppeteers .evaluate()メソッドで関数を渡す方法は?

次のように関数を渡そうとすると、

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

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

私は得ます:

(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.

どうして?それを正しく行う方法は?

ありがとうございました!

€:明確にしましょう:最初にいくつかのDOM要素を見つけ、その関数内で使用したいので、このようにしています。

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

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

同様の問題が操り人形師 issue で議論されています。

問題に対処する方法はいくつかあります。最初のルールは、シンプルにすることです。

機能を評価する

これが最も速い方法です。関数を渡して実行するだけです。

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

事前に関数を公開する

Page.evaluateまたは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;
});

ElementHandleを使用する

page。$(selector)

エレメントハンドルを渡して、.evaluateに変更し、必要に応じて変更を加えることができます。

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

page。$ eval

1つの要素を対象として、必要に応じて変更を加えることができます。

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

秘訣は ドキュメントを読む でシンプルにすることです。

12
Md. Abu Taher

パラメーター付きのパス関数

//手動で追加してウィンドウに公開します

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

//次に、上記で宣言された関数を呼び出します

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

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;

すべてのパラメータを受け取り、関数を文字列に変換します。
次に、ブラウザコンテキストで関数を再作成します。
参照 https://github.com/puppeteer/puppeteer/issues/1474

この関数は次のように使用できます。

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

関数を直接page.evaluate()に渡すことはできませんが、関数をグローバル関数として公開する別の特別なメソッド(_page.exposeFunction_)を呼び出すことができます(ページの属性としても使用できますwindowオブジェクト)なので、page.evaluate()の内部で呼び出すことができます:

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

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

page.exposeFunction()を指定すると、関数がPromiseを返すようになるので、asyncawaitを使用する必要があります。これは、関数が ブラウザー内で実行される ではなく、nodejsアプリケーション内であるために発生します。

  1. exposeFunction()はgoto()の後に機能しません
  2. Puppeteerを使用して、exposeFunction()関数の「ウィンドウ」にアクセスできないのはなぜですか?
  3. evaluateOnNewDocumentとexposedFunctionの使い方?
  4. exposeFunctionはメモリに残りますか?
  5. 人形劇:.evaluate()で変数を渡す
  6. 人形使いが関数を評価する
  7. パラメータ化された関数を文字列としてpage.evaluateに渡すことを許可する
  8. page.exposeFunction()でバインドされた関数は、未処理のプロミス拒否を生成します
  9. 公開された関数queryseldtcorが人形劇で機能しない
  10. Puppeteerを使用して評価する関数を動的に注入するにはどうすればよいですか?
0
user

func();を実行したが、funcが関数ではないため、エラーがスローされます。私はあなたの更新された質問に答えるために私の答えを更新します:

オプション1:ページコンテキストで関数を実行します。

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

オプション2:要素ハンドルを引数として渡す

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