Puppeteer: biến biến trong .evalu ()


127

Tôi đang cố gắng chuyển một biến vào một page.evaluate()hàm trong Puppeteer , nhưng khi tôi sử dụng ví dụ rất đơn giản sau đây, biến đó evalVarkhông được xác định.

Tôi mới sử dụng Puppeteer và không thể tìm thấy bất kỳ ví dụ nào để xây dựng, vì vậy tôi cần trợ giúp chuyển biến đó vào page.evaluate()hàm để tôi có thể sử dụng nó bên trong.

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

  }

})();

Câu trả lời:


188

Bạn phải truyền biến như một đối số cho pageFunctionnhư thế này:

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

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

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

Các đối số cũng có thể được tuần tự hóa: https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pageevalupagefeft-args .


3
Xin chào, làm thế nào bạn sẽ vượt qua nhiều biến?
chitzui

4
Ngoài ra, tôi không thực sự có thể vượt qua một hàm: var myFunction = function () {console.log ("hello")}; đang chờ page.evalu (func => func (), myFactor); cho tôi: Evaluation failed: TypeError: func is not a function.. Tại sao?
chitzui

1
Đừng quên nhập evalVarcả hai trong chữ ký đối số hàm và như là một đối số được truyền vào evaluate(ở cuối ví dụ mã).
Flimm

2
@chitzui: Bạn không thể chuyển một chức năng cho pate.evaluate(). Bạn có thể 'phơi bày' nó với page.exposeFunction. Để biết thêm, xem stackoverflow.com/a/58040978 .
knod

Vì điều này có mức tăng cao nhất, có ai gặp phải lỗi linting với điều này chưa? cụ thể với tham số đã được khai báo trong phạm vi trên. ngoài lỗi này, nó không hoạt động.
Trộn Master Mike

60

Tôi khuyến khích bạn tiếp tục theo phong cách này, vì nó thuận tiệndễ đọc hơn .

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

40

Biến đơn:

Bạn có thể truyền một biến để page.evaluate()sử dụng cú pháp sau:

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

Lưu ý: Bạn không cần đưa vào biến (), trừ khi bạn sẽ chuyển nhiều biến.

Nhiều biến:

Bạn có thể chuyển nhiều biến sang page.evaluate()sử dụng cú pháp sau:

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

Lưu ý: Việc bao gồm các biến của bạn trong {}không cần thiết.


12

Tôi đã mất nhiều thời gian để tìm ra rằng console.log()trong evaluate()không thể hiển thị ở nút điều khiển.

Tham chiếu: https://github.com/GoogleChrom/puppeteer/issues/1944

tất cả mọi thứ được chạy bên trong chức năng page.evalu được thực hiện trong ngữ cảnh của trang trình duyệt. Tập lệnh đang chạy trong trình duyệt không có trong node.js, vì vậy nếu bạn đăng nhập, nó sẽ hiển thị trong bảng điều khiển trình duyệt mà nếu bạn đang chạy không đầu thì bạn sẽ không thấy. Bạn cũng không thể đặt điểm dừng nút bên trong hàm.

Hy vọng điều này có thể giúp đỡ.


6

Đối với vượt qua a function, có hai cách bạn có thể làm điều đó.

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

Bạn có thể thêm devtools: truevào các tùy chọn khởi chạy để kiểm tra


Và tôi muốn vượt qua một đối tượng?
xe điện

Làm thế nào bạn sẽ thêm một đối số trong trường hợp thứ 2? ví dụ: tôi muốn thêm một chuỗi vào yourFunc
user3568719

Bạn có thể thay thế yourFuncbằng đối tượng Nếu tài sản của bạn không phải là một chức năng. @tramada
sói

func tương tự như bạnFunc vì vậy bạn có thể gọi func (stringArg) giống như exec yourFunc @ user3568719
sói

Bạn có phiền chỉ ra cách bạn sẽ chuyển một đối tượng vào cửa sổ và sau đó truy cập nó không?
wuno

2

Tôi có một ví dụ về bản in có thể giúp ai đó mới trong bản in.

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

Làm thế nào để bạn chạy puppeteertrong bản thảo? Bạn có dịch mã sang js mỗi khi bạn sửa đổi mã của mình không?
tuyết lở1

Đúng. Bạn có thể xem dự án này tại đây - github.com/srinivasreddy/compiances-list
Srinivas Reddy Thatiparthy

-1

Với trang. $$ eval

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

[xem thêm tại trang. $ eval cho một bộ chọn]


Làm thế nào mà trả lời câu hỏi? Tôi không thấy bất kỳ biến nào bạn đang chuyển từ bối cảnh thử nghiệm sang bối cảnh trình duyệt.
Ambroise Rabier
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.