Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

getting property from ElementHandle

I am using Puppeteer in a Node.js module. I retrieve an HTML element with an XPath selector and need to extract the text property.

Currently I use:

    // Get the element
    let ele = await element.$x(`//div[@class="g"][${i}]/div/div/h3/a`);

    // Get the text property
    const title = await(await ele[0].getProperty('text')).jsonValue();

Is there any way to do this without being so verbose?

like image 837
f0rt1s Avatar asked Mar 20 '18 15:03

f0rt1s


People also ask

What is ElementHandle?

ElementHandle prevents DOM element from garbage collection unless the handle is disposed . ElementHandles are auto-disposed when their origin frame gets navigated. ElementHandle instances can be used as arguments in page.

What is Jshandle?

Represents a reference to a JavaScript object. Instances can be created using Page. evaluateHandle(). Handles prevent the referenced JavaScript object from being garbage-collected unless the handle is purposely disposed.

What is Page $$ eval?

$$eval() method. This method runs Array. from(document. querySelectorAll(selector)) within the page and passes the result as the first argument to the pageFunction .

What does the return value of elementhandle return?

Returns either null or the object handle itself, if the object handle is an instance of ElementHandle. This method returns the bounding box of the element (relative to the main frame), or null if the element is not visible. This method returns boxes of the element, or null if the element is not visible.

What is the use of elementhandle in JavaScript?

ElementHandle instances can be used as arguments in page.$eval and page.evaluate methods. Returns either null or the object handle itself, if the object handle is an instance of ElementHandle. This method returns the bounding box of the element (relative to the main frame), or null if the element is not visible.

How to use elementhandle as an argument in a page?

ElementHandle instances can be used as arguments in page.$eval and page.evaluate methods. Returns either null or the object handle itself, if the object handle is an instance of ElementHandle.

How do I dispose an elementhandle?

ElementHandles are auto-disposed when their origin frame gets navigated. ElementHandle instances can be used as arguments in page.$eval and page.evaluate methods. Returns either null or the object handle itself, if the object handle is an instance of ElementHandle.


2 Answers

...or write a tiny helper function.

public async GetProperty(element: ElementHandle, property: string): Promise<string> {
    return await (await element.getProperty(property)).jsonValue();
}

use:

let inner = await GetProperty(ele, 'innerHTML');
like image 200
f0rt1s Avatar answered Nov 12 '22 20:11

f0rt1s


I would rather extend ElementHandle for missing methods like:

//  [email protected]
let { ElementHandle } = require( "puppeteer/lib/ExecutionContext" );
// [email protected] 
if ( ElementHandle === undefined ) {
  ElementHandle = require( "puppeteer/lib/JSHandle" ).ElementHandle;
}

/**
 * Set value on a select element
 * @param {string} value
 * @returns {Promise<Undefined>}
 */
ElementHandle.prototype.select = async function( value ) {
  await this._page.evaluateHandle( ( el, value ) => {
      const event = new Event( "change", { bubbles: true });
      event.simulated = true;
      el.querySelector( `option[value="${ value }"]` ).selected = true;
      el.dispatchEvent( event );
  }, this, value );
};

/**
 * Check if element is visible in the DOM
 * @returns {Promise<Boolean>}
 **/
ElementHandle.prototype.isVisible = async function(){
  return (await this.boundingBox() !== null);
};

/**
 * Get element attribute
 * @param {string} attr
 * @returns {Promise<String>}
 */
ElementHandle.prototype.getAttr = async function( attr ){
  const handle = await this._page.evaluateHandle( ( el, attr ) => el.getAttribute( attr ), this, attr );
  return await handle.jsonValue();
};

/**
 * Get element property
 * @param {string} prop
 * @returns {Promise<String>}
 */
ElementHandle.prototype.getProp = async function( prop ){
  const handle = await this._page.evaluateHandle( ( el, prop ) => el[ prop ], this, prop );
  return await handle.jsonValue();
};

As soon as you import this module once in you code you can play with the handles as follows:

const elh = await page.$( `#testTarget` );
console.log( await elh.isVisible() );
console.log( await elh.getAttr( "class" ) );
console.log( await elh.getProp( "innerHTML" ) );
like image 24
Dmitry Sheiko Avatar answered Nov 12 '22 20:11

Dmitry Sheiko