Lalkarz: przekaż zmienną w .evaluate ()

128

Próbuję przekazać zmienną do page.evaluate()funkcji w Puppeteer , ale kiedy używam następującego bardzo uproszczonego przykładu, zmiennaevalVar jest niezdefiniowana.

Jestem nowy w Puppeteer i nie mogę znaleźć żadnych przykładów do zbudowania, więc potrzebuję pomocy w przekazaniu tej zmiennej do page.evaluate()funkcji, aby móc jej użyć w środku.

const puppeteer = require('puppeteer');

(async() => {

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

  const evalVar = 'WHUT??';

  try {

    await page.goto('https://www.google.com.au');
    await page.waitForSelector('#fbar');
    const links = await page.evaluate((evalVar) => {

      console.log('evalVar:', evalVar); // appears undefined

      const urls = [];
      hrefs = document.querySelectorAll('#fbar #fsl a');
      hrefs.forEach(function(el) {
        urls.push(el.href);
      });
      return urls;
    })
    console.log('links:', links);

  } catch (err) {

    console.log('ERR:', err.message);

  } finally {

    // browser.close();

  }

})();
Cat Burston
źródło

Odpowiedzi:

189

Musisz przekazać zmienną jako argument do pageFunctiontego:

const links = await page.evaluate((evalVar) => {

  console.log(evalVar); // 2. should be defined now
  

}, evalVar); // 1. pass variable as an argument

Argumenty można również serializować: https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pageevaluatepagefunction-args .

flozia
źródło
3
Witam, jak przekazałbyś wiele zmiennych?
chitzui
4
Poza tym nie jestem w stanie przekazać funkcji: var myFunction = function () {console.log ("hello")}; await page.evaluate (func => func (), myFunction); daje mi: Evaluation failed: TypeError: func is not a function.. Dlaczego?
chitzui
1
Nie zapomnij wpisać evalVarzarówno w podpisie argumentu funkcji, jak i jako przekazany argument do evaluate(na końcu przykładu kodu).
Flimm
2
@chitzui: Nie możesz przekazać funkcji do pate.evaluate(). Można to rzekomo „zdemaskować” page.exposeFunction. Więcej informacji można znaleźć na stronie stackoverflow.com/a/58040978 .
knod
ponieważ ma najwięcej głosów pozytywnych, czy ktoś doświadczył błędów lintowania? konkretnie z parametrem już zadeklarowanym w górnym zakresie. poza tym błędem to działa.
Mix Master Mike
61

Zachęcam do trzymania się tego stylu, bo jest wygodniejszy i bardziej czytelny .

let name = 'jack';
let age  = 33;
let location = 'Berlin/Germany';

await page.evaluate(({name, age, location}) => {

    console.log(name);
    console.log(age);
    console.log(location);

},{name, age, location});
Mehdi Raash
źródło
41

Pojedyncza zmienna:

Można przekazać jednej zmiennej do page.evaluate()stosując następującą składnię:

await page.evaluate(example => { /* ... */ }, example);

Uwaga: nie musisz umieszczać zmiennej wewnątrz (), chyba że masz zamiar przekazywać wiele zmiennych.

Wiele zmiennych:

Można przekazać wiele zmiennych do page.evaluate()stosując następującą składnię:

await page.evaluate((example_1, example_2) => { /* ... */ }, example_1, example_2);

Uwaga: umieszczanie zmiennych wewnątrz {}nie jest konieczne.

Grant Miller
źródło
12

Zajęło mi trochę czasu, zanim zorientowałem się, że console.log()w evaluate()konsoli węzła nie można wyświetlić.

Ref: https://github.com/GoogleChrome/puppeteer/issues/1944

wszystko, co jest uruchamiane wewnątrz strony. funkcja oceny jest wykonywana w kontekście strony przeglądarki. Skrypt działa w przeglądarce, a nie w node.js, więc jeśli się zalogujesz, pokaże się w konsoli przeglądarki, czego nie zobaczysz, jeśli pracujesz bez głowy. Nie możesz również ustawić punktu przerwania węzła wewnątrz funkcji.

Mam nadzieję, że to pomoże.

harrrrrrry
źródło
6

W przypadku zaliczenia a functionmożesz to zrobić na dwa sposoby.

// 1. Defined in evaluationContext
await page.evaluate(() => {
  window.yourFunc = function() {...};
});
const links = await page.evaluate(() => {
  const func = window.yourFunc;
  func();
});


// 2. Transform function to serializable(string). (Function can not be serialized)
const yourFunc = function() {...};
const obj = {
  func: yourFunc.toString()
};
const otherObj = {
  foo: 'bar'
};
const links = await page.evaluate((obj, aObj) => {
   const funStr = obj.func;
   const func = new Function(`return ${funStr}.apply(null, arguments)`)
   func();

   const foo = aObj.foo; // bar, for object
   window.foo = foo;
   debugger;
}, obj, otherObj);

Możesz dodać devtools: truedo opcji uruchamiania w celu przetestowania

Wilk
źródło
I chciałem przekazać obiekt?
tramada
Jak dodasz argument w drugim przypadku? np. chcę dodać pass ciąg do
yourFunc
Możesz zamienić na yourFuncobiekt, jeśli twoja właściwość nie jest funkcją. @tramada
wolf
func jest podobna do youFunc ,, więc możesz wywołać func (stringArg) tak samo jak exec yourFunc @ user3568719
wolf
Czy mógłbyś pokazać, jak przekazać obiekt do okna, a następnie uzyskać do niego dostęp?
wuno
2

Mam przykład maszynopisu, który mógłby pomóc komuś nowemu w pisaniu maszynowym.

const hyperlinks: string [] = await page.evaluate((url: string, regex: RegExp, querySelect: string) => {
.........
}, url, regex, querySelect);
Srinivas Reddy Thatiparthy
źródło
Jak puppeteerbiegasz w maszynie? Czy przechodzisz do js za każdym razem, gdy modyfikujesz swój kod?
lawina 1
Tak. Możesz rzucić
Srinivas Reddy Thatiparthy
-1

Ze stroną. $$ eval

//..
const page = await browser.newPage();
const hrefs = await page.$$eval('#fbar #fsl a', as => as.map(a => a.href));
console.log(hrefs);
//..

[zobacz także na stronie. $ eval dla pojedynczego selektora]

voodoo417
źródło
Jak to odpowiada na pytanie? Nie widzę żadnej zmiennej, którą przekazujesz z kontekstu testowego do kontekstu przeglądarki.
Ambroise Rabier