我在node.js模块中使用puppeteer。我使用XPath选择器检索元素,需要提取文本属性。
目前我使用:
ConfigObject conf = new ConfigSlurper().parse( new File("src/main/resources/version.properties").toURI().toURL());
有没有办法做到这一点而不是冗长?
答案 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。
这将转换为您的示例,如下所示:
await elementHandle.$eval(`//div[@class="g"][${i}]/div/div/h3/a`, el => el.text);