Puppeteer: ผ่านตัวแปรใน. ประเมิน ()


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


3
สวัสดีคุณจะส่งผ่านตัวแปรหลายตัวได้อย่างไร?
chitzui

4
นอกจากนี้ฉันไม่สามารถส่งผ่านฟังก์ชัน: var myFunction = function () {console.log ("hello")}; รอหน้าการประเมิน (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

ทุกอย่างที่ทำงานในหน้าฟังก์ชั่นการประเมินจะทำในบริบทของหน้าเบราว์เซอร์ สคริปต์กำลังทำงานในเบราว์เซอร์ที่ไม่ได้อยู่ใน node.js ดังนั้นหากคุณบันทึกมันจะแสดงในคอนโซลของเบราว์เซอร์ซึ่งหากคุณใช้งานแบบไร้หัวคุณจะไม่เห็น คุณยังไม่สามารถตั้งค่าจุดพักโหนดภายในฟังก์ชันได้

หวังว่านี่จะช่วยได้


6

สำหรับ pass a 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

คุณจะเพิ่มอาร์กิวเมนต์ในกรณีที่ 2 ได้อย่างไร? เช่นฉันต้องการเพิ่มรหัสผ่านไปยัง yourFunc
user3568719

คุณสามารถแทนที่yourFuncด้วย object ได้หากคุณสมบัติของคุณไม่ใช่ฟังก์ชัน @tramada
wolf

func นั้นคล้ายกับ youFunc, ดังนั้นคุณสามารถเรียก func (stringArg) ได้เหมือนกับ exec yourFunc @ user3568719
wolf

คุณช่วยดูว่าคุณจะส่งวัตถุไปที่หน้าต่างแล้วเข้าถึงได้อย่างไร
wuno

2

ฉันมีตัวอย่าง typescript ที่สามารถช่วยคนใหม่ใน typescript ได้

const hyperlinks: string [] = await page.evaluate((url: string, regex: RegExp, querySelect: string) => {
.........
}, url, regex, querySelect);

คุณทำงานpuppeteerใน typescript ได้อย่างไร? คุณเปลี่ยนเป็น js ทุกครั้งที่คุณแก้ไขโค้ดของคุณหรือไม่?
หิมะถล่ม

ใช่. คุณสามารถดูโครงการนี้ได้ที่นี่ - 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สำหรับตัวเลือกเดียว]


วิธีนี้ตอบคำถาม? ฉันไม่เห็นตัวแปรใด ๆ ที่คุณกำลังส่งจากบริบทการทดสอบไปยังบริบทของเบราว์เซอร์
Ambroise Rabier
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.