puppet-browser-handler
Version:
A Node.js package that provides a convenient wrapper around Puppeteer for handling browser automation tasks. This package simplifies common browser operations like navigation, downloads management, screenshots, and page interactions.
226 lines (200 loc) • 5.52 kB
JavaScript
import puppeteer from "puppeteer";
import { Logger } from "logger-standard";
import fs from "fs";
const SERVICE_NAME = "BrowserHandler";
export default class BrowserHandler {
constructor(downloadPath = null) {
this._logger = new Logger({
service: SERVICE_NAME,
showDate: true,
});
this._page = null;
this._browser = null;
this.downloadPath = downloadPath;
}
async configureDownloadsFolder() {
try {
await this._page._client().send("Page.setDownloadBehavior", {
behavior: "allow",
downloadPath: this.downloadPath,
});
if (!fs.existsSync(this.downloadPath)) {
fs.mkdirSync(this.downloadPath, { recursive: true });
this._logger.info("Downloads folder successfully created");
}
this._logger.info("Downloads folder configuration complete");
} catch (error) {
throw error;
}
}
async openBrowser(cookies = null, headless = "new", slowMo = 30) {
try {
this._browser = await puppeteer.launch({
headless,
pipe: true,
executablePath: "/usr/bin/google-chrome",
args: ["--disable-setuid-sandbox", "--no-sandbox"],
slowMo,
});
this._page = await this._browser.newPage();
this._logger.info("Browser initialized successfully");
await this.configureDownloadsFolder();
await this._page.setDefaultNavigationTimeout(0);
await this._page.setViewport({ width: 1920, height: 1080 });
if (cookies) {
for (let cookie of cookies) {
await this._page.setCookie({
name: cookie.name,
value: cookie.value,
domain: cookie.domain,
});
this._logger.info(`"${cookie.name}" cookie configured successfully`);
}
}
} catch (error) {
this._logger.error(error.message);
}
}
async closeBrowser() {
try {
if (this._page) {
await this._page.close();
}
if (this._browser) {
await this._browser.close();
}
this._logger.info("Browser terminated successfully");
} catch (error) {
this._logger.error(error.message);
}
}
async sleep(limit, start = 0) {
try {
const range = limit - start;
const randomSeconds = Math.random() * range + start;
const pause = Math.floor(randomSeconds * 1000);
return new Promise((resolve) => setTimeout(resolve, pause));
} catch (error) {
this._logger.error(error.message);
}
}
async screenshot(fileName, fileExt) {
await this._page.screenshot({
path: `${this.downloadPath}/${fileName}.${fileExt}`,
fullPage: true,
type: "png",
});
}
async goToPage(url) {
try {
this._logger.info(`Navigating to ${url}`);
await this._page.goto(url);
} catch (error) {
this._logger.error(error.message);
}
}
async scrollDown() {
try {
await this._page.evaluate(async () => {
await new Promise((resolve, reject) => {
let totalHeight = 0;
const distance = 1000;
const timer = setInterval(() => {
const scrollHeight = document.body.scrollHeight;
window.scrollBy(0, distance);
totalHeight += distance;
if (totalHeight >= scrollHeight) {
clearInterval(timer);
resolve();
}
}, 1000);
});
});
} catch (error) {
this._logger.error(error.message);
}
}
async click(selector) {
try {
if (!this.elementExists(selector)) {
throw new Error(`Failed to click element: ${selector}`);
}
await this._page.click(selector);
} catch (error) {
throw error;
}
}
async getElementHrefLink(selector) {
try {
if (!this.elementExists(selector)) {
throw new Error(`Failed to get href link from element: ${selector}`);
}
return await this._page.$eval(selector, (el) => el.href);
} catch (error) {
throw error;
}
}
async getElementsHrefLink(elements) {
try {
const links = [];
let $ = await this._page.content();
$ = cheerio.load($);
for (const elm of $(elements)) {
const link = $(elm).attr("href");
if (link) {
links.push(link);
}
}
return links;
} catch (error) {
throw error;
}
}
async getElementBySelector(selector) {
try {
if (!this.elementExists(selector)) {
throw new Error("The element cannot be found.");
}
let $ = await this._page.content();
$ = cheerio.load($);
let element = $(selector);
if (element.length > 1) {
element = element[0];
}
return element;
} catch (error) {
throw error;
}
}
async getElementsBySelector(selector) {
try {
let $ = await this._page.content();
$ = cheerio.load($);
return await $(selector);
} catch (error) {
throw error;
}
}
async elementExists(selector, timeout = 5000) {
try {
await this._page.waitForSelector(selector, {
visible: true,
timeout,
});
return true;
} catch (error) {
return false;
}
}
async isElementDisabled(element) {
return await element.evaluate((element) => element.disabled);
}
async openNewPage() {
this._page = await this._browser.newPage();
}
async closeCurrentPage() {
if (this._page) {
await this._page.close();
}
}
}