web-dev-qa-db-ja.com

Puppeteerを使用して、exposeFunction()関数の「ウィンドウ」にアクセスできないのはなぜですか?

私は exposeFunction() を使用してヘッドレスChrome内で何かを実行する非常に単純な Puppeteer スクリプトを持っています。

_(async function(){

    var log = console.log.bind(console),
        puppeteer = require('puppeteer');


    const browser = await puppeteer.launch();
    const page = await browser.newPage();

    var functionToInject = function(){
        return window.navigator.appName;
    }

    await page.exposeFunction('functionToInject', functionToInject);

    var data = await page.evaluate(async function(){
        console.log('woo I run inside a browser')
        return await functionToInject();
    });

    console.log(data);

    await browser.close();

})()
_

これは失敗します:

_ReferenceError: window is not defined
_

注入された関数を指します。ヘッドレスChrome内でwindowにアクセスするにはどうすればよいですか?

代わりにevaluate()を実行できることはわかっていますが、これは動的に渡す関数では機能しません。

_(async function(){

    var log = console.log.bind(console),
        puppeteer = require('puppeteer');

    const browser = await puppeteer.launch();
    const page = await browser.newPage();

    var data = await page.evaluate(async function(){
        console.log('woo I run inside a browser')
        return window.navigator.appName;
    });

    console.log(data);

    await browser.close();

})()
_
9
mikemaccana

evaluate関数

evaluateを使用して動的スクリプトを渡すことができます。

(async function(){
    var puppeteer = require('puppeteer');
    const browser = await puppeteer.launch();
    const page = await browser.newPage();

    var functionToInject = function(){
        return window.navigator.appName;
    }

    var data = await page.evaluate(functionToInject); // <-- Just pass the function
    console.log(data); // outputs: Netscape

    await browser.close();
})()

addScriptTagおよびreadFileSync

関数を別のファイルに保存し、addScriptTagを使用して関数を使用できます。

await page.addScriptTag({path: 'my-script.js'});

またはevaluate with readFileSync

await page.evaluate(fs.readFileSync(filePath, 'utf8'));

または、パラメータ化された関数を文字列としてpage.evaluateに渡します。

await page.evaluate(new Function('foo', 'console.log(foo);'), {foo: 'bar'});

新しい関数を動的に作成する

これに対処するために他の方法が必要ですか? runnable関数:Dにしてみませんか?

function runnable(fn) {
  return new Function("arguments", `return ${fn.toString()}(arguments)`);
}

上記は、指定された引数で新しい関数を作成します。必要な関数を渡すことができます。

windowを指定した次の関数と引数

function functionToInject() {
  return window.location.href;
};

約束も完璧に機能し、

function functionToInject() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(window.location.href);
    }, 5000);
  });
}

引数付きで、

async function functionToInject(someargs) {
  return someargs; // {bar: 'foo'}
};

evaluateを使用して目的の関数を呼び出します。

var data = await page.evaluate(runnable(functionToInject), {bar: "foo"});
console.log(data); // shows the location
7
Md. Abu Taher

exposeFunction()は、このジョブに適したツールではありません。

Puppeteer docs から

page.exposeFunction(name、puppeteerFunction)

puppeteerFunction Puppeteerのコンテキストと呼ばれるコールバック関数。

「人形遣いの文脈で」は少し曖昧ですが、evaluate()のドキュメントをチェックしてください:

page.evaluateHandle(pageFunction、... args)

評価されるpageFunction関数ページコンテキスト

exposeFunction()は、ページ内で実行される関数を公開しませんが、ノードで実行される関数を公開します呼び出されるページから。

evaluate()を使用する必要があります:

6
mikemaccana

あなたの問題はpage.exposeFunction()があなたの関数にPromiseを返すという事実に関係しているかもしれません(asyncawaitの使用が必要です)。これは、関数が ブラウザー内で実行される ではなく、nodejsアプリケーション内で行われ、その結果がブラウザーコードとの間でやり取りされるために発生します。これが、page.exposeFunction()に渡された関数が実際の結果ではなくpromiseを返すようになった理由です。そして、関数がwindow(ブラウザーではなく)内で実行され、nodejs内にnodejsがないため、window関数が定義されていない理由を説明します利用可能な定義。

関連する質問:

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