Skip to content

Instantly share code, notes, and snippets.

@Big-al
Created August 18, 2020 23:14
Show Gist options
  • Save Big-al/3fecac52b1629b5839fdedea995ef94f to your computer and use it in GitHub Desktop.
Save Big-al/3fecac52b1629b5839fdedea995ef94f to your computer and use it in GitHub Desktop.
Example on how to create a puppeteer browser instance using a singleton pattern in Typescript, with error handling and performance optimizations.
Import puppeteer from 'puppeteer';
Import { LoggingService, LogLevel } from './LoggingService';
const Logger: LoggingService = LoggingService.getInstance();
export class Browser implements IBrowser {
private browser: puppeteer.Browser;
private readonly TIMEOUT: number;
private readonly USER_AGENT = 'INSERT_USERAGENT';
constructor(_timeout: number = 30000) {
this.TIMEOUT = _timeout;
// For debugging try these Puppeteer Params:
// headless: true
// executablePath: PathToCustomChromiumInstall
// devtools: true
// slowMo: 2000
// Starting the async Init flow
(async () => {
await this.Init();
})();
}
public async GetBrowserInstance(): Promise<puppeteer.Browser> {
return this.browser;
}
public async CreatePage(URL: string, options: puppeteer.DirectNavigationOptions = {waitUntil: 'load'}): Promise<puppeteer.Page> {
const page = await this.browser.newPage();
await page.setViewport({
width: 1920,
height: 1080,
deviceScaleFactor: 1,
hasTouch: false,
isLandscape: false,
isMobile: false,
});
await page.setUserAgent(this.USER_AGENT);
await page.setJavaScriptEnabled(true);
await page.setDefaultNavigationTimeout(this.TIMEOUT);
//skips css fonts and images for performance and efficiency
await page.setRequestInterception(true);
page.on('request', (req) => {
if(req.resourceType() == 'font' || req.resourceType() == 'image' || req.resourceType() == 'stylesheet' ){
req.abort();
}
else {
req.continue();
}
});
try {
await page.goto(URL, options);
} catch (err) {
await page.close();
throw err;
}
return page;
}
private async Init(HeadLess: boolean = true, SlowDown: number = 0, DevTools: boolean = false) {
Logger.Log("Puppeteer browser init. Timeout set to: " + this.TIMEOUT.toString(), LogLevel.Trace);
this.browser = await this.StartBrowser(HeadLess, SlowDown, DevTools);
// Listen to Disconnect event, and restart.
this.browser.on('disconnected', async () => {
Logger.Log("Puppeteer browser crashed, Restarting browser.", LogLevel.Error);
await this.ReleaseBrowser();
if (this.browser && this.browser.process() != null) this.browser.process().kill('SIGINT');
await this.Init();
});
};
private async ReleaseBrowser() {
Logger.Log("Puppeteer browser releasing and closing.", LogLevel.Warning);
if (this.browser) await this.browser.close();
}
private async StartBrowser(HeadLess: boolean, SlowDown: number, DevTools: boolean): Promise<puppeteer.Browser> {
Logger.Log("Puppeteer browser starting up with slowdown set to: " + SlowDown, LogLevel.Trace);
return await puppeteer.launch({
headless: HeadLess,
devtools: DevTools,
ignoreHTTPSErrors: true,
slowMo: SlowDown,
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage',
'--disable-accelerated-2d-canvas',
'--no-first-run',
'--no-zygote',
'--disable-gpu'
// '--single-process'
// '--user-data-dir=./'
]
});
}
}
export interface IBrowser {
GetBrowserInstance(): Promise<puppeteer.Browser>;
CreatePage(URL: string, options: puppeteer.DirectNavigationOptions): Promise<puppeteer.Page>;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment