Puppeteer: How to get DOM after switching chromium Tabs? - node.js

Right now I am getting all the DOM from Only one Tab which is Default.But I want to capture DOM from Each tab after Switching.
Here is the my sample code.
async function RedirectToLogin(page)
{
console.log(page.content());
}
async function main() {
const browser = await puppeteer.launch({headless: false});
const page = await browser.newPage();
await page.setViewport({
width: 2000,
height: 1000,
});
await page.goto('https://www.google.com/');
console.log('clicked');
browser.on('targetchanged', () => RedirectToLogin(page));
count++;
}
main();

You can get the URL for the currently active page by doing the following:
const url = await page.url();
console.log(url);

Related

Can't click link using puppeteer - Thingiverse

I'm trying to automate away downloading multiple files on thingiverse. I choose an object at random. But I'm having a hard time locating the link I need, clicking and then downloading. Has someone run into this before can I get some help?
I've tried several other variations.
import puppeteer from 'puppeteer';
async function main() {
const browser = await puppeteer.launch({
headless: true,
});
const page = await browser.newPage();
const response = await page.goto('https://www.thingiverse.com/thing:2033856/files');
const buttons = await page.$x(`//a[contains(text(), 'Download')]`);
if(buttons.length > 0){
console.log(buttons.length);
} else {
console.log('no buttons');
}
await wait(5000);
await browser.close();
return 'Finish';
}
async function wait(time: number) {
return new Promise(function (resolve) {
setTimeout(resolve, time);
});
}
function start() {
main()
.then((test) => console.log('DONE'))
.catch((reason) => console.log('Error: ', reason));
}
start();
Download Page
Code
I was able to get it to work.
The selector is: a[class^="ThingFile__download"]
Puppeteer is: const puppeteer = require('puppeteer-extra');
Before the await page.goto() I always recommend setting the viewport:
await page.setViewport({width: 1920, height: 720});
After that is set, change the await page.goto() to have a waitUntil option:
const response = await page.goto('https://www.thingiverse.com/thing:2033856/files', { waitUntil: 'networkidle0' }); // wait until page load
Next, this is a very important part. You have to do what is called waitForSelector() or waitForFunction().
I added both of these lines of code after the const response:
await page.waitForSelector('a[class^="ThingFile__download"]', {visible: true})
await page.waitForFunction("document.querySelector('a[class^=\"ThingFile__download\"]') && document.querySelector('a[class^=\"ThingFile__download\"]').clientHeight != 0");
Next, get the buttons. For my testing I just grabbed the button href.
const buttons = await page.$eval('a[class^="ThingFile__download"]', anchor => anchor.getAttribute('href'));
Lastly, do not check the .length of this variable. In this case we are just returning the href value which is a string. You will get a Promise of an ElementHandle when you try getting just the button:
const button = await page.$('a[class^="ThingFile__download"]');
console.log(button)
if (button) { ... }
Now if you change that page.$ to be page.$$, you will be getting a Promise of an Array<ElementHandle>, and will be able to use .length there.
const buttonsAll = await page.$$('a[class^="ThingFile__download"]');
console.log(buttonsAll)
if (buttons.length > 0) { ... }
Hopefully this helps, and if you can't figure it out I can post my full source later if I have time to make it look better.

Puppeteer not clicking button with text

I have a simple function that tries to accept the cookies
Here's my code:
(async () => {
const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
await page.goto('https://www.sport1.de/live/darts-sport');
await page.click('button[text=AKZEPTIEREN]');
// await page.screenshot({ path: 'example.png' });
// await browser.close();
})();
The cookie popup is placed in an iframe. You have to switch to iframe by contentFrame to be able to click on the accept button.
Also, if you want to filter by textContent, you need to use XPath. With CSS selector you can't get elements by its textContent.
const cookiePopUpIframeElement=await page.$("iframe[id='sp_message_iframe_373079']");
const cookiePopUpIframe=await cookiePopUpIframeElement.contentFrame();
const acceptElementToClick = await cookiePopUpIframe.$x("//button[text()='AKZEPTIEREN']");
await acceptElementToClick[0].click();

Puppeteer Failing for more than 11 Urls

I would like to ask, whats the best way to capture more than 20 screenshots or different Urls?
I have tried the following code.
async function sCapture(url, site_name) {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setViewport({ width: 1280, height: 720 })
await page.goto(url);
await page.screenshot({
path:`statusImage/${site_name}.jpg`
});
await browser.close();
}
Am getting the Urls from my DB like this.
db_connection.promise()
.execute("SELECT * FROM `urls`")
.then(([rows]) => {
rows.forEach(user => {
const url = user.link;
const name = user.link_name;
console.log(name);
sCapture(url, name)
});
db_connection.end();
}).catch(err => {
console.log(err);
});
Because my DB Table contains more than 50 urls
Before, I was getting this error:
MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 exit listeners added. Use emitter.setMaxListeners() to increase limit
After I added the line below. Its just killing my server and I have to do a manual reboot for my site to work again.
require('events').EventEmitter.prototype._maxListeners = 100;
I will appreciate any help rendered.
I think your current code actually starts a new browser instance for each URL you want to fetch and I don't think you need to do that. A separate page is enough. Also, you are currently making all those requests in parallel, which will tax your machine more than doing it in sequence. Putting these two changes together give you something like this:
let browser;
async function sCapture(url, site_name) {
const page = await browser.newPage();
await page.setViewport({ width: 1280, height: 720 })
await page.goto(url);
await page.screenshot({
path:`statusImage/${site_name}.jpg`
});
}
const doit = () => {
db_connection.promise()
.execute("SELECT * FROM `urls`")
.then(([rows]) => {
rows.forEach(async user => {
const url = user.link;
const name = user.link_name;
console.log(name);
await sCapture(url, name);
});
db_connection.end();
}).catch(err => {
console.log(err);
});
}
(async () => {
browser = await puppeteer.launch();
doit();
await browser.close();
})();

Puppeteer doesn't recognize selector with just type and class but accepts full selector

I'm trying to click on a cookiewall on a webpage, but Puppeteer refuses to recognize the short selector with just the type and class selector (button.button-action). Changing this to the full CSS selector fixes the problem but isn't a viable solution since any chance in parent elements can break the selector. As far as I know this shouldn't be a problem because on the page in question using document.querySelector("button.button-action") also returns the element I'm trying to click.
The code that doesn't work:
const puppeteer = require('puppeteer');
const main = async () => {
const browser = await puppeteer.launch({headless: false,});
const page = await browser.newPage();
await page.goto("https://www.euclaim.nl/check-uw-vlucht#/problem", { waitUntil: 'networkidle2' });
const cookiewall = await page.waitForSelector("button.button-action", {visible: true});
await cookiewall.click();
};
main();
The code that does work:
const puppeteer = require('puppeteer');
const main = async () => {
const browser = await puppeteer.launch({headless: false,});
const page = await browser.newPage();
await page.goto("https://www.euclaim.nl/check-uw-vlucht#/problem", { waitUntil: 'networkidle2' });
const cookiewall = await page.waitForSelector("#InfoPopupContainer > div.ipBody > div > div > div.row.actionButtonContainer.mobileText > button", {visible: true});
await cookiewall.click();
};
main();
The problem is that you have three button.button-action there. And the first match is not visible.
One thing you could do is waitForSelector but without the visible bit (because it will check the first button).
And then iterate through all items checking which item is clickable.
await page.waitForSelector("button.button-action");
const actions = await page.$$("button.button-action");
for(let action of actions) {
if(await action.boundingBox()){
await action.click();
break;
}
}

Switching between tabs with puppeteer

I need a example how to switch betweens tabs with puppeteer
this is currently what i have:
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({
headless: false, // launch headful mode
});
const page = await browser.newPage();
await page.setViewport({ width: 1920, height: 1080 });
await page.goto('https://URL1.com');
const pagee = await browser.newPage();
await pagee.setViewport({ width: 1920, height: 1080 });
await pagee.goto('https://URL2.com');
})();
So it opens 2 tabs first:Url1, second: Url2
What i need:
first Tab do some action...
go to second Tab do some action...
go back to first Tab do some action...
can you guys please provide me a example ?
thank you
The bit of code you need is page.bringToFront See here
A working script below. Please note I have adding in a wait between tab switching else the script runs to fast :)
const puppeteer = require('puppeteer');
async function run() {
const browser = await puppeteer.launch( {
headless: false
});
const page1 = await browser.newPage();
await page1.goto('https://www.google.com');
const page2 = await browser.newPage();
await page2.goto('https://www.bing.com');
const pageList = await browser.pages();
console.log("NUMBER TABS:", pageList.length);
//switch tabs here
await page1.bringToFront();
blockingWait(1);
await page2.bringToFront();
blockingWait(1);
await page1.bringToFront();
blockingWait(4);
await browser.close();
};
function blockingWait(seconds) {
//simple blocking technique (wait...)
var waitTill = new Date(new Date().getTime() + seconds * 1000);
while(waitTill > new Date()){}
}
run();
In the case of clicking on a link/button to open a new tab with a new URL, the following worked for me.
await page.click('#your_Button_To_Open_New_Tab_With_Different_URL')
await page.waitForTimeout(3000)
const pageList = await browser.pages();
await console.log("NUMBER TABS:", pageList.length);
await console.log("NUMBER TABS:", pageList[2]._target._targetInfo.url);
await page.waitForTimeout(3000)
page2 = await browser.newPage()
const redirectedUrlforService = pageList[2]._target._targetInfo.url;
await page2.goto(redirectedUrlforService)
await page2.bringToFront();
await page2.waitForTimeout(3000)
await page2.waitForSelector('#A_Selector_On_New_Page_To_Verify_That_You_Can_Perform_Your_Actions_There')
Waiting for idle network requests might not always work if the responses involve long-running DOM updates that take longer than 500ms to trigger a render.

Resources