how to unite cheerio with puppeteer so he can click on elements - javascript

I tried cheerio to find the element and if the element is found then he has to click but I don't know what to do with the puppeteer combination, the button I want to click is in the 3rd pict
await page.waitForTimeout(10000)
const contentHTML = await page.content();
const $ = cheerio.load(contentHTML);
const outerHTML = $('<button class="sc-nkuzb1-0 sc-d5trka-0 dsOMxw button" data-theme="home.verifyButton">Authenticate</button>').prop('innerText');
console.log(outerHTML);

Related

Render an element inside literal templates with a EventListener

I'm trying to insert an element with an EventListener at a certain point of an element. I can achieve this via appendChild but I want to insert it at a certain point. Like this:
const divT = () => {
const div = document.createElement("div");
const div_inside = document.createElement("div");
div_inside.addEventListener("click", () => {console.log("div_inside")});
div_inside.innerHTML = "INSIDE";
div.innerHTML = ` TEST ${div_inside.outerHTML} TEST `;
return div;
};
document.body.appendChild(divT());
The main problem is the outerHTML does not contain the information of the listener. There is a method to render the HTML with the listener still active?
Thanks in advance
Find a workaround using insertAdjacentElement and attaching an empty div:
const divT = () => {
const div = document.createElement("div");
const div_inside = document.createElement("div");
div_inside.innerHTML = "Hello World";
div_inside.addEventListener("click", () => {console.log("div_inside")});
div.innerHTML = ` TEST <div id="inside"></div> TEST `;
const div_s = div.getElementsByTagName('div')
div_s[0].insertAdjacentElement('beforebegin', div_inside)
return div;
};

creating multiple blog posts using divs javascript

I used the following code that allows for creating a "blog post" that is composed of multiple divs. I want that every time I click the button a new blog post is created but what actually happens is that no new posts are created and the only thing that changes is the content of the divs, to be specific the content of contentDiv. In other words, the user input or the post content is the only thing that changes.
const BtnAdd = document.getElementById("buttonpost1");
BtnAdd.addEventListener("click", AddNew);
function AddNew() {
var newhtml = document.getElementById("postbox").value;
sessionStorage.setItem("page1content", newhtml);
document.getElementById("postbox").value = "";
location.reload();
return false;
}
var newhtml2 = document.getElementById("profilecontent").innerHTML;
var newhtml3 = document.getElementById("underpost").innerHTML;
var newhtml4 = document.getElementById("commentcontent").innerHTML;
sessionStorage.setItem("usercontent" , newhtml2);
sessionStorage.setItem("belowcontent", newhtml3)
sessionStorage.setItem("commentcont", newhtml4)
const contentDiv = document.createElement("div");
const userDiv = document.createElement("div");
const lowerDiv = document.createElement("div");
const commentDiv = document.createElement("div");
const bigDiv = document.createElement("div");
bigDiv.classList.add("div-shadow");
contentDiv.classList.add("div-shadow2");
userDiv.classList.add("div-shadow3");
lowerDiv.classList.add("div-shadow4");
commentDiv.classList.add("div-shadow5");
userDiv.innerHTML = sessionStorage.getItem("usercontent");
contentDiv.innerHTML = sessionStorage.getItem("page1content");
lowerDiv.innerHTML = sessionStorage.getItem("belowcontent");
commentDiv.innerHTML = sessionStorage.getItem("commentcont");
var cWrapper = document.getElementById("contentwrapper");
bigDiv.appendChild(contentDiv);
bigDiv.appendChild(userDiv);
bigDiv.appendChild(lowerDiv);
bigDiv.appendChild(commentDiv);
cWrapper.appendChild(bigDiv);
what changes should I make to allow for the creation of a new blog post each time the user clicks the button of id buttonpost1 and not just override the content of the existing post (divs)?
I don't see any appendChild in your AddNew function, you need to create and append new elements each time the AddNew function gets called.
This is a minimal example:
const container = document.querySelector('#container');
const button = document.querySelector('button');
button.addEventListener('click', () => {
addNewPost();
});
function addNewPost() {
const newPost = document.createElement('div');
newPost.innerText = 'New Post';
container.appendChild(newPost);
}
<button type="button">Add New Post</button>
<div id="container"></div>

Can't find a working selector on drop down menu while using Puppeteer? [duplicate]

This question already has answers here:
Issue with CSS locator select-react
(2 answers)
Closed 3 years ago.
I'm creating an automated script with puppeteer and I'm running across a problem of trying to find a selector that could be understood. I have tried many different options but gotten no luck.
Note:Don't worry its a dummy account so nothing important is on it.
I tried using
const myacc = '.li.member-nav-item.d-sm-ib.va-sm-m > button';
and bunch of others but still getting selector error
Code:
const puppeteer = require('puppeteer');
var emailVal = 'kellybrando23434#gmail.com';
var passwordVal = 'd34gfA#4dfW';
const AcceptCookies = '#cookie-settings-layout > div > div > div > div.ncss-row.mt5-sm.mb7-sm > div:nth-child(2) > button';
const loginBtn = 'li.member-nav-item.d-sm-ib.va-sm-m > button';
const email = 'input[type="email"]';
const password = 'input[type="password"]';
const logsubmit = '.loginSubmit.nike-unite-component > input[type="button"]';
const myacc = '.li.member-nav-item.d-sm-ib.va-sm-m > button'; //this line contains error
(async () => {
const browser = await puppeteer.launch({headless: false, slowMo: 150});
const page = await browser.newPage();
await page.setViewport({ width: 1920, height: 1080 })
await page.goto('https://www.nike.com/launch/'); const AcceptCookies = '#cookie-settings-layout > div > div > div > div.ncss-row.mt5-sm.mb7-sm > div:nth-child(2) > button'; await page.click(loginBtn);
console.log("Login Button Clicked...");
await page.waitFor(5000);
console.log("email: " + emailVal);
await page.type(email, emailVal);
console.log("entered email");
await page.type(password, passwordVal);
console.log("waiting 0.5s");
await page.waitFor(500);
console.log("waiting done");
await page.click(logsubmit);
console.log("submitted"); await page.waitFor(10000); await page.click(myacc); await page.waitFor(10000);
await browser.close(); })();
I'm trying to get the correct selector - "const myacc=..."- to click account profile as shown in the picture (highlighted section) but instead I'm getting a selector error ("Error:No node found for selector:...."). How would you find it in this situation as their is no id?
Before Picture
After Picture
There are almost all of the elements contains a unique attribute for testing data-qa. I would recommend using it for testing, so replace all your selectors with it.
Here is the example for the 'my account' selector:
const myAcc = '[data-qa="user-name"]';
Also, you may not see that the selector was clicked due to screen size, so you will need to maximize screen size.

Using Puppeteer to find element by title

Assuming I have a link in an iframe without an id, where the only uniquely identifiable piece of information is the element title of this link, how would I go about finding it? It could look like this:
<a class="link spacer--double" href="#" tabindex="51" title="Click here to use new code">Use new code</a>
This is what I have attempted so far:
(async() => {
const browser = await puppeteer.launch({
headless: false
});
const page = await browser.newPage();
console.log("starting new page");
var contentHtml = fs.readFileSync('1-iframe.html', 'utf8');
await page.setContent(contentHtml);
const result = await page.evaluate(() => {
let elements = document.getElementById("framecontentscroll").innerText;
for (let element of elements)
console.log(element);
})
})();
But I don't seem to get anything in elements. The id of the iframe is "framecontentscroll".
Is there a way where I can go directly for the link element using it's title and a querySelector or something similar?
You can use the querySelector to select by title. See:
Select an element by title with JavaScript and tweak from the browser?

How to manipulate the DOM before in-page scripts are executed?

Using Puppeteer, how can I run a script in the page context, with the full DOM available, before the in-page JS is executed?
For example, how can I run the following script to remove alt attributes from img elements, before any of the page JS is run?
document.querySelectorAll('img[alt]').forEach(
e => e.removeAttribute('alt')
)
(page.evaluateOnNewDocument looks like it would be useful, but it appears to be executed before the page content is available--at the point at which it runs, the page is blank.)
I think the way to achieve what you are looking for is to perform:
set page.setJavaScriptEnabled(false)
enter the page
extract all the scripts and HTML without scripts
set page.setJavaScriptEnabled(true)
enter page.goto(`data:text/html,${HTMLWithoutScript}`) with HTML from step 3
execute your scripts
incject original extracted scripts page.addScriptTag({ content: script }) from step 3
Example
Here is a visualization of your problematic example:
const puppeteer = require('puppeteer');
const html = `
<html>
<head></head>
<body>
<img src="https://picsum.photos/200/300?image=1062" alt="dog ">
<img src="https://picsum.photos/200/300?image=1072" alt="car ">
<div class="alts">List of alts: </div>
<script>
const images = document.querySelectorAll('img');
const altsContainer = document.querySelector('.alts');
images.forEach(image => {
const alt = image.getAttribute('alt') || 'missing alt ';
altsContainer.insertAdjacentHTML('beforeend', alt);
})
</script>
</body>
</html>`;
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto(`data:text/html,${html}`);
await page.evaluate(() => {
document.querySelectorAll('img[alt]').forEach(
e => e.removeAttribute('alt')
)
});
await page.screenshot({ path: 'image.png' });
await browser.close();
})();
This code produce:
So remove alts is not working here.
solution
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setJavaScriptEnabled(false);
await page.goto(`data:text/html,${html}`);
const { script, HTMLWithoutScript } = await page.evaluate(() => {
const script = document.querySelector('script').innerHTML;
document.querySelector('script').innerHTML = '';
const HTMLWithoutScript = document.body.innerHTML;
return { script, HTMLWithoutScript }
});
await page.setJavaScriptEnabled(true);
await page.goto(`data:text/html,${HTMLWithoutScript}`);
await page.evaluate(() => {
document.querySelectorAll('img[alt]').forEach(
e => e.removeAttribute('alt')
)
});
await page.addScriptTag({ content: script });
await page.screenshot({ path: 'image.png' });
await browser.close();
})();
This will produce results as you expect in a question:
You can move your script tags to body instead of head. Then using document onload event you can execute a script. According to MDN this event fires when an object has been loaded. Below is the example code
function removeAlt(){
document.querySelectorAll('img[alt]').forEach((e)=>{
e.removeAttribute('alt');
});
}
<body onload="removeAlt()">
<img src="http://placehold.it/64x64" alt="1">
<img src="http://placehold.it/64x64" alt="2">
</body>
Let me know whether this fits into your requirement, I tested and function is removing alt tags from image

Categories

Resources