puppeteer-pro
Version:
A simple puppeteer wrapper to enable useful plugins with ease
278 lines • 10.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Plugin = void 0;
exports.connect = connect;
exports.launch = launch;
/* eslint-disable prefer-rest-params */
const events = require("events");
// Puppeteer Defaults
const Puppeteer = require("puppeteer");
async function connect(options) {
const browser = await Puppeteer.connect(options || {});
return createBrowser(browser);
}
async function launch(options) {
if (!options)
options = {};
process.env.PUPPETEER_DISABLE_HEADLESS_WARNING = 'true';
const browser = await Puppeteer.launch({ defaultViewport: undefined, ...options });
return createBrowser(browser);
}
async function createBrowser(puppeteerBrowser) {
const browser = puppeteerBrowser;
const _close = browser.close;
browser.close = async () => {
await _close.apply(browser);
browser.browserEvents.emit('close');
};
const _createBrowserContext = browser.createBrowserContext;
browser.createBrowserContext = async (options) => {
const context = await _createBrowserContext.apply(browser, options);
return createBrowserContext(context);
};
const _newPage = browser.newPage;
browser.newPage = async () => {
const page = await _newPage.apply(browser);
return newPage(page);
};
addPluginSupport(browser);
return browser;
}
async function createBrowserContext(puppeteerBrowserContext) {
const browser = puppeteerBrowserContext;
const _close = browser.close;
browser.close = async () => {
await _close.apply(browser);
browser.browserEvents.emit('close');
};
const _newPage = browser.newPage;
browser.newPage = async () => {
const page = await _newPage.apply(browser);
return newPage(page);
};
addPluginSupport(browser);
return browser;
}
function newPage(oldPage) {
const page = oldPage;
page.waitAndClick = async (selector, waitOptions, clickOptions) => {
await page.waitForSelector(selector, waitOptions);
await page.click(selector, clickOptions);
};
page.waitAndType = async (selector, text, waitOptions, typeOptions) => {
await page.waitForSelector(selector, waitOptions);
await page.type(selector, text, typeOptions);
};
return page;
}
function addPluginSupport(browser) {
browser.plugins = [];
browser.browserEvents = new events.EventEmitter();
browser.interceptions = 0;
browser.addPlugin = async (plugin) => {
browser.plugins.push(plugin);
await plugin.init(browser);
};
browser.clearPlugins = () => {
browser.plugins.forEach(async (plugin) => {
await plugin.stop();
});
browser.plugins = [];
};
browser.anonymizeUserAgent = async () => {
const plugin = new anonymize_user_agent_1.AnonymizeUserAgentPlugin();
await browser.addPlugin(plugin);
return plugin;
};
browser.avoidDetection = async (options) => {
const plugin = new avoid_detection_1.AvoidDetectionPlugin(options);
await browser.addPlugin(plugin);
return plugin;
};
browser.blockResources = async (...resources) => {
const plugin = new block_resources_1.BlockResourcesPlugin(resources);
await browser.addPlugin(plugin);
return plugin;
};
browser.disableDialogs = async (logMessages = false) => {
const plugin = new disable_dialogs_1.DisableDialogsPlugin(logMessages);
await browser.addPlugin(plugin);
return plugin;
};
browser.manageCookies = async (opts) => {
const plugin = new manage_cookies_1.ManageCookiesPlugin(opts);
await browser.addPlugin(plugin);
return plugin;
};
browser.manageLocalStorage = async (opts) => {
const plugin = new manage_localstorage_1.ManageLocalStoragePlugin(opts);
await browser.addPlugin(plugin);
return plugin;
};
browser.solveRecaptchas = async (accessToken) => {
const plugin = new solve_recaptchas_1.SolveRecaptchasPlugin(accessToken);
await browser.addPlugin(plugin);
return plugin;
};
}
class Plugin {
constructor() {
this.browser = null;
this.initialized = false;
this.startCounter = 0;
this.dependencies = [];
this.requiresInterception = false;
}
get isInitialized() { return this.initialized; }
get isStopped() { return this.startCounter === 0; }
async addDependency(plugin) {
this.dependencies.push(plugin);
}
async init(browser) {
if (this.initialized)
return;
this.browser = browser;
const offOnClose = [];
browser.browserEvents.once('close', async () => {
offOnClose.forEach(fn => fn());
this.browser = null;
this.initialized = false;
this.startCounter = 0;
await this.onClose();
});
this.startCounter++;
const thisOnTargetCreated = this.onTargetCreated.bind(this);
browser.on('targetcreated', thisOnTargetCreated);
offOnClose.push(() => browser.off('targetcreated', thisOnTargetCreated));
this.initialized = true;
this.dependencies.forEach(x => x.init(browser));
return this.afterLaunch(browser);
}
async afterLaunch(_browser) { null; }
async onClose() { null; }
async onTargetCreated(target) {
if (this.isStopped)
return;
if (target.type() !== 'page')
return;
const page = newPage(await target.page());
if (page.isClosed())
return;
const offOnClose = [];
page.once('close', async () => {
offOnClose.forEach(fn => fn());
});
const requestHandlers = [];
page.on('request', request => {
const _respond = request.respond;
let responded = 0;
let respondArgs;
const _abort = request.abort;
let aborted = 0;
let abortArgs;
const _continue = request.continue;
let continued = 0;
let continueArgs;
const handleRequest = async function () {
const total = responded + aborted + continued;
if (!request._interceptionHandled) {
if (responded === 1)
await _respond.apply(request, respondArgs);
else if (responded === 0 && aborted >= 1 && total === requestHandlers.length)
await _abort.apply(request, abortArgs);
else if (continued === requestHandlers.length)
await _continue.apply(request, continueArgs);
}
};
request.respond = async function () { responded++; respondArgs = respondArgs || arguments; await handleRequest(); };
request.abort = async function () { aborted++; abortArgs = abortArgs || arguments; await handleRequest(); };
request.continue = async function () { continued++; continueArgs = continueArgs || arguments; await handleRequest(); };
requestHandlers.forEach(handler => handler(request));
});
const _pageOn = page.on;
page.on = function async(eventName, handler) {
if (eventName === 'request') {
requestHandlers.push(handler);
return page;
}
else {
return _pageOn.call(page, eventName, handler);
}
};
if (this.requiresInterception) {
await page.setRequestInterception(true);
const thisOnRequest = this.onRequest.bind(this);
page.on('request', thisOnRequest);
offOnClose.push(() => page.off('request', thisOnRequest));
}
const thisOnDialog = this.onDialog.bind(this);
page.on('dialog', thisOnDialog);
offOnClose.push(() => page.off('dialog', thisOnDialog));
await this.onPageCreated(page);
}
async onPageCreated(_page) { null; }
async onRequest(request) {
const interceptionHandled = request._interceptionHandled;
if (interceptionHandled)
return;
if (this.isStopped)
return request.continue();
await this.processRequest(request);
}
async processRequest(_request) { null; }
async onDialog(dialog) {
if (this.isStopped)
return;
const _dismiss = dialog.dismiss;
dialog.dismiss = async () => {
if (dialog.handled)
return;
await _dismiss.apply(dialog);
};
await this.processDialog(dialog);
}
async processDialog(_dialog) { null; }
async beforeRestart() { null; }
async restart() {
await this.beforeRestart();
this.startCounter++;
if (this.requiresInterception && this.browser)
this.browser.interceptions++;
this.dependencies.forEach(x => x.restart());
await this.afterRestart();
}
async afterRestart() { null; }
async beforeStop() { null; }
async stop() {
await this.beforeStop();
this.startCounter--;
if (this.requiresInterception && this.browser)
this.browser.interceptions--;
if (this.browser && this.browser.interceptions === 0) {
const pages = await this.browser.pages();
pages.filter(x => !x.isClosed()).forEach(async (page) => {
await page.setRequestInterception(false);
});
}
this.dependencies.forEach(x => x.stop());
await this.afterStop();
}
async afterStop() { null; }
async getFirstPage() {
if (!this.browser)
return null;
const pages = await this.browser.pages();
const openPages = pages.filter(x => !x.isClosed());
const activePages = pages.filter(x => x.url() !== 'about:blank');
return activePages[0] || openPages[0];
}
}
exports.Plugin = Plugin;
const anonymize_user_agent_1 = require("./plugins/anonymize.user.agent");
const avoid_detection_1 = require("./plugins/avoid.detection");
const block_resources_1 = require("./plugins/block.resources");
const disable_dialogs_1 = require("./plugins/disable.dialogs");
const manage_cookies_1 = require("./plugins/manage.cookies");
const manage_localstorage_1 = require("./plugins/manage.localstorage");
const solve_recaptchas_1 = require("./plugins/solve.recaptchas");
//# sourceMappingURL=index.js.map