I would like to get an element's tagName. Should be button in following example.
const puppeteer = require('puppeteer')
async function run () {
const browser = await puppeteer.launch({headless: false})
const page = await browser.newPage()
const html = `
<div>
<button type="button">click me</button>
<span>Some words.</span>
</div>
`
await page.setContent(html)
const elements = await page.$$('button')
const tagName = await elements[0].$eval('*', node => node.tagName)
console.log(tagName) // expect to be 'button'
await browser.close()
}
run()
The error message said Error: failed to find element matching selector "*"
I can tell elements matched one element as elements.length is 1
Where is wrong?
========== Edit ==========
Let's say I already had elements beforehand, how to get the tagName out of it.
Thanks!
Try using page.$eval to select the button, and then get the tagName from the button:
const tagName = await page.$eval('button', button => button.tagName);
If you already have an elementHandle like elements[0], you can get an attribute from that element by passing it through page.evaluate:
const tagName = await page.evaluate(
element => element.tagName,
elements[0]
);
It appears your elements is an array of ElementHandles.
In that case, there may be a slightly more straightforward syntax:
const tag_name = await (await elements[0].getProperty('tagName')).jsonValue()
This does not involve referring to the page object.
Thanks!
Related
I'm using Puppeteer to extract the text of a span by it's class name but I'm getting returned nothing. I don't know if its because the page isn't loading in time or not.
This is my current code:
async function Reload() {
Page.reload()
Price = await Page.evaluate(() => document.getElementsByClassName("text-robux-lg wait-for-i18n-format-render"))
console.log(Price)
}
Reload()
HTML
<div class="icon-text-wrapper clearfix icon-robux-price-container">
<span class="icon-robux-16x16 wait-for-i18n-format-render"></span>
<span class="text-robux-lg wait-for-i18n-format-render">689</span>
</div>
because the function that you passed to Page.evaluate() returns a non-Serializable value.
from the puppeteer official document
If the function passed to the page.evaluate returns a non-Serializable value, then page.evaluate resolves to undefined
so you have to make the function that passed to Page.evaluate() returns the text of span element rather than returns the Element object of span.
like the following code
const puppeteer = require('puppeteer');
const htmlCode = `
<div class="icon-text-wrapper clearfix icon-robux-price-container">
<span class="icon-robux-16x16 wait-for-i18n-format-render"></span>
<span class="text-robux-lg wait-for-i18n-format-render">689</span>
</div>
`;
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setContent(htmlCode);
const price = await page.evaluate(() => {
const elements = document.getElementsByClassName('text-robux-lg wait-for-i18n-format-render');
return Array.from(elements).map(element => element.innerText); // as you see, now this function returns array of texts instead of Array of elements
})
console.log(price); // this will log the text of all elements that have the specific class above
console.log(price[0]); // this will log the first element that have the specific class above
// other actions...
await browser.close();
})();
NOTE: if you want to get the html code from another site by its url use page.goto() instead of page.setContent()
NOTE: because you are using document.getElementsByClassName() the returned value of the function that passed to page.evaluate() in the code above will be array of texts and not text as document.getElementById() do
NOTE: if you want to know what is the difference between Serializable objects and non-serializable objects read the answers of this question on Stackoverflow
How do I get an href attribute from an element in puppeteer?
I am trying to get the href attribute from the anchorTag.
const anchorTag = await page.$('table#middleContent_grvTransactionList > tbody > tr:nth-child(4) > td:nth-child(7) > a');
You can do this in many ways:
Using evaluate:
const href = await page.evaluate(el => el.getAttribute('href'), anchorTag);
Using getProperty:
const propertyHandle = await anchorTag.getProperty('href');
const href = await propertyHandle.jsonValue();
Using $eval:
const href = await page.$eval('table#middleContent_grvTransactionList > tbody > tr:nth-child(4) > td:nth-child(7) > a', el => el.getAttribute('href'));
I'm trying to click on a div that has a role="button" attribute,
Even though I'm not using it trying to get it by its DOM path is not working either.
What I've tried:
try {
let Button = await this.page.$("div.class1.class2 > div");
await Button.click();
console.log("Clicked");
} catch (e) {
console.log(e);
console.log("No button");
}
The error I get is:
TypeError: Cannot read property '$' of undefined
I tried to get to the div by the div that contains it which does have 2 classes I can relate on but it doesn't seem to work.
Is there a way to get an array of all the divs with role="button" and click only on the one that has a span inside it with a specific text?
Remove this keyword to fix the TypeError error.
let Button = await page.$("div.class1.class2 > div");
To get an array of all the divs with role=button and Specific text text:
const buttons = await page.$x('//div[#role="button"][text()="Specific Text"]'); // returns: <Promise<Array<ElementHandle>>>
But I would recommend adding waitForXPath method to wait for the element.
Full example:
try {
const button = await page.waitForXPath('//div[#role="button"][text()="Specific Text"]');
await button.click();
console.log("Clicked");
} catch (e) {
console.log("No button", e);
}
The markup i have to work with looks like this:
<label>
<input type="radio" name="myfield" value="Yes" size>
</label>
I want to call page.click(selector) with the radio as the selector, but I can't. I don't think it is visible because of the size attribute.
My javascript looks like this:
const page = await browser.newPage();
const selector = 'input[name="myfield"]';
await page.click(selector);
So I would like to target and click the parent label element.
How do I change the value of my selector constant to target the label?
Sorry, I didn't explain very well. By can't, i mean that the element is not visible and therefore i don't believe it can technically be clicked. Therefore I think i need to target the label which is visible, but i don't know how I target it
not visible or not visible at the moment?
Have you tried to use waitForSelector(selector) ?
const page = await browser.newPage();
const selector = 'input[name="myfield"]';
await page.waitForSelector(selector); // waiting here before click
await page.click(selector);
Or something like:
const page = await browser.newPage();
const selector = 'label';
await page.waitForSelector(selector);
await page.evaluate((_) => {
document.querySelector('label > input[name="myfield"]').parentElement.click()
});
page.select() in Puppeteer not working as expected with kendo drop down, its not throwing any error. but the value not getting selected
am using puppeteer 5.6.0
sync function create(page)
{
const engCreationbtn = await page.$('.AddEngBtn');
await engCreationbtn.click();
await page.type('#createEngSidebar input[name="engName"]','puppeteer',{delay:20});
//await page.select('#createEngSidebar select[name="engType"]', 'Audit')
await page.select('select[name="country"]','IN')
await page.type('#createEngSidebar input[name="KPMGOffice"]','Tice',{delay:20});
//await page.select('#createEngSidebar select[name="timezone"]','India Standard Time||Asia/Kolkata',{delay:20})
await page.type('#createEngSidebar input[name="ClientName"]','pup-pepsi',{delay:20});
await page.type('#createEngSidebar .flyoutctrlpart .k-numeric-wrap .k-input','133',{delay:20});
const createbtn = await page.$('#createEngSidebar .flyoutfooter .btnPrimary');
await page.screenshot({path: 'engCreation.png'});
await createbtn.click();
await page.screenshot({path: 'afterengCreation.png'});
}
Html where am trying to set
<div class="flyoutctrlpart">
<span title="" class="k-widget k-dropdown k-header" unselectable="on" role="listbox" aria-haspopup="true" aria-expanded="false" tabindex="0" aria-owns="" aria-disabled="false" aria-busy="false" style="" aria-activedescendant="3f3ec341-a8f4-45bb-b617-0ce20b6b3db2"><span unselectable="on" class="k-dropdown-wrap k-state-default"><span unselectable="on" class="k-input">Select Country/Jurisdiction</span><span unselectable="on" class="k-select"><span unselectable="on" class="k-icon k-i-arrow-s">select</span></span></span><select name="country" kendo-drop-down-list="" k-data-text-field="'name'" k-data-value-field="'code'" k-data-source="engPopCtrl2019V1.countryList" k-option-label="engPopCtrl2019V1.SelectCountry" k-value-primitive="true" k-on-change="engPopCtrl2019V1.CountryChanged()" k-ng-model="engPopCtrl2019V1.country" data-role="dropdownlist" style="display: none;"><option value="" selected="selected">Select Country/Jurisdiction</option><option value="AF">Afghanistan</option><option value="AL">Albania and Kosovo</option><option value="DZ">Algeria</option><option value="AD">Andorra</option><option value="AO">Angola</option><option value="AI">Anguilla</option><option value="AG">Antigua and Barbuda</option><option value="AR">Argentina</option><option value="AM">Armenia</option><option value="AW">Aruba</option><option value="AU">Australia</option><option value="AT">Austria</option><option value="AZ">Azerbaijan</option><option value="SI">Slovenia</option><option value="ZA">South Africa</option><option value="SP">Spain</option><option value="LK">Sri Lanka</option><option value="LC">St. Lucia</option><option value="MF">St. Maarten</option><option value="VC">St. Vincent and the Grenadines</option><option value="SR">Suriname</option><option value="SE">Sweden</option><option value="CH">Switzerland</option><option value="SY">Syria</option><option value="TW">Taiwan</option><option value="TZ">Tanzania</option><option value="TH">Thailand</option><option value="TG">Togo</option><option value="TT">Trinidad and Tobago</option><option value="TN">Tunisia</option><option value="TR">Turkey</option><option value="TC">Turks & Caicos</option><option value="AE">UAE</option><option value="UG">Uganda</option><option value="UA">Ukraine</option><option value="UK">United Kingdom</option><option value="US">United States</option><option value="UY">Uruguay</option><option value="UZ">Uzbekistan</option><option value="VU">Vanuatu</option><option value="VE">Venezuela</option><option value="VN">Vietnam</option><option value="YE">Yemen</option><option value="ZM">Zambia</option><option value="ZW">Zimbabwe</option></select></span>
</div>
i have tried this against the kendo site also same am not able to set the value
const puppeteer = require('puppeteer');
const homepage = 'https://demos.telerik.com/kendo-ui/dropdownlist/index';
async function test() {
const browser = await puppeteer.launch({headless:false});
const page = await browser.newPage();
await page.setViewport({width: 1400, height: 1400});
await page.goto(homepage, {waitUntil: 'networkidle2'});
await page.select('#size','XL - 7 5/8"');
}
test()
page.select() will work only on select elements and not custom elements like span, it is behaving as expected.
Kendo does a data binding to the select element hence it does not update when you select/update the select element.
The easiest way is to use the kendoUI itself.
On the demo page, the UI initializes by following,
var size = $("#size").data("kendoDropDownList");
To set the value,
size.value('M - 7 1/4"')
To get the value,
size.value()
Same with the input box,
var color = $("#color").data("kendoDropDownList");
color.value() // "1" => which is Blank
color.value("2") // "2" => Now it's Orange
Working example with puppeteer,
const puppeteer = require('puppeteer');
const homepage = 'https://demos.telerik.com/kendo-ui/dropdownlist/index';
async function test() {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto(homepage, {waitUntil: 'networkidle2'});
// use the demo pages built in jQuery and Kendo to change the results
const sizeValue = await page.evaluate(()=>{
var size = $("#size").data("kendoDropDownList");
size.value('XL - 7 5/8"')
return size.value()
});
await page.screenshot({path: 'kendoTest.png', fullPage: true});
await browser.close();
return sizeValue;
}
test().then(console.log) // should say XL - 7 5/8"
Result: