从ElementHandle获得房产

时间:2018-03-20 15:40:38

标签: puppeteer

我在node.js模块中使用puppeteer。我使用XPath选择器检索元素,需要提取文本属性。

目前我使用:

ConfigObject conf = new ConfigSlurper().parse( new File("src/main/resources/version.properties").toURI().toURL());

有没有办法做到这一点而不是冗长?

5 个答案:

答案 0 :(得分:2)

我宁愿为缺少的方法扩展ElementHandle,例如:

//  puppeteer@1.9.0
let { ElementHandle } = require( "puppeteer/lib/ExecutionContext" );
// puppeteer@1.12 
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();
};

只要在代码中导入此模块一次,就可以按如下方式使用句柄:

const elh = await page.$( `#testTarget` );
console.log( await elh.isVisible() );
console.log( await elh.getAttr( "class" ) );
console.log( await elh.getProp( "innerHTML" ) );

答案 1 :(得分:1)

我更喜欢使用eval()函数,因此我可以使用更简洁的代码:

page.eval(() => {

    let element = document.querySelector('#mySelector')
    return element.innerText

}).then(text => {
    console.log(text)
})

您还可以传递之前抓取的元素,例如ele var:

page.eval(element => {
    return element.innerText
}, ele).then(text => {
    // Do whatever you want with text
})

(我很抱歉使用Promise语法,我不熟悉await逻辑)

答案 2 :(得分:1)

...或写一个小帮手功能。

browser.get("https://www.vudu.com/content/movies/details/title/835625")

price_element = browser.find_elements_by_xpath("//div[@class='row nr-p-0 nr-mb-10']")
prices = [x.text for x in price_element]

使用:

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

答案 3 :(得分:0)

我的方式

async function getVisibleHandle(selector, page) {

    const elements = await page.$$(selector);

    let hasVisibleElement = false,
        visibleElement = '';

    if (!elements.length) {
        return [hasVisibleElement, visibleElement];
    }

    let i = 0;
    for (let element of elements) {
        const isVisibleHandle = await page.evaluateHandle((e) => {
            const style = window.getComputedStyle(e);
            return (style && style.display !== 'none' &&
                style.visibility !== 'hidden' && style.opacity !== '0');
        }, element);
        var visible = await isVisibleHandle.jsonValue();
        const box = await element.boxModel();
        if (visible && box) {
            hasVisibleElement = true;
            visibleElement = elements[i];
            break;
        }
        i++;
    }

    return [hasVisibleElement, visibleElement];
}

用法

let selector = "a[href='https://example.com/']";

let visibleHandle = await getVisibleHandle(selector, page);

if (visibleHandle[1]) {

   await Promise.all([
     visibleHandle[1].click(),
     page.waitForNavigation()
   ]);
}

答案 4 :(得分:0)

但是,在接受的答案中提到了page.eval(),对于伪满的人,这种方法从未存在过,我认为实际上是page.evaluate()

但是,使用page.evaluate()需要将操作分为两部分(一个用于获取元素,一个用于选择值)。

  

有没有办法做到这一点呢?

在这种情况下,page.$eval()似乎更合适,因为它允许您直接将选择器作为参数传递,从而减少了需要引入的操作或变量的数量:

现在,在您的特定情况下,您不仅要在整个页面上执行$eval,而且要在ElementHandle上执行,这是自May 9, 2018以来通过elementHandle.$eval()开始执行的:

  

此方法在元素内运行document.querySelector并将其作为第一个参数传递给pageFunction。

enter image description here

这将转换为您的示例,如下所示:

await elementHandle.$eval(`//div[@class="g"][${i}]/div/div/h3/a`, el => el.text);