Skip to content

Instantly share code, notes, and snippets.

@robertkirkman
Last active November 19, 2024 17:19
Show Gist options
  • Save robertkirkman/0c2f3426024069546ed9b7bb2f26cb99 to your computer and use it in GitHub Desktop.
Save robertkirkman/0c2f3426024069546ed9b7bb2f26cb99 to your computer and use it in GitHub Desktop.
How To Run Node.js Puppeteer On Android

Headless Mode

Important

  • Open Termux, then run these commands
pkg install x11-repo
pkg install nodejs firefox # I will attempt to upstream the patch into the firefox package that comes from this command
npm install puppeteer-core
curl -O https://gist.githubusercontent.com/robertkirkman/0c2f3426024069546ed9b7bb2f26cb99/raw/d9ce8ebd95df85584a10718f4198c746fcefe4eb/puppeteer_search_headless.js
node puppeteer_search_headless.js
cat puppeteer_faq.html

Graphical Mode

Note

This mode is the most stable and uses the llvmpipe software renderer for all graphics

pkg install x11-repo
pkg install nodejs firefox termux-x11-nightly xfce
npm install puppeteer-core
export TERMUX_X11_XSTARTUP="xfce4-session"
termux-x11 &
export DISPLAY=:0
curl -O https://gist.githubusercontent.com/robertkirkman/0c2f3426024069546ed9b7bb2f26cb99/raw/d9ce8ebd95df85584a10718f4198c746fcefe4eb/puppeteer_search_graphical.js
node puppeteer_search_graphical.js
  • GPU acceleration for WebGL:

Note

Do this instead to get GPU acceleration with WebGL->Firefox->virglrenderer-android->OpenGL ES 3.0 other APIs besides WebGL (like normal page loading) continue to use software rendering. This mode is not as stable, it can crash, sometimes. This example does not demo the WebGL functionality, it's just the commands to enable it.

pkg install x11-repo
pkg install nodejs firefox termux-x11-nightly xfce virglrenderer-android
npm install puppeteer-core
export TERMUX_X11_XSTARTUP="xfce4-session"
termux-x11 &
virgl_test_server_android &
export DISPLAY=:0 GALLIUM_DRIVER=virpipe
curl -O https://gist.githubusercontent.com/robertkirkman/0c2f3426024069546ed9b7bb2f26cb99/raw/d9ce8ebd95df85584a10718f4198c746fcefe4eb/puppeteer_search_graphical.js
node puppeteer_search_graphical.js
const puppeteer = require('puppeteer-core');
(async () => {
// variables
const puppeteer_xpath = "//h3[contains(text(), 'Puppeteer')]";
const faq_xpath = "//a[contains(text(), 'FAQ')]";
const width = 1450
const height = 1200
// open firefox
const browser = await puppeteer.launch({
product: 'firefox',
browser: 'firefox',
executablePath: '/data/data/com.termux/files/usr/bin/firefox',
headless: false,
args: ['-width', width.toString(), '-height', height.toString()],
});
// open new tab
const page = await browser.newPage();
// set tab viewport to correct dimensions
await page.setViewport({
width: width,
height: height,
deviceScaleFactor: 1,
});
// go to google.com
await page.goto('https://www.google.com/', {
waitUntil: "domcontentloaded",
});
// type in search box
await page.type('textarea', 'puppeteer');
// press enter
await page.keyboard.press('Enter');
// wait for result
await page.waitForSelector('xpath/' + puppeteer_xpath);
// click link
const puppeteerURL = await page.evaluate((xpath) => {
const result = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
if (result.singleNodeValue) {
result.singleNodeValue.click();
return true;
}
return false;
}, puppeteer_xpath);
// quit if link not found
if (!puppeteerURL) {
await browser.close();
return;
}
// wait for result
await page.waitForSelector('xpath/' + faq_xpath);
// click link
const faqURL = await page.evaluate((xpath) => {
const result = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
if (result.singleNodeValue) {
result.singleNodeValue.click();
return true;
}
return false;
}, faq_xpath);
// quit if link not found
if (!faqURL) {
await browser.close();
return;
}
// wait for 10 seconds
await new Promise(resolve => setTimeout(resolve, 10000));
// close browser
await browser.close();
})();
const puppeteer = require('puppeteer-core');
const fs = require("fs");
(async () => {
// variables
const puppeteer_xpath = "//h3[contains(text(), 'Puppeteer')]";
const faq_xpath = "//a[contains(text(), 'FAQ')]";
const width = 1450
const height = 1200
// open firefox
const browser = await puppeteer.launch({
product: 'firefox',
browser: 'firefox',
executablePath: '/data/data/com.termux/files/usr/bin/firefox',
headless: true,
args: ['-width', width.toString(), '-height', height.toString()],
});
// open new tab
const page = await browser.newPage();
// set tab viewport to correct dimensions
await page.setViewport({
width: width,
height: height,
deviceScaleFactor: 1,
});
// go to google.com
await page.goto('https://www.google.com/', {
waitUntil: "domcontentloaded",
});
// type in search box
await page.type('textarea', 'puppeteer');
// press enter
await page.keyboard.press('Enter');
// wait for result
await page.waitForSelector('xpath/' + puppeteer_xpath);
// click link
const puppeteerURL = await page.evaluate((xpath) => {
const result = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
if (result.singleNodeValue) {
result.singleNodeValue.click();
return true;
}
return false;
}, puppeteer_xpath);
// quit if link not found
if (!puppeteerURL) {
await browser.close();
return;
}
// wait for result
await page.waitForSelector('xpath/' + faq_xpath);
// click link
const faqURL = await page.evaluate((xpath) => {
const result = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
if (result.singleNodeValue) {
result.singleNodeValue.click();
return true;
}
return false;
}, faq_xpath);
// quit if link not found
if (!faqURL) {
await browser.close();
return;
}
// sleep for 10 seconds
await new Promise(resolve => setTimeout(resolve, 10000));
// save page as file
const html = await page.content();
fs.writeFileSync("puppeteer_faq.html", html);
// close browser
await browser.close();
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment