Pass Arguments with Page.Evaluate

Pass arguments with page.evaluate

I've had that exact problem. It can be done with a little trickery, because page.evaluate also can accept a string.

There are several ways to do it, but I use a wrapper called evaluate, which accepts additional parameters to pass to the function that must be evaluated on the webkit side. You would use it like this:

page.open(url, function() {
var foo = 42;

evaluate(page, function(foo) {
// this code has now has access to foo
console.log(foo);
}, foo);
});

And here is the evaluate() function:

/*
* This function wraps WebPage.evaluate, and offers the possibility to pass
* parameters into the webpage function. The PhantomJS issue is here:
*
* http://code.google.com/p/phantomjs/issues/detail?id=132
*
* This is from comment #43.
*/
function evaluate(page, func) {
var args = [].slice.call(arguments, 2);
var fn = "function() { return (" + func.toString() + ").apply(this, " + JSON.stringify(args) + ");}";
return page.evaluate(fn);
}

How can I pass variable into an evaluate function?

You have to pass the variable as an argument to the pageFunction like this:

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

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


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

You can pass in multiple variables by passing more arguments to page.evaluate():

await page.evaluate((a, b c) => { console.log(a, b, c) }, a, b, c)

The arguments must either be serializable as JSON or JSHandles of in-browser objects: https://pptr.dev/#?show=api-pageevaluatepagefunction-args

Passing arguments to page.evaluate (puppeteer) when used with pkg builds

If you just need to get some property value, you should probably use getProperty (see https://pptr.dev/api/puppeteer.jshandle.getproperty):

const myValue: string = await element.getProperty("value").then(e => e._remoteObject.value);

Otherwise, I haven't tried this but it seems that evaluate function can be called on a JSHandle (https://pptr.dev/api/puppeteer.jshandle.evaluate), so maybe the following could work:

element.evaluate(
`((el) => {
return el.value;
})();`
);

If that doesn't work then you could add these functions to the spawn browsers:

// get elements by xpath (same as $x)
function getElementByXpath(thePath, target = document) {
const result = document.evaluate(thePath, target, null, XPathResult.ANY_TYPE, null);
const tags = [];
let node = null;
// eslint-disable-next-line no-cond-assign,@typescript-eslint/strict-boolean-expressions
while(node = result.iterateNext()) {
tags.push(node);
}

return tags;
}

// get elements from css or xpath
function getElements(selectorOrXpath, parent = document) {
const isxPath = selectorOrXpath.includes("//");
if(isxPath) {
return getElementByXpath(selectorOrXpath, parent)
}
else {
return parent.querySelectorAll(selectorOrXpath)
}
}

and then call getElements("${selector}"); instead of document.querySelectorAll("${selector}"); in your example,

this way it'll work with both xpath selectors as well as css.

Note that these functions will get removed from your spawn browsers when they refresh (easy way to get around this is to just include them in the same "evaluate" function).

How do pass arguments to a page.evaluate?

You pass arguments to the evaluate method like this:

page.evaluate((a, b) => {
// you can use `a` and `b` here
}, a, b);

You can read more on arguments for the method in the docs here.

Is it possible to pass a function to Puppeteer's page.evaluate()

No, you cannot pass functions like that. The passed data needs to be serializable via JSON.stringify, which is not possible for functions.

Alternative: Expose the function

To use a function from your Node.js environment inside the page, you need to expose it via page.exposeFunction. When called the function is executed inside your Node.js environment

await page.exposeFunction('myfunction', text => `great ${text}`);
await page.evaluate(async (object) => {
return await window.myfunction(object); // 'great example'
}, 'example');

Alternative: Define the function inside page.evaluate

To use a function inside the page context, you can either define it inside of the context. This way, the function does not have access to your Node.js variables.

await page.evaluate((obj) => {
const myfunction = (stuff) => `great ${stuff}`;
return myfunction(obj); // 'great example'
}, 'example');

Puppeteer - Passing a variable to page.evaluate()

Figured it out. Of course 5 minutes after posting to SO following hours of frustration, but here goes:

const x = 2;
let value = await page.evaluate((x) => {
return Promise.resolve(document.querySelector("#pageBody > div:nth-child(" + x + ") > table > tr > td").innerText)
}, x);
console.log(value);

pass multiple parameters into page.evaluate()

You can pass as many as necessary parameters into page.evaluate as long as they're serializable:

await page.evaluate( (selector, state) => {
console.log(selector)
console.log(state)
}, "div.top-select-option a.eccheckbox", state);

How to pass page as an argument in the function parameter of page.evaluate()?

I'm not sure if you understand how the .evaluate method works. This method executes the code in the browser context, so to click on an element, you can use such code as if you were writing it in a browser. You cannot pass complex objects like page between the browser and Node.js. I changed your code inside the .evaluate method, it should look something like this:

const result = await page.evaluate((selector1, selector2) => {
const result = [];
const sel = document.querySelectorAll(selector1);
if (sel.length) {
const total = sel.length;
for (let i = 0; i<total; i++) {
result.push(sel.querySelector(`div:nth-child(${i+1})`).textContent);
document.querySelector(`${selector2} div:nth-child(${i+1})`).click();
}
}
return result;
}, selector1, selector2);


Related Topics



Leave a reply



Submit