Reputation: 43
when i use click method in normal browser screen_resolution then it is work but when i set in mobile device mode with the help of browser mobile screen toolbar then this method not work
My high-level goal is just click on button in mobile device toolbar because without mobile device toolbar clicking on button is too easy with page.click("#answer-buttons > button:nth-child(1)")
but this function not work when we switch to mobile device toolbar .
const delay = async (ms) => {
return new Promise((resolve) => setTimeout(resolve, ms));
};
async function performAutomation(websocketUrl, targetUrl) {
const browser = await puppeteer.connect({ browserWSEndpoint: websocketUrl });
const pages = await browser.pages();
const page = pages[0];
await page.goto(targetUrl);
const selector = "#answer-buttons > button:nth-child(1)";
await page.click(selector)
await delay(30000);
setTimeout(async () => {
await browser.close();
}, 5000);
}
Upvotes: 0
Views: 58
Reputation: 57195
This is a very simple static site with light vanilla JS and no backend, so I suggest digging into the dev tools and page sources yourself as an exercise. Understand the page before automating. Focus on the real goal (automating the quiz) rather than the step you might be stuck on in your attempt (clicking a button).
For the sample quiz you linked, there are two questions, and they're both live on the page right from the start.
The first question has 4 buttons which aren't hidden, and the second question has 4 buttons that are hidden.
When you answer the first question, it runs some JS that makes the second question visible.
So if you want to answer both questions randomly, all you need to do is click on one button inside each box, without worrying about its visible state:
import puppeteer from "puppeteer"; // ^23.10.4
let browser;
(async () => {
browser = await puppeteer.launch({headless: true});
const [page] = await browser.pages();
await page.goto("https://playquiz.storiesinsta.online/", {
waitUntil: "domcontentloaded",
});
const navPromise = page.waitForNavigation({
waitUntil: "domcontentloaded",
});
await page.$$eval("#question-container > div", questions => {
for (const question of questions) {
const buttons = [
...question.querySelectorAll(".answer-button"),
];
buttons[~~(Math.random() * buttons.length)].click();
}
});
await navPromise;
await page.screenshot({path: "finished-sample-quiz.png"});
})()
.catch(err => console.error(err))
.finally(() => browser?.close());
Note that the other quizzes on the site are different than the sample one. Each quiz is on a single page, but only one question exists at a time, so you'll need to wait for either the button text to change, or just repeatedly click since the DOM click updates are basically instantaneous (the site isn't making any server requests, it's just a bit of simple JS).
Digging into the page source for any quiz, all of the correct answers are right there:
const quizQuestions = [
{
question_no: '1 / 20',
question: 'What is the primary goal of artificial intelligence (AI)?',
options: ["To make machines more human-like", "To make machines intelligent and capable of performing tasks that require human intelligence", "To replace humans in the workforce", "To create robots with emotions"],
correctAnswer: "To make machines intelligent and capable of performing tasks that require human intelligence"
},
{
question_no: '2 / 20',
question: 'Which of the following is NOT a subfield of artificial intelligence?',
options: ["Machine Learning", "Robotics", "Cyber Security", "Natural Language Processing"],
correctAnswer: "Cyber Security"
},
// ...
]
Here's code to play through one of the quizzes for a perfect score:
import puppeteer from "puppeteer";
let browser;
(async () => {
browser = await puppeteer.launch({headless: false});
const [page] = await browser.pages();
await page.goto(
"https://playquiz.storiesinsta.online/artificial_intelligence/index.html",
{waitUntil: "domcontentloaded"}
);
const questions = await page.$$eval("script", scripts => {
const script = scripts.find(script =>
script.textContent.includes("const quizQuestions =")
).textContent;
return eval(script.match(/const quizQuestions = (\[.*?\]);/s)[1]);
});
await page.$eval("#start-button", el => el.click());
for (const {correctAnswer} of questions) {
await page.locator(`::-p-text(${correctAnswer})`).click();
}
await page.screenshot({path: "finished-quiz.png"});
})()
.catch(err => console.error(err))
.finally(() => browser?.close());
If you don't like using eval
to parse the JSON (it should be safe enough to run in the sandboxed browser), you can use JSON5.
Regarding your concerns about mobile behavior, the site is narrow and basically all-mobile, so it works the same in pretty much any viewport size.
But in general, smaller viewports can cause some elements to become hidden and unclickable, or require scrolling to bring into view, and site behavior can be different as it typically is in a browser on different viewports. I've bypassed visibility checks altogether in some of my clicks in this post.
But beyond that, Puppeteer doesn't care what the viewport size is--it's not like page.click()
stops working altogether on mobile viewports. Whatever behavior you're concerned about is probably related to logical problems in your code or visibility in the particular site you're automating rather than the Puppeteer library itself.
A final note: avoid sleeping.
Upvotes: 0