skip to Main Content

I have some JavaScript code running in which controls to automate tasks in a web browser.

This code gets a list of links on the page and outputs them to the console:

const links = await page.evaluate(() => { return [...document.querySelectorAll('a')].map(({href, innerText}) => ({href, innerText})); });
links.forEach(a => console.log(`<a href="${a.href}">${a.innerText.trim()}</a>`));

If I change it to this:

const links = await page.evaluate(() => { return [...document.querySelectorAll('a')]; });
links.forEach(a => console.log(`<a href="${a.href}">${a.innerText.trim()}</a>`));

Then I get this error:

TypeError: Cannot read properties of undefined (reading 'trim')

Is there any way to work directly on the original array, without having to make a copy of the array using map()?

There are a couple of hundred properties on each <a> link, which I’d have to type out one at a time in the map() if I wanted to use many of them.


As an aside, is there any way to combine the 2 lines of code in to 1?

If I change it to this:

await page.evaluate(() => { return [...document.querySelectorAll('a')].map(({href, innerText}) => ({href, innerText})); })
    .forEach(a => console.log(`<a href="${a.href}">${a.innerText.trim()}</a>`));

Then I get this error:

TypeError: page.evaluate(...).forEach is not a function

I also found that it doesn’t seem to be possible to do a console.log() whilst inside a page.evaluate() (I get no output). This is why I moved the forEach on to a 2nd line.

2

Answers


  1. The map is necessary to convert each HTMLElement into a serializable object { href, innerText } that can be passed in page.evaluate from the context of the browser (page) to the context of your node app.

    If you want to work on the original array of elements, you can execute JavaScript on the context of the page inside the page.evaluate handler.

    Login or Signup to reply.
  2. Access the properties inside the evaluate function, in the code that’s running in the page, and send back only the results of your function back to the driver process. In your particular example, you’ll want to simplify to

    (await page.evaluate(() =>
       Array.from(document.querySelectorAll('a'), a => `<a href="${a.href}">${a.innerText.trim()}</a>`)
    )).forEach(console.log);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search