Кукловод: передать переменную в .evaluate ()

128

Я пытаюсь передать переменную в page.evaluate()функцию в Puppeteer , но когда я использую следующий очень упрощенный пример, переменная evalVarне определена.

Я новичок в Puppeteer и не могу найти никаких примеров для развития, поэтому мне нужна помощь в передаче этой переменной в page.evaluate()функцию, чтобы я мог использовать ее внутри.

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();

  }

})();
Кот Бёрстон
источник

Ответы:

189

Вы должны передать переменную в качестве аргумента pageFunctionпримерно так:

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

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

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

Аргументы также можно сериализовать: https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pageevaluatepagefunction-args .

flozia
источник
3
Привет, как бы передать несколько переменных?
chitzui
4
Кроме того, я не могу передать функцию: var myFunction = function () {console.log ("hello")}; ждите page.evaluate (func => func (), myFunction); дает мне: Evaluation failed: TypeError: func is not a function.. Почему?
chitzui
1
Не забудьте ввести evalVarкак сигнатуру аргумента функции, так и переданный аргумент evaluate(в конце примера кода).
Flimm
2
@chitzui: вы не можете передать функцию pate.evaluate(). Вы можете якобы "разоблачить" это с помощью page.exposeFunction. Для получения дополнительной информации см. Stackoverflow.com/a/58040978 .
knod
поскольку у него самые высокие голоса, возникали ли у кого-нибудь ошибки линтинга с этим? особенно с параметром, уже объявленным в верхней области. помимо этой ошибки, это действительно работает.
Mix Master Mike
61

Я рекомендую вам придерживаться этого стиля, потому что он более удобен и читаем .

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});
Мехди Рааш
источник
41

Одиночная переменная:

Вы можете передать одну переменную , чтобы , page.evaluate()используя следующий синтаксис:

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

Примечание: вам не нужно заключать переменную в (), если вы не собираетесь передавать несколько переменных.

Несколько переменных:

Вы можете передать несколько переменных к , page.evaluate()используя следующий синтаксис:

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

Примечание: заключать переменные внутрь {}необязательно.

Грант Миллер
источник
12

Мне потребовалось довольно много времени, чтобы понять, что console.log()в evaluate()консоли узла не отображается.

Ссылка: https://github.com/GoogleChrome/puppeteer/issues/1944

все, что выполняется внутри функции page.evaluate, выполняется в контексте страницы браузера. Сценарий выполняется в браузере, а не в node.js, поэтому, если вы зарегистрируетесь, он отобразится в консоли браузера, которую вы не увидите, если вы работаете без головы. Вы также не можете установить точку останова внутри функции.

Надеюсь, это поможет.

harrrrrrry
источник
6

functionЕсть два способа сделать это для сдачи а .

// 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);

Вы можете добавить devtools: trueв параметры запуска для тестирования

волк
источник
И я хотел передать объект?
tramada
Как бы вы добавили аргумент во втором случае? например, я хочу добавить строку для передачи в yourFunc
user3568719
Вы можете заменить yourFuncна объект, если ваше свойство не является функцией. @tramada
wolf
func похож на youFunc ,, поэтому вы можете вызывать func (stringArg) точно так же, как exec yourFunc @ user3568719
wolf
Не могли бы вы показать, как передать объект в окно, а затем получить к нему доступ?
wuno
2

У меня есть пример машинописного текста, который может помочь кому-то новичку в машинописном тексте.

const hyperlinks: string [] = await page.evaluate((url: string, regex: RegExp, querySelect: string) => {
.........
}, url, regex, querySelect);
Шринивас Редди Татипарти
источник
Как у вас работает puppeteerмашинописный текст? Вы переходите на js каждый раз, когда изменяете свой код?
avalanche1
Да. Вы можете посмотреть на этот проект здесь - github.com/srinivasreddy/companies-list
Srinivas Reddy Thatiparthy
-1

Со страницей. $$ eval

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

[см. также на стр. $ eval для отдельного селектора]

voodoo417
источник
Как это отвечает на вопрос? Я не вижу никаких переменных, которые вы передаете из контекста тестирования в контекст браузера.
Амбруаз Рабье,