Rename to hkt.sh
This commit is contained in:
21
node_modules/puppeteer-extra/LICENSE
generated
vendored
Normal file
21
node_modules/puppeteer-extra/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2019 berstend <github@berstend.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
8
node_modules/puppeteer-extra/dist/ambient.d.ts
generated
vendored
Normal file
8
node_modules/puppeteer-extra/dist/ambient.d.ts
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
export {}
|
||||
|
||||
// https://github.com/sindresorhus/type-fest/issues/19
|
||||
declare global {
|
||||
interface SymbolConstructor {
|
||||
readonly observable: symbol
|
||||
}
|
||||
}
|
||||
470
node_modules/puppeteer-extra/dist/index.cjs.js
generated
vendored
Normal file
470
node_modules/puppeteer-extra/dist/index.cjs.js
generated
vendored
Normal file
@@ -0,0 +1,470 @@
|
||||
/*!
|
||||
* puppeteer-extra v3.3.5 by berstend
|
||||
* https://github.com/berstend/puppeteer-extra
|
||||
* @license MIT
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
|
||||
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
|
||||
|
||||
var Debug = _interopDefault(require('debug'));
|
||||
var merge = _interopDefault(require('deepmerge'));
|
||||
|
||||
const debug = Debug('puppeteer-extra');
|
||||
/**
|
||||
* Modular plugin framework to teach `puppeteer` new tricks.
|
||||
*
|
||||
* This module acts as a drop-in replacement for `puppeteer`.
|
||||
*
|
||||
* Allows PuppeteerExtraPlugin's to register themselves and
|
||||
* to extend puppeteer with additional functionality.
|
||||
*
|
||||
* @class PuppeteerExtra
|
||||
* @implements {VanillaPuppeteer}
|
||||
*
|
||||
* @example
|
||||
* const puppeteer = require('puppeteer-extra')
|
||||
* puppeteer.use(require('puppeteer-extra-plugin-anonymize-ua')())
|
||||
* puppeteer.use(require('puppeteer-extra-plugin-font-size')({defaultFontSize: 18}))
|
||||
*
|
||||
* ;(async () => {
|
||||
* const browser = await puppeteer.launch({headless: false})
|
||||
* const page = await browser.newPage()
|
||||
* await page.goto('http://example.com', {waitUntil: 'domcontentloaded'})
|
||||
* await browser.close()
|
||||
* })()
|
||||
*/
|
||||
class PuppeteerExtra {
|
||||
constructor(_pptr, _requireError) {
|
||||
this._pptr = _pptr;
|
||||
this._requireError = _requireError;
|
||||
this._plugins = [];
|
||||
}
|
||||
/**
|
||||
* The **main interface** to register `puppeteer-extra` plugins.
|
||||
*
|
||||
* @example
|
||||
* puppeteer.use(plugin1).use(plugin2)
|
||||
*
|
||||
* @see [PuppeteerExtraPlugin]
|
||||
*
|
||||
* @return The same `PuppeteerExtra` instance (for optional chaining)
|
||||
*/
|
||||
use(plugin) {
|
||||
if (typeof plugin !== 'object' || !plugin._isPuppeteerExtraPlugin) {
|
||||
console.error(`Warning: Plugin is not derived from PuppeteerExtraPlugin, ignoring.`, plugin);
|
||||
return this;
|
||||
}
|
||||
if (!plugin.name) {
|
||||
console.error(`Warning: Plugin with no name registering, ignoring.`, plugin);
|
||||
return this;
|
||||
}
|
||||
if (plugin.requirements.has('dataFromPlugins')) {
|
||||
plugin.getDataFromPlugins = this.getPluginData.bind(this);
|
||||
}
|
||||
plugin._register(Object.getPrototypeOf(plugin));
|
||||
this._plugins.push(plugin);
|
||||
debug('plugin registered', plugin.name);
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* To stay backwards compatible with puppeteer's (and our) default export after adding `addExtra`
|
||||
* we need to defer the check if we have a puppeteer instance to work with.
|
||||
* Otherwise we would throw even if the user intends to use their non-standard puppeteer implementation.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
get pptr() {
|
||||
if (this._pptr) {
|
||||
return this._pptr;
|
||||
}
|
||||
// Whoopsie
|
||||
console.warn(`
|
||||
Puppeteer is missing. :-)
|
||||
|
||||
Note: puppeteer is a peer dependency of puppeteer-extra,
|
||||
which means you can install your own preferred version.
|
||||
|
||||
- To get the latest stable version run: 'yarn add puppeteer' or 'npm i puppeteer'
|
||||
|
||||
Alternatively:
|
||||
- To get puppeteer without the bundled Chromium browser install 'puppeteer-core'
|
||||
`);
|
||||
throw this._requireError || new Error('No puppeteer instance provided.');
|
||||
}
|
||||
/**
|
||||
* The method launches a browser instance with given arguments. The browser will be closed when the parent node.js process is closed.
|
||||
*
|
||||
* Augments the original `puppeteer.launch` method with plugin lifecycle methods.
|
||||
*
|
||||
* All registered plugins that have a `beforeLaunch` method will be called
|
||||
* in sequence to potentially update the `options` Object before launching the browser.
|
||||
*
|
||||
* @example
|
||||
* const browser = await puppeteer.launch({
|
||||
* headless: false,
|
||||
* defaultViewport: null
|
||||
* })
|
||||
*
|
||||
* @param options - See [puppeteer docs](https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#puppeteerlaunchoptions).
|
||||
*/
|
||||
async launch(options) {
|
||||
// Ensure there are certain properties (e.g. the `options.args` array)
|
||||
const defaultLaunchOptions = { args: [] };
|
||||
options = merge(defaultLaunchOptions, options || {});
|
||||
this.resolvePluginDependencies();
|
||||
this.orderPlugins();
|
||||
// Give plugins the chance to modify the options before launch
|
||||
options = await this.callPluginsWithValue('beforeLaunch', options);
|
||||
const opts = {
|
||||
context: 'launch',
|
||||
options,
|
||||
defaultArgs: this.defaultArgs
|
||||
};
|
||||
// Let's check requirements after plugin had the chance to modify the options
|
||||
this.checkPluginRequirements(opts);
|
||||
const browser = await this.pptr.launch(options);
|
||||
this._patchPageCreationMethods(browser);
|
||||
await this.callPlugins('_bindBrowserEvents', browser, opts);
|
||||
return browser;
|
||||
}
|
||||
/**
|
||||
* Attach Puppeteer to an existing Chromium instance.
|
||||
*
|
||||
* Augments the original `puppeteer.connect` method with plugin lifecycle methods.
|
||||
*
|
||||
* All registered plugins that have a `beforeConnect` method will be called
|
||||
* in sequence to potentially update the `options` Object before launching the browser.
|
||||
*
|
||||
* @param options - See [puppeteer docs](https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#puppeteerconnectoptions).
|
||||
*/
|
||||
async connect(options) {
|
||||
this.resolvePluginDependencies();
|
||||
this.orderPlugins();
|
||||
// Give plugins the chance to modify the options before connect
|
||||
options = await this.callPluginsWithValue('beforeConnect', options);
|
||||
const opts = { context: 'connect', options };
|
||||
// Let's check requirements after plugin had the chance to modify the options
|
||||
this.checkPluginRequirements(opts);
|
||||
const browser = await this.pptr.connect(options);
|
||||
this._patchPageCreationMethods(browser);
|
||||
await this.callPlugins('_bindBrowserEvents', browser, opts);
|
||||
return browser;
|
||||
}
|
||||
/**
|
||||
* The default flags that Chromium will be launched with.
|
||||
*
|
||||
* @param options - See [puppeteer docs](https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#puppeteerdefaultargsoptions).
|
||||
*/
|
||||
defaultArgs(options) {
|
||||
return this.pptr.defaultArgs(options);
|
||||
}
|
||||
/** Path where Puppeteer expects to find bundled Chromium. */
|
||||
executablePath() {
|
||||
return this.pptr.executablePath();
|
||||
}
|
||||
/**
|
||||
* This methods attaches Puppeteer to an existing Chromium instance.
|
||||
*
|
||||
* @param options - See [puppeteer docs](https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#puppeteercreatebrowserfetcheroptions).
|
||||
*/
|
||||
createBrowserFetcher(options) {
|
||||
return this.pptr.createBrowserFetcher(options);
|
||||
}
|
||||
/**
|
||||
* Patch page creation methods (both regular and incognito contexts).
|
||||
*
|
||||
* Unfortunately it's possible that the `targetcreated` events are not triggered
|
||||
* early enough for listeners (e.g. plugins using `onPageCreated`) to be able to
|
||||
* modify the page instance (e.g. user-agent) before the browser request occurs.
|
||||
*
|
||||
* This only affects the first request of a newly created page target.
|
||||
*
|
||||
* As a workaround I've noticed that navigating to `about:blank` (again),
|
||||
* right after a page has been created reliably fixes this issue and adds
|
||||
* no noticable delay or side-effects.
|
||||
*
|
||||
* This problem is not specific to `puppeteer-extra` but default Puppeteer behaviour.
|
||||
*
|
||||
* Note: This patch only fixes explicitly created pages, implicitly created ones
|
||||
* (e.g. through `window.open`) are still subject to this issue. I didn't find a
|
||||
* reliable mitigation for implicitly created pages yet.
|
||||
*
|
||||
* Puppeteer issues:
|
||||
* https://github.com/GoogleChrome/puppeteer/issues/2669
|
||||
* https://github.com/puppeteer/puppeteer/issues/3667
|
||||
* https://github.com/GoogleChrome/puppeteer/issues/386#issuecomment-343059315
|
||||
* https://github.com/GoogleChrome/puppeteer/issues/1378#issue-273733905
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_patchPageCreationMethods(browser) {
|
||||
if (!browser._createPageInContext) {
|
||||
debug('warning: _patchPageCreationMethods failed (no browser._createPageInContext)');
|
||||
return;
|
||||
}
|
||||
browser._createPageInContext = (function (originalMethod, context) {
|
||||
return async function () {
|
||||
const page = await originalMethod.apply(context, arguments);
|
||||
await page.goto('about:blank');
|
||||
return page;
|
||||
};
|
||||
})(browser._createPageInContext, browser);
|
||||
}
|
||||
/**
|
||||
* Get a list of all registered plugins.
|
||||
*
|
||||
* @member {Array<PuppeteerExtraPlugin>}
|
||||
*/
|
||||
get plugins() {
|
||||
return this._plugins;
|
||||
}
|
||||
/**
|
||||
* Get the names of all registered plugins.
|
||||
*
|
||||
* @member {Array<string>}
|
||||
* @private
|
||||
*/
|
||||
get pluginNames() {
|
||||
return this._plugins.map(p => p.name);
|
||||
}
|
||||
/**
|
||||
* Collects the exposed `data` property of all registered plugins.
|
||||
* Will be reduced/flattened to a single array.
|
||||
*
|
||||
* Can be accessed by plugins that listed the `dataFromPlugins` requirement.
|
||||
*
|
||||
* Implemented mainly for plugins that need data from other plugins (e.g. `user-preferences`).
|
||||
*
|
||||
* @see [PuppeteerExtraPlugin]/data
|
||||
* @param name - Filter data by optional plugin name
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
getPluginData(name) {
|
||||
const data = this._plugins
|
||||
.map(p => (Array.isArray(p.data) ? p.data : [p.data]))
|
||||
.reduce((acc, arr) => [...acc, ...arr], []);
|
||||
return name ? data.filter((d) => d.name === name) : data;
|
||||
}
|
||||
/**
|
||||
* Get all plugins that feature a given property/class method.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
getPluginsByProp(prop) {
|
||||
return this._plugins.filter(plugin => prop in plugin);
|
||||
}
|
||||
/**
|
||||
* Lightweight plugin dependency management to require plugins and code mods on demand.
|
||||
*
|
||||
* This uses the `dependencies` stanza (a `Set`) exposed by `puppeteer-extra` plugins.
|
||||
*
|
||||
* @todo Allow objects as depdencies that contains opts for the requested plugin.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
resolvePluginDependencies() {
|
||||
// Request missing dependencies from all plugins and flatten to a single Set
|
||||
const missingPlugins = this._plugins
|
||||
.map(p => p._getMissingDependencies(this._plugins))
|
||||
.reduce((combined, list) => {
|
||||
return new Set([...combined, ...list]);
|
||||
}, new Set());
|
||||
if (!missingPlugins.size) {
|
||||
debug('no dependencies are missing');
|
||||
return;
|
||||
}
|
||||
debug('dependencies missing', missingPlugins);
|
||||
// Loop through all dependencies declared missing by plugins
|
||||
for (let name of [...missingPlugins]) {
|
||||
// Check if the dependency hasn't been registered as plugin already.
|
||||
// This might happen when multiple plugins have nested dependencies.
|
||||
if (this.pluginNames.includes(name)) {
|
||||
debug(`ignoring dependency '${name}', which has been required already.`);
|
||||
continue;
|
||||
}
|
||||
// We follow a plugin naming convention, but let's rather enforce it <3
|
||||
name = name.startsWith('puppeteer-extra-plugin')
|
||||
? name
|
||||
: `puppeteer-extra-plugin-${name}`;
|
||||
// In case a module sub resource is requested print out the main package name
|
||||
// e.g. puppeteer-extra-plugin-stealth/evasions/console.debug => puppeteer-extra-plugin-stealth
|
||||
const packageName = name.split('/')[0];
|
||||
let dep = null;
|
||||
try {
|
||||
// Try to require and instantiate the stated dependency
|
||||
dep = require(name)();
|
||||
// Register it with `puppeteer-extra` as plugin
|
||||
this.use(dep);
|
||||
}
|
||||
catch (err) {
|
||||
console.warn(`
|
||||
A plugin listed '${name}' as dependency,
|
||||
which is currently missing. Please install it:
|
||||
|
||||
yarn add ${packageName}
|
||||
|
||||
Note: You don't need to require the plugin yourself,
|
||||
unless you want to modify it's default settings.
|
||||
`);
|
||||
throw err;
|
||||
}
|
||||
// Handle nested dependencies :D
|
||||
if (dep.dependencies.size) {
|
||||
this.resolvePluginDependencies();
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Order plugins that have expressed a special placement requirement.
|
||||
*
|
||||
* This is useful/necessary for e.g. plugins that depend on the data from other plugins.
|
||||
*
|
||||
* @todo Support more than 'runLast'.
|
||||
* @todo If there are multiple plugins defining 'runLast', sort them depending on who depends on whom. :D
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
orderPlugins() {
|
||||
debug('orderPlugins:before', this.pluginNames);
|
||||
const runLast = this._plugins
|
||||
.filter(p => p.requirements.has('runLast'))
|
||||
.map(p => p.name);
|
||||
for (const name of runLast) {
|
||||
const index = this._plugins.findIndex(p => p.name === name);
|
||||
this._plugins.push(this._plugins.splice(index, 1)[0]);
|
||||
}
|
||||
debug('orderPlugins:after', this.pluginNames);
|
||||
}
|
||||
/**
|
||||
* Lightweight plugin requirement checking.
|
||||
*
|
||||
* The main intent is to notify the user when a plugin won't work as expected.
|
||||
*
|
||||
* @todo This could be improved, e.g. be evaluated by the plugin base class.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
checkPluginRequirements(opts = {}) {
|
||||
for (const plugin of this._plugins) {
|
||||
for (const requirement of plugin.requirements) {
|
||||
if (opts.context === 'launch' &&
|
||||
requirement === 'headful' &&
|
||||
opts.options.headless) {
|
||||
console.warn(`Warning: Plugin '${plugin.name}' is not supported in headless mode.`);
|
||||
}
|
||||
if (opts.context === 'connect' && requirement === 'launch') {
|
||||
console.warn(`Warning: Plugin '${plugin.name}' doesn't support puppeteer.connect().`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Call plugins sequentially with the same values.
|
||||
* Plugins that expose the supplied property will be called.
|
||||
*
|
||||
* @param prop - The plugin property to call
|
||||
* @param values - Any number of values
|
||||
* @private
|
||||
*/
|
||||
async callPlugins(prop, ...values) {
|
||||
for (const plugin of this.getPluginsByProp(prop)) {
|
||||
await plugin[prop].apply(plugin, values);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Call plugins sequentially and pass on a value (waterfall style).
|
||||
* Plugins that expose the supplied property will be called.
|
||||
*
|
||||
* The plugins can either modify the value or return an updated one.
|
||||
* Will return the latest, updated value which ran through all plugins.
|
||||
*
|
||||
* @param prop - The plugin property to call
|
||||
* @param value - Any value
|
||||
* @return The new updated value
|
||||
* @private
|
||||
*/
|
||||
async callPluginsWithValue(prop, value) {
|
||||
for (const plugin of this.getPluginsByProp(prop)) {
|
||||
const newValue = await plugin[prop](value);
|
||||
if (newValue) {
|
||||
value = newValue;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* The **default export** will behave exactly the same as the regular puppeteer
|
||||
* (just with extra plugin functionality) and can be used as a drop-in replacement.
|
||||
*
|
||||
* Behind the scenes it will try to require either `puppeteer`
|
||||
* or [`puppeteer-core`](https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#puppeteer-vs-puppeteer-core)
|
||||
* from the installed dependencies.
|
||||
*
|
||||
* @example
|
||||
* // javascript import
|
||||
* const puppeteer = require('puppeteer-extra')
|
||||
*
|
||||
* // typescript/es6 module import
|
||||
* import puppeteer from 'puppeteer-extra'
|
||||
*
|
||||
* // Add plugins
|
||||
* puppeteer.use(...)
|
||||
*/
|
||||
const defaultExport = (() => {
|
||||
return new PuppeteerExtra(...requireVanillaPuppeteer());
|
||||
})();
|
||||
/**
|
||||
* An **alternative way** to use `puppeteer-extra`: Augments the provided puppeteer with extra plugin functionality.
|
||||
*
|
||||
* This is useful in case you need multiple puppeteer instances with different plugins or to add plugins to a non-standard puppeteer package.
|
||||
*
|
||||
* @example
|
||||
* // js import
|
||||
* const { addExtra } = require('puppeteer-extra')
|
||||
*
|
||||
* // ts/es6 import
|
||||
* import { addExtra } from 'puppeteer-extra'
|
||||
*
|
||||
* // Patch e.g. puppeteer-firefox and add plugins
|
||||
* const puppeteer = addExtra(require('puppeteer-firefox'))
|
||||
* puppeteer.use(...)
|
||||
*
|
||||
* @param puppeteer Any puppeteer API-compatible puppeteer implementation or version.
|
||||
* @return A fresh PuppeteerExtra instance using the provided puppeteer
|
||||
*/
|
||||
const addExtra = (puppeteer) => new PuppeteerExtra(puppeteer);
|
||||
/**
|
||||
* Attempt to require puppeteer or puppeteer-core from dependencies.
|
||||
* To stay backwards compatible with the existing default export we have to do some gymnastics here.
|
||||
*
|
||||
* @return Either a Puppeteer instance or an Error, which we'll throw later if need be.
|
||||
* @private
|
||||
*/
|
||||
function requireVanillaPuppeteer() {
|
||||
try {
|
||||
return [require('puppeteer'), undefined];
|
||||
}
|
||||
catch (_) {
|
||||
// noop
|
||||
}
|
||||
try {
|
||||
return [require('puppeteer-core'), undefined];
|
||||
}
|
||||
catch (err) {
|
||||
return [undefined, err];
|
||||
}
|
||||
}
|
||||
|
||||
exports.PuppeteerExtra = PuppeteerExtra;
|
||||
exports.addExtra = addExtra;
|
||||
exports.default = defaultExport;
|
||||
|
||||
|
||||
module.exports = exports.default || {}
|
||||
Object.entries(exports).forEach(([key, value]) => { module.exports[key] = value })
|
||||
//# sourceMappingURL=index.cjs.js.map
|
||||
1
node_modules/puppeteer-extra/dist/index.cjs.js.map
generated
vendored
Normal file
1
node_modules/puppeteer-extra/dist/index.cjs.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
260
node_modules/puppeteer-extra/dist/index.d.ts
generated
vendored
Normal file
260
node_modules/puppeteer-extra/dist/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,260 @@
|
||||
/// <reference path="../dist/puppeteer-legacy.d.ts" />
|
||||
import { PuppeteerNode } from 'puppeteer';
|
||||
/**
|
||||
* Original Puppeteer API
|
||||
* @private
|
||||
*/
|
||||
export interface VanillaPuppeteer extends Pick<PuppeteerNode, 'connect' | 'defaultArgs' | 'executablePath' | 'launch' | 'createBrowserFetcher'> {
|
||||
}
|
||||
/**
|
||||
* Minimal plugin interface
|
||||
* @private
|
||||
*/
|
||||
export interface PuppeteerExtraPlugin {
|
||||
_isPuppeteerExtraPlugin: boolean;
|
||||
[propName: string]: any;
|
||||
}
|
||||
/**
|
||||
* Modular plugin framework to teach `puppeteer` new tricks.
|
||||
*
|
||||
* This module acts as a drop-in replacement for `puppeteer`.
|
||||
*
|
||||
* Allows PuppeteerExtraPlugin's to register themselves and
|
||||
* to extend puppeteer with additional functionality.
|
||||
*
|
||||
* @class PuppeteerExtra
|
||||
* @implements {VanillaPuppeteer}
|
||||
*
|
||||
* @example
|
||||
* const puppeteer = require('puppeteer-extra')
|
||||
* puppeteer.use(require('puppeteer-extra-plugin-anonymize-ua')())
|
||||
* puppeteer.use(require('puppeteer-extra-plugin-font-size')({defaultFontSize: 18}))
|
||||
*
|
||||
* ;(async () => {
|
||||
* const browser = await puppeteer.launch({headless: false})
|
||||
* const page = await browser.newPage()
|
||||
* await page.goto('http://example.com', {waitUntil: 'domcontentloaded'})
|
||||
* await browser.close()
|
||||
* })()
|
||||
*/
|
||||
export declare class PuppeteerExtra implements VanillaPuppeteer {
|
||||
private _pptr?;
|
||||
private _requireError?;
|
||||
private _plugins;
|
||||
constructor(_pptr?: VanillaPuppeteer | undefined, _requireError?: Error | undefined);
|
||||
/**
|
||||
* The **main interface** to register `puppeteer-extra` plugins.
|
||||
*
|
||||
* @example
|
||||
* puppeteer.use(plugin1).use(plugin2)
|
||||
*
|
||||
* @see [PuppeteerExtraPlugin]
|
||||
*
|
||||
* @return The same `PuppeteerExtra` instance (for optional chaining)
|
||||
*/
|
||||
use(plugin: PuppeteerExtraPlugin): this;
|
||||
/**
|
||||
* To stay backwards compatible with puppeteer's (and our) default export after adding `addExtra`
|
||||
* we need to defer the check if we have a puppeteer instance to work with.
|
||||
* Otherwise we would throw even if the user intends to use their non-standard puppeteer implementation.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
get pptr(): VanillaPuppeteer;
|
||||
/**
|
||||
* The method launches a browser instance with given arguments. The browser will be closed when the parent node.js process is closed.
|
||||
*
|
||||
* Augments the original `puppeteer.launch` method with plugin lifecycle methods.
|
||||
*
|
||||
* All registered plugins that have a `beforeLaunch` method will be called
|
||||
* in sequence to potentially update the `options` Object before launching the browser.
|
||||
*
|
||||
* @example
|
||||
* const browser = await puppeteer.launch({
|
||||
* headless: false,
|
||||
* defaultViewport: null
|
||||
* })
|
||||
*
|
||||
* @param options - See [puppeteer docs](https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#puppeteerlaunchoptions).
|
||||
*/
|
||||
launch(options?: Parameters<VanillaPuppeteer['launch']>[0]): ReturnType<VanillaPuppeteer['launch']>;
|
||||
/**
|
||||
* Attach Puppeteer to an existing Chromium instance.
|
||||
*
|
||||
* Augments the original `puppeteer.connect` method with plugin lifecycle methods.
|
||||
*
|
||||
* All registered plugins that have a `beforeConnect` method will be called
|
||||
* in sequence to potentially update the `options` Object before launching the browser.
|
||||
*
|
||||
* @param options - See [puppeteer docs](https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#puppeteerconnectoptions).
|
||||
*/
|
||||
connect(options: Parameters<VanillaPuppeteer['connect']>[0]): ReturnType<VanillaPuppeteer['connect']>;
|
||||
/**
|
||||
* The default flags that Chromium will be launched with.
|
||||
*
|
||||
* @param options - See [puppeteer docs](https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#puppeteerdefaultargsoptions).
|
||||
*/
|
||||
defaultArgs(options?: Parameters<VanillaPuppeteer['defaultArgs']>[0]): ReturnType<VanillaPuppeteer['defaultArgs']>;
|
||||
/** Path where Puppeteer expects to find bundled Chromium. */
|
||||
executablePath(): string;
|
||||
/**
|
||||
* This methods attaches Puppeteer to an existing Chromium instance.
|
||||
*
|
||||
* @param options - See [puppeteer docs](https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#puppeteercreatebrowserfetcheroptions).
|
||||
*/
|
||||
createBrowserFetcher(options: Parameters<VanillaPuppeteer['createBrowserFetcher']>[0]): ReturnType<VanillaPuppeteer['createBrowserFetcher']>;
|
||||
/**
|
||||
* Patch page creation methods (both regular and incognito contexts).
|
||||
*
|
||||
* Unfortunately it's possible that the `targetcreated` events are not triggered
|
||||
* early enough for listeners (e.g. plugins using `onPageCreated`) to be able to
|
||||
* modify the page instance (e.g. user-agent) before the browser request occurs.
|
||||
*
|
||||
* This only affects the first request of a newly created page target.
|
||||
*
|
||||
* As a workaround I've noticed that navigating to `about:blank` (again),
|
||||
* right after a page has been created reliably fixes this issue and adds
|
||||
* no noticable delay or side-effects.
|
||||
*
|
||||
* This problem is not specific to `puppeteer-extra` but default Puppeteer behaviour.
|
||||
*
|
||||
* Note: This patch only fixes explicitly created pages, implicitly created ones
|
||||
* (e.g. through `window.open`) are still subject to this issue. I didn't find a
|
||||
* reliable mitigation for implicitly created pages yet.
|
||||
*
|
||||
* Puppeteer issues:
|
||||
* https://github.com/GoogleChrome/puppeteer/issues/2669
|
||||
* https://github.com/puppeteer/puppeteer/issues/3667
|
||||
* https://github.com/GoogleChrome/puppeteer/issues/386#issuecomment-343059315
|
||||
* https://github.com/GoogleChrome/puppeteer/issues/1378#issue-273733905
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
private _patchPageCreationMethods;
|
||||
/**
|
||||
* Get a list of all registered plugins.
|
||||
*
|
||||
* @member {Array<PuppeteerExtraPlugin>}
|
||||
*/
|
||||
get plugins(): PuppeteerExtraPlugin[];
|
||||
/**
|
||||
* Get the names of all registered plugins.
|
||||
*
|
||||
* @member {Array<string>}
|
||||
* @private
|
||||
*/
|
||||
get pluginNames(): any[];
|
||||
/**
|
||||
* Collects the exposed `data` property of all registered plugins.
|
||||
* Will be reduced/flattened to a single array.
|
||||
*
|
||||
* Can be accessed by plugins that listed the `dataFromPlugins` requirement.
|
||||
*
|
||||
* Implemented mainly for plugins that need data from other plugins (e.g. `user-preferences`).
|
||||
*
|
||||
* @see [PuppeteerExtraPlugin]/data
|
||||
* @param name - Filter data by optional plugin name
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
getPluginData(name?: string): any[];
|
||||
/**
|
||||
* Get all plugins that feature a given property/class method.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
private getPluginsByProp;
|
||||
/**
|
||||
* Lightweight plugin dependency management to require plugins and code mods on demand.
|
||||
*
|
||||
* This uses the `dependencies` stanza (a `Set`) exposed by `puppeteer-extra` plugins.
|
||||
*
|
||||
* @todo Allow objects as depdencies that contains opts for the requested plugin.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
private resolvePluginDependencies;
|
||||
/**
|
||||
* Order plugins that have expressed a special placement requirement.
|
||||
*
|
||||
* This is useful/necessary for e.g. plugins that depend on the data from other plugins.
|
||||
*
|
||||
* @todo Support more than 'runLast'.
|
||||
* @todo If there are multiple plugins defining 'runLast', sort them depending on who depends on whom. :D
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
private orderPlugins;
|
||||
/**
|
||||
* Lightweight plugin requirement checking.
|
||||
*
|
||||
* The main intent is to notify the user when a plugin won't work as expected.
|
||||
*
|
||||
* @todo This could be improved, e.g. be evaluated by the plugin base class.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
private checkPluginRequirements;
|
||||
/**
|
||||
* Call plugins sequentially with the same values.
|
||||
* Plugins that expose the supplied property will be called.
|
||||
*
|
||||
* @param prop - The plugin property to call
|
||||
* @param values - Any number of values
|
||||
* @private
|
||||
*/
|
||||
private callPlugins;
|
||||
/**
|
||||
* Call plugins sequentially and pass on a value (waterfall style).
|
||||
* Plugins that expose the supplied property will be called.
|
||||
*
|
||||
* The plugins can either modify the value or return an updated one.
|
||||
* Will return the latest, updated value which ran through all plugins.
|
||||
*
|
||||
* @param prop - The plugin property to call
|
||||
* @param value - Any value
|
||||
* @return The new updated value
|
||||
* @private
|
||||
*/
|
||||
private callPluginsWithValue;
|
||||
}
|
||||
/**
|
||||
* The **default export** will behave exactly the same as the regular puppeteer
|
||||
* (just with extra plugin functionality) and can be used as a drop-in replacement.
|
||||
*
|
||||
* Behind the scenes it will try to require either `puppeteer`
|
||||
* or [`puppeteer-core`](https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#puppeteer-vs-puppeteer-core)
|
||||
* from the installed dependencies.
|
||||
*
|
||||
* @example
|
||||
* // javascript import
|
||||
* const puppeteer = require('puppeteer-extra')
|
||||
*
|
||||
* // typescript/es6 module import
|
||||
* import puppeteer from 'puppeteer-extra'
|
||||
*
|
||||
* // Add plugins
|
||||
* puppeteer.use(...)
|
||||
*/
|
||||
declare const defaultExport: PuppeteerExtra;
|
||||
export default defaultExport;
|
||||
/**
|
||||
* An **alternative way** to use `puppeteer-extra`: Augments the provided puppeteer with extra plugin functionality.
|
||||
*
|
||||
* This is useful in case you need multiple puppeteer instances with different plugins or to add plugins to a non-standard puppeteer package.
|
||||
*
|
||||
* @example
|
||||
* // js import
|
||||
* const { addExtra } = require('puppeteer-extra')
|
||||
*
|
||||
* // ts/es6 import
|
||||
* import { addExtra } from 'puppeteer-extra'
|
||||
*
|
||||
* // Patch e.g. puppeteer-firefox and add plugins
|
||||
* const puppeteer = addExtra(require('puppeteer-firefox'))
|
||||
* puppeteer.use(...)
|
||||
*
|
||||
* @param puppeteer Any puppeteer API-compatible puppeteer implementation or version.
|
||||
* @return A fresh PuppeteerExtra instance using the provided puppeteer
|
||||
*/
|
||||
export declare const addExtra: (puppeteer: VanillaPuppeteer) => PuppeteerExtra;
|
||||
459
node_modules/puppeteer-extra/dist/index.esm.js
generated
vendored
Normal file
459
node_modules/puppeteer-extra/dist/index.esm.js
generated
vendored
Normal file
@@ -0,0 +1,459 @@
|
||||
/*!
|
||||
* puppeteer-extra v3.3.5 by berstend
|
||||
* https://github.com/berstend/puppeteer-extra
|
||||
* @license MIT
|
||||
*/
|
||||
import Debug from 'debug';
|
||||
import merge from 'deepmerge';
|
||||
|
||||
const debug = Debug('puppeteer-extra');
|
||||
/**
|
||||
* Modular plugin framework to teach `puppeteer` new tricks.
|
||||
*
|
||||
* This module acts as a drop-in replacement for `puppeteer`.
|
||||
*
|
||||
* Allows PuppeteerExtraPlugin's to register themselves and
|
||||
* to extend puppeteer with additional functionality.
|
||||
*
|
||||
* @class PuppeteerExtra
|
||||
* @implements {VanillaPuppeteer}
|
||||
*
|
||||
* @example
|
||||
* const puppeteer = require('puppeteer-extra')
|
||||
* puppeteer.use(require('puppeteer-extra-plugin-anonymize-ua')())
|
||||
* puppeteer.use(require('puppeteer-extra-plugin-font-size')({defaultFontSize: 18}))
|
||||
*
|
||||
* ;(async () => {
|
||||
* const browser = await puppeteer.launch({headless: false})
|
||||
* const page = await browser.newPage()
|
||||
* await page.goto('http://example.com', {waitUntil: 'domcontentloaded'})
|
||||
* await browser.close()
|
||||
* })()
|
||||
*/
|
||||
class PuppeteerExtra {
|
||||
constructor(_pptr, _requireError) {
|
||||
this._pptr = _pptr;
|
||||
this._requireError = _requireError;
|
||||
this._plugins = [];
|
||||
}
|
||||
/**
|
||||
* The **main interface** to register `puppeteer-extra` plugins.
|
||||
*
|
||||
* @example
|
||||
* puppeteer.use(plugin1).use(plugin2)
|
||||
*
|
||||
* @see [PuppeteerExtraPlugin]
|
||||
*
|
||||
* @return The same `PuppeteerExtra` instance (for optional chaining)
|
||||
*/
|
||||
use(plugin) {
|
||||
if (typeof plugin !== 'object' || !plugin._isPuppeteerExtraPlugin) {
|
||||
console.error(`Warning: Plugin is not derived from PuppeteerExtraPlugin, ignoring.`, plugin);
|
||||
return this;
|
||||
}
|
||||
if (!plugin.name) {
|
||||
console.error(`Warning: Plugin with no name registering, ignoring.`, plugin);
|
||||
return this;
|
||||
}
|
||||
if (plugin.requirements.has('dataFromPlugins')) {
|
||||
plugin.getDataFromPlugins = this.getPluginData.bind(this);
|
||||
}
|
||||
plugin._register(Object.getPrototypeOf(plugin));
|
||||
this._plugins.push(plugin);
|
||||
debug('plugin registered', plugin.name);
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* To stay backwards compatible with puppeteer's (and our) default export after adding `addExtra`
|
||||
* we need to defer the check if we have a puppeteer instance to work with.
|
||||
* Otherwise we would throw even if the user intends to use their non-standard puppeteer implementation.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
get pptr() {
|
||||
if (this._pptr) {
|
||||
return this._pptr;
|
||||
}
|
||||
// Whoopsie
|
||||
console.warn(`
|
||||
Puppeteer is missing. :-)
|
||||
|
||||
Note: puppeteer is a peer dependency of puppeteer-extra,
|
||||
which means you can install your own preferred version.
|
||||
|
||||
- To get the latest stable version run: 'yarn add puppeteer' or 'npm i puppeteer'
|
||||
|
||||
Alternatively:
|
||||
- To get puppeteer without the bundled Chromium browser install 'puppeteer-core'
|
||||
`);
|
||||
throw this._requireError || new Error('No puppeteer instance provided.');
|
||||
}
|
||||
/**
|
||||
* The method launches a browser instance with given arguments. The browser will be closed when the parent node.js process is closed.
|
||||
*
|
||||
* Augments the original `puppeteer.launch` method with plugin lifecycle methods.
|
||||
*
|
||||
* All registered plugins that have a `beforeLaunch` method will be called
|
||||
* in sequence to potentially update the `options` Object before launching the browser.
|
||||
*
|
||||
* @example
|
||||
* const browser = await puppeteer.launch({
|
||||
* headless: false,
|
||||
* defaultViewport: null
|
||||
* })
|
||||
*
|
||||
* @param options - See [puppeteer docs](https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#puppeteerlaunchoptions).
|
||||
*/
|
||||
async launch(options) {
|
||||
// Ensure there are certain properties (e.g. the `options.args` array)
|
||||
const defaultLaunchOptions = { args: [] };
|
||||
options = merge(defaultLaunchOptions, options || {});
|
||||
this.resolvePluginDependencies();
|
||||
this.orderPlugins();
|
||||
// Give plugins the chance to modify the options before launch
|
||||
options = await this.callPluginsWithValue('beforeLaunch', options);
|
||||
const opts = {
|
||||
context: 'launch',
|
||||
options,
|
||||
defaultArgs: this.defaultArgs
|
||||
};
|
||||
// Let's check requirements after plugin had the chance to modify the options
|
||||
this.checkPluginRequirements(opts);
|
||||
const browser = await this.pptr.launch(options);
|
||||
this._patchPageCreationMethods(browser);
|
||||
await this.callPlugins('_bindBrowserEvents', browser, opts);
|
||||
return browser;
|
||||
}
|
||||
/**
|
||||
* Attach Puppeteer to an existing Chromium instance.
|
||||
*
|
||||
* Augments the original `puppeteer.connect` method with plugin lifecycle methods.
|
||||
*
|
||||
* All registered plugins that have a `beforeConnect` method will be called
|
||||
* in sequence to potentially update the `options` Object before launching the browser.
|
||||
*
|
||||
* @param options - See [puppeteer docs](https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#puppeteerconnectoptions).
|
||||
*/
|
||||
async connect(options) {
|
||||
this.resolvePluginDependencies();
|
||||
this.orderPlugins();
|
||||
// Give plugins the chance to modify the options before connect
|
||||
options = await this.callPluginsWithValue('beforeConnect', options);
|
||||
const opts = { context: 'connect', options };
|
||||
// Let's check requirements after plugin had the chance to modify the options
|
||||
this.checkPluginRequirements(opts);
|
||||
const browser = await this.pptr.connect(options);
|
||||
this._patchPageCreationMethods(browser);
|
||||
await this.callPlugins('_bindBrowserEvents', browser, opts);
|
||||
return browser;
|
||||
}
|
||||
/**
|
||||
* The default flags that Chromium will be launched with.
|
||||
*
|
||||
* @param options - See [puppeteer docs](https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#puppeteerdefaultargsoptions).
|
||||
*/
|
||||
defaultArgs(options) {
|
||||
return this.pptr.defaultArgs(options);
|
||||
}
|
||||
/** Path where Puppeteer expects to find bundled Chromium. */
|
||||
executablePath() {
|
||||
return this.pptr.executablePath();
|
||||
}
|
||||
/**
|
||||
* This methods attaches Puppeteer to an existing Chromium instance.
|
||||
*
|
||||
* @param options - See [puppeteer docs](https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#puppeteercreatebrowserfetcheroptions).
|
||||
*/
|
||||
createBrowserFetcher(options) {
|
||||
return this.pptr.createBrowserFetcher(options);
|
||||
}
|
||||
/**
|
||||
* Patch page creation methods (both regular and incognito contexts).
|
||||
*
|
||||
* Unfortunately it's possible that the `targetcreated` events are not triggered
|
||||
* early enough for listeners (e.g. plugins using `onPageCreated`) to be able to
|
||||
* modify the page instance (e.g. user-agent) before the browser request occurs.
|
||||
*
|
||||
* This only affects the first request of a newly created page target.
|
||||
*
|
||||
* As a workaround I've noticed that navigating to `about:blank` (again),
|
||||
* right after a page has been created reliably fixes this issue and adds
|
||||
* no noticable delay or side-effects.
|
||||
*
|
||||
* This problem is not specific to `puppeteer-extra` but default Puppeteer behaviour.
|
||||
*
|
||||
* Note: This patch only fixes explicitly created pages, implicitly created ones
|
||||
* (e.g. through `window.open`) are still subject to this issue. I didn't find a
|
||||
* reliable mitigation for implicitly created pages yet.
|
||||
*
|
||||
* Puppeteer issues:
|
||||
* https://github.com/GoogleChrome/puppeteer/issues/2669
|
||||
* https://github.com/puppeteer/puppeteer/issues/3667
|
||||
* https://github.com/GoogleChrome/puppeteer/issues/386#issuecomment-343059315
|
||||
* https://github.com/GoogleChrome/puppeteer/issues/1378#issue-273733905
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_patchPageCreationMethods(browser) {
|
||||
if (!browser._createPageInContext) {
|
||||
debug('warning: _patchPageCreationMethods failed (no browser._createPageInContext)');
|
||||
return;
|
||||
}
|
||||
browser._createPageInContext = (function (originalMethod, context) {
|
||||
return async function () {
|
||||
const page = await originalMethod.apply(context, arguments);
|
||||
await page.goto('about:blank');
|
||||
return page;
|
||||
};
|
||||
})(browser._createPageInContext, browser);
|
||||
}
|
||||
/**
|
||||
* Get a list of all registered plugins.
|
||||
*
|
||||
* @member {Array<PuppeteerExtraPlugin>}
|
||||
*/
|
||||
get plugins() {
|
||||
return this._plugins;
|
||||
}
|
||||
/**
|
||||
* Get the names of all registered plugins.
|
||||
*
|
||||
* @member {Array<string>}
|
||||
* @private
|
||||
*/
|
||||
get pluginNames() {
|
||||
return this._plugins.map(p => p.name);
|
||||
}
|
||||
/**
|
||||
* Collects the exposed `data` property of all registered plugins.
|
||||
* Will be reduced/flattened to a single array.
|
||||
*
|
||||
* Can be accessed by plugins that listed the `dataFromPlugins` requirement.
|
||||
*
|
||||
* Implemented mainly for plugins that need data from other plugins (e.g. `user-preferences`).
|
||||
*
|
||||
* @see [PuppeteerExtraPlugin]/data
|
||||
* @param name - Filter data by optional plugin name
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
getPluginData(name) {
|
||||
const data = this._plugins
|
||||
.map(p => (Array.isArray(p.data) ? p.data : [p.data]))
|
||||
.reduce((acc, arr) => [...acc, ...arr], []);
|
||||
return name ? data.filter((d) => d.name === name) : data;
|
||||
}
|
||||
/**
|
||||
* Get all plugins that feature a given property/class method.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
getPluginsByProp(prop) {
|
||||
return this._plugins.filter(plugin => prop in plugin);
|
||||
}
|
||||
/**
|
||||
* Lightweight plugin dependency management to require plugins and code mods on demand.
|
||||
*
|
||||
* This uses the `dependencies` stanza (a `Set`) exposed by `puppeteer-extra` plugins.
|
||||
*
|
||||
* @todo Allow objects as depdencies that contains opts for the requested plugin.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
resolvePluginDependencies() {
|
||||
// Request missing dependencies from all plugins and flatten to a single Set
|
||||
const missingPlugins = this._plugins
|
||||
.map(p => p._getMissingDependencies(this._plugins))
|
||||
.reduce((combined, list) => {
|
||||
return new Set([...combined, ...list]);
|
||||
}, new Set());
|
||||
if (!missingPlugins.size) {
|
||||
debug('no dependencies are missing');
|
||||
return;
|
||||
}
|
||||
debug('dependencies missing', missingPlugins);
|
||||
// Loop through all dependencies declared missing by plugins
|
||||
for (let name of [...missingPlugins]) {
|
||||
// Check if the dependency hasn't been registered as plugin already.
|
||||
// This might happen when multiple plugins have nested dependencies.
|
||||
if (this.pluginNames.includes(name)) {
|
||||
debug(`ignoring dependency '${name}', which has been required already.`);
|
||||
continue;
|
||||
}
|
||||
// We follow a plugin naming convention, but let's rather enforce it <3
|
||||
name = name.startsWith('puppeteer-extra-plugin')
|
||||
? name
|
||||
: `puppeteer-extra-plugin-${name}`;
|
||||
// In case a module sub resource is requested print out the main package name
|
||||
// e.g. puppeteer-extra-plugin-stealth/evasions/console.debug => puppeteer-extra-plugin-stealth
|
||||
const packageName = name.split('/')[0];
|
||||
let dep = null;
|
||||
try {
|
||||
// Try to require and instantiate the stated dependency
|
||||
dep = require(name)();
|
||||
// Register it with `puppeteer-extra` as plugin
|
||||
this.use(dep);
|
||||
}
|
||||
catch (err) {
|
||||
console.warn(`
|
||||
A plugin listed '${name}' as dependency,
|
||||
which is currently missing. Please install it:
|
||||
|
||||
yarn add ${packageName}
|
||||
|
||||
Note: You don't need to require the plugin yourself,
|
||||
unless you want to modify it's default settings.
|
||||
`);
|
||||
throw err;
|
||||
}
|
||||
// Handle nested dependencies :D
|
||||
if (dep.dependencies.size) {
|
||||
this.resolvePluginDependencies();
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Order plugins that have expressed a special placement requirement.
|
||||
*
|
||||
* This is useful/necessary for e.g. plugins that depend on the data from other plugins.
|
||||
*
|
||||
* @todo Support more than 'runLast'.
|
||||
* @todo If there are multiple plugins defining 'runLast', sort them depending on who depends on whom. :D
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
orderPlugins() {
|
||||
debug('orderPlugins:before', this.pluginNames);
|
||||
const runLast = this._plugins
|
||||
.filter(p => p.requirements.has('runLast'))
|
||||
.map(p => p.name);
|
||||
for (const name of runLast) {
|
||||
const index = this._plugins.findIndex(p => p.name === name);
|
||||
this._plugins.push(this._plugins.splice(index, 1)[0]);
|
||||
}
|
||||
debug('orderPlugins:after', this.pluginNames);
|
||||
}
|
||||
/**
|
||||
* Lightweight plugin requirement checking.
|
||||
*
|
||||
* The main intent is to notify the user when a plugin won't work as expected.
|
||||
*
|
||||
* @todo This could be improved, e.g. be evaluated by the plugin base class.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
checkPluginRequirements(opts = {}) {
|
||||
for (const plugin of this._plugins) {
|
||||
for (const requirement of plugin.requirements) {
|
||||
if (opts.context === 'launch' &&
|
||||
requirement === 'headful' &&
|
||||
opts.options.headless) {
|
||||
console.warn(`Warning: Plugin '${plugin.name}' is not supported in headless mode.`);
|
||||
}
|
||||
if (opts.context === 'connect' && requirement === 'launch') {
|
||||
console.warn(`Warning: Plugin '${plugin.name}' doesn't support puppeteer.connect().`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Call plugins sequentially with the same values.
|
||||
* Plugins that expose the supplied property will be called.
|
||||
*
|
||||
* @param prop - The plugin property to call
|
||||
* @param values - Any number of values
|
||||
* @private
|
||||
*/
|
||||
async callPlugins(prop, ...values) {
|
||||
for (const plugin of this.getPluginsByProp(prop)) {
|
||||
await plugin[prop].apply(plugin, values);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Call plugins sequentially and pass on a value (waterfall style).
|
||||
* Plugins that expose the supplied property will be called.
|
||||
*
|
||||
* The plugins can either modify the value or return an updated one.
|
||||
* Will return the latest, updated value which ran through all plugins.
|
||||
*
|
||||
* @param prop - The plugin property to call
|
||||
* @param value - Any value
|
||||
* @return The new updated value
|
||||
* @private
|
||||
*/
|
||||
async callPluginsWithValue(prop, value) {
|
||||
for (const plugin of this.getPluginsByProp(prop)) {
|
||||
const newValue = await plugin[prop](value);
|
||||
if (newValue) {
|
||||
value = newValue;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* The **default export** will behave exactly the same as the regular puppeteer
|
||||
* (just with extra plugin functionality) and can be used as a drop-in replacement.
|
||||
*
|
||||
* Behind the scenes it will try to require either `puppeteer`
|
||||
* or [`puppeteer-core`](https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#puppeteer-vs-puppeteer-core)
|
||||
* from the installed dependencies.
|
||||
*
|
||||
* @example
|
||||
* // javascript import
|
||||
* const puppeteer = require('puppeteer-extra')
|
||||
*
|
||||
* // typescript/es6 module import
|
||||
* import puppeteer from 'puppeteer-extra'
|
||||
*
|
||||
* // Add plugins
|
||||
* puppeteer.use(...)
|
||||
*/
|
||||
const defaultExport = (() => {
|
||||
return new PuppeteerExtra(...requireVanillaPuppeteer());
|
||||
})();
|
||||
/**
|
||||
* An **alternative way** to use `puppeteer-extra`: Augments the provided puppeteer with extra plugin functionality.
|
||||
*
|
||||
* This is useful in case you need multiple puppeteer instances with different plugins or to add plugins to a non-standard puppeteer package.
|
||||
*
|
||||
* @example
|
||||
* // js import
|
||||
* const { addExtra } = require('puppeteer-extra')
|
||||
*
|
||||
* // ts/es6 import
|
||||
* import { addExtra } from 'puppeteer-extra'
|
||||
*
|
||||
* // Patch e.g. puppeteer-firefox and add plugins
|
||||
* const puppeteer = addExtra(require('puppeteer-firefox'))
|
||||
* puppeteer.use(...)
|
||||
*
|
||||
* @param puppeteer Any puppeteer API-compatible puppeteer implementation or version.
|
||||
* @return A fresh PuppeteerExtra instance using the provided puppeteer
|
||||
*/
|
||||
const addExtra = (puppeteer) => new PuppeteerExtra(puppeteer);
|
||||
/**
|
||||
* Attempt to require puppeteer or puppeteer-core from dependencies.
|
||||
* To stay backwards compatible with the existing default export we have to do some gymnastics here.
|
||||
*
|
||||
* @return Either a Puppeteer instance or an Error, which we'll throw later if need be.
|
||||
* @private
|
||||
*/
|
||||
function requireVanillaPuppeteer() {
|
||||
try {
|
||||
return [require('puppeteer'), undefined];
|
||||
}
|
||||
catch (_) {
|
||||
// noop
|
||||
}
|
||||
try {
|
||||
return [require('puppeteer-core'), undefined];
|
||||
}
|
||||
catch (err) {
|
||||
return [undefined, err];
|
||||
}
|
||||
}
|
||||
|
||||
export default defaultExport;
|
||||
export { PuppeteerExtra, addExtra };
|
||||
//# sourceMappingURL=index.esm.js.map
|
||||
1
node_modules/puppeteer-extra/dist/index.esm.js.map
generated
vendored
Normal file
1
node_modules/puppeteer-extra/dist/index.esm.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
459
node_modules/puppeteer-extra/dist/index.js
generated
vendored
Normal file
459
node_modules/puppeteer-extra/dist/index.js
generated
vendored
Normal file
@@ -0,0 +1,459 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.addExtra = exports.PuppeteerExtra = void 0;
|
||||
const debug_1 = __importDefault(require("debug"));
|
||||
const debug = (0, debug_1.default)('puppeteer-extra');
|
||||
const deepmerge_1 = __importDefault(require("deepmerge"));
|
||||
/**
|
||||
* Modular plugin framework to teach `puppeteer` new tricks.
|
||||
*
|
||||
* This module acts as a drop-in replacement for `puppeteer`.
|
||||
*
|
||||
* Allows PuppeteerExtraPlugin's to register themselves and
|
||||
* to extend puppeteer with additional functionality.
|
||||
*
|
||||
* @class PuppeteerExtra
|
||||
* @implements {VanillaPuppeteer}
|
||||
*
|
||||
* @example
|
||||
* const puppeteer = require('puppeteer-extra')
|
||||
* puppeteer.use(require('puppeteer-extra-plugin-anonymize-ua')())
|
||||
* puppeteer.use(require('puppeteer-extra-plugin-font-size')({defaultFontSize: 18}))
|
||||
*
|
||||
* ;(async () => {
|
||||
* const browser = await puppeteer.launch({headless: false})
|
||||
* const page = await browser.newPage()
|
||||
* await page.goto('http://example.com', {waitUntil: 'domcontentloaded'})
|
||||
* await browser.close()
|
||||
* })()
|
||||
*/
|
||||
class PuppeteerExtra {
|
||||
constructor(_pptr, _requireError) {
|
||||
this._pptr = _pptr;
|
||||
this._requireError = _requireError;
|
||||
this._plugins = [];
|
||||
}
|
||||
/**
|
||||
* The **main interface** to register `puppeteer-extra` plugins.
|
||||
*
|
||||
* @example
|
||||
* puppeteer.use(plugin1).use(plugin2)
|
||||
*
|
||||
* @see [PuppeteerExtraPlugin]
|
||||
*
|
||||
* @return The same `PuppeteerExtra` instance (for optional chaining)
|
||||
*/
|
||||
use(plugin) {
|
||||
if (typeof plugin !== 'object' || !plugin._isPuppeteerExtraPlugin) {
|
||||
console.error(`Warning: Plugin is not derived from PuppeteerExtraPlugin, ignoring.`, plugin);
|
||||
return this;
|
||||
}
|
||||
if (!plugin.name) {
|
||||
console.error(`Warning: Plugin with no name registering, ignoring.`, plugin);
|
||||
return this;
|
||||
}
|
||||
if (plugin.requirements.has('dataFromPlugins')) {
|
||||
plugin.getDataFromPlugins = this.getPluginData.bind(this);
|
||||
}
|
||||
plugin._register(Object.getPrototypeOf(plugin));
|
||||
this._plugins.push(plugin);
|
||||
debug('plugin registered', plugin.name);
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* To stay backwards compatible with puppeteer's (and our) default export after adding `addExtra`
|
||||
* we need to defer the check if we have a puppeteer instance to work with.
|
||||
* Otherwise we would throw even if the user intends to use their non-standard puppeteer implementation.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
get pptr() {
|
||||
if (this._pptr) {
|
||||
return this._pptr;
|
||||
}
|
||||
// Whoopsie
|
||||
console.warn(`
|
||||
Puppeteer is missing. :-)
|
||||
|
||||
Note: puppeteer is a peer dependency of puppeteer-extra,
|
||||
which means you can install your own preferred version.
|
||||
|
||||
- To get the latest stable version run: 'yarn add puppeteer' or 'npm i puppeteer'
|
||||
|
||||
Alternatively:
|
||||
- To get puppeteer without the bundled Chromium browser install 'puppeteer-core'
|
||||
`);
|
||||
throw this._requireError || new Error('No puppeteer instance provided.');
|
||||
}
|
||||
/**
|
||||
* The method launches a browser instance with given arguments. The browser will be closed when the parent node.js process is closed.
|
||||
*
|
||||
* Augments the original `puppeteer.launch` method with plugin lifecycle methods.
|
||||
*
|
||||
* All registered plugins that have a `beforeLaunch` method will be called
|
||||
* in sequence to potentially update the `options` Object before launching the browser.
|
||||
*
|
||||
* @example
|
||||
* const browser = await puppeteer.launch({
|
||||
* headless: false,
|
||||
* defaultViewport: null
|
||||
* })
|
||||
*
|
||||
* @param options - See [puppeteer docs](https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#puppeteerlaunchoptions).
|
||||
*/
|
||||
async launch(options) {
|
||||
// Ensure there are certain properties (e.g. the `options.args` array)
|
||||
const defaultLaunchOptions = { args: [] };
|
||||
options = (0, deepmerge_1.default)(defaultLaunchOptions, options || {});
|
||||
this.resolvePluginDependencies();
|
||||
this.orderPlugins();
|
||||
// Give plugins the chance to modify the options before launch
|
||||
options = await this.callPluginsWithValue('beforeLaunch', options);
|
||||
const opts = {
|
||||
context: 'launch',
|
||||
options,
|
||||
defaultArgs: this.defaultArgs
|
||||
};
|
||||
// Let's check requirements after plugin had the chance to modify the options
|
||||
this.checkPluginRequirements(opts);
|
||||
const browser = await this.pptr.launch(options);
|
||||
this._patchPageCreationMethods(browser);
|
||||
await this.callPlugins('_bindBrowserEvents', browser, opts);
|
||||
return browser;
|
||||
}
|
||||
/**
|
||||
* Attach Puppeteer to an existing Chromium instance.
|
||||
*
|
||||
* Augments the original `puppeteer.connect` method with plugin lifecycle methods.
|
||||
*
|
||||
* All registered plugins that have a `beforeConnect` method will be called
|
||||
* in sequence to potentially update the `options` Object before launching the browser.
|
||||
*
|
||||
* @param options - See [puppeteer docs](https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#puppeteerconnectoptions).
|
||||
*/
|
||||
async connect(options) {
|
||||
this.resolvePluginDependencies();
|
||||
this.orderPlugins();
|
||||
// Give plugins the chance to modify the options before connect
|
||||
options = await this.callPluginsWithValue('beforeConnect', options);
|
||||
const opts = { context: 'connect', options };
|
||||
// Let's check requirements after plugin had the chance to modify the options
|
||||
this.checkPluginRequirements(opts);
|
||||
const browser = await this.pptr.connect(options);
|
||||
this._patchPageCreationMethods(browser);
|
||||
await this.callPlugins('_bindBrowserEvents', browser, opts);
|
||||
return browser;
|
||||
}
|
||||
/**
|
||||
* The default flags that Chromium will be launched with.
|
||||
*
|
||||
* @param options - See [puppeteer docs](https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#puppeteerdefaultargsoptions).
|
||||
*/
|
||||
defaultArgs(options) {
|
||||
return this.pptr.defaultArgs(options);
|
||||
}
|
||||
/** Path where Puppeteer expects to find bundled Chromium. */
|
||||
executablePath() {
|
||||
return this.pptr.executablePath();
|
||||
}
|
||||
/**
|
||||
* This methods attaches Puppeteer to an existing Chromium instance.
|
||||
*
|
||||
* @param options - See [puppeteer docs](https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#puppeteercreatebrowserfetcheroptions).
|
||||
*/
|
||||
createBrowserFetcher(options) {
|
||||
return this.pptr.createBrowserFetcher(options);
|
||||
}
|
||||
/**
|
||||
* Patch page creation methods (both regular and incognito contexts).
|
||||
*
|
||||
* Unfortunately it's possible that the `targetcreated` events are not triggered
|
||||
* early enough for listeners (e.g. plugins using `onPageCreated`) to be able to
|
||||
* modify the page instance (e.g. user-agent) before the browser request occurs.
|
||||
*
|
||||
* This only affects the first request of a newly created page target.
|
||||
*
|
||||
* As a workaround I've noticed that navigating to `about:blank` (again),
|
||||
* right after a page has been created reliably fixes this issue and adds
|
||||
* no noticable delay or side-effects.
|
||||
*
|
||||
* This problem is not specific to `puppeteer-extra` but default Puppeteer behaviour.
|
||||
*
|
||||
* Note: This patch only fixes explicitly created pages, implicitly created ones
|
||||
* (e.g. through `window.open`) are still subject to this issue. I didn't find a
|
||||
* reliable mitigation for implicitly created pages yet.
|
||||
*
|
||||
* Puppeteer issues:
|
||||
* https://github.com/GoogleChrome/puppeteer/issues/2669
|
||||
* https://github.com/puppeteer/puppeteer/issues/3667
|
||||
* https://github.com/GoogleChrome/puppeteer/issues/386#issuecomment-343059315
|
||||
* https://github.com/GoogleChrome/puppeteer/issues/1378#issue-273733905
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_patchPageCreationMethods(browser) {
|
||||
if (!browser._createPageInContext) {
|
||||
debug('warning: _patchPageCreationMethods failed (no browser._createPageInContext)');
|
||||
return;
|
||||
}
|
||||
browser._createPageInContext = (function (originalMethod, context) {
|
||||
return async function () {
|
||||
const page = await originalMethod.apply(context, arguments);
|
||||
await page.goto('about:blank');
|
||||
return page;
|
||||
};
|
||||
})(browser._createPageInContext, browser);
|
||||
}
|
||||
/**
|
||||
* Get a list of all registered plugins.
|
||||
*
|
||||
* @member {Array<PuppeteerExtraPlugin>}
|
||||
*/
|
||||
get plugins() {
|
||||
return this._plugins;
|
||||
}
|
||||
/**
|
||||
* Get the names of all registered plugins.
|
||||
*
|
||||
* @member {Array<string>}
|
||||
* @private
|
||||
*/
|
||||
get pluginNames() {
|
||||
return this._plugins.map(p => p.name);
|
||||
}
|
||||
/**
|
||||
* Collects the exposed `data` property of all registered plugins.
|
||||
* Will be reduced/flattened to a single array.
|
||||
*
|
||||
* Can be accessed by plugins that listed the `dataFromPlugins` requirement.
|
||||
*
|
||||
* Implemented mainly for plugins that need data from other plugins (e.g. `user-preferences`).
|
||||
*
|
||||
* @see [PuppeteerExtraPlugin]/data
|
||||
* @param name - Filter data by optional plugin name
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
getPluginData(name) {
|
||||
const data = this._plugins
|
||||
.map(p => (Array.isArray(p.data) ? p.data : [p.data]))
|
||||
.reduce((acc, arr) => [...acc, ...arr], []);
|
||||
return name ? data.filter((d) => d.name === name) : data;
|
||||
}
|
||||
/**
|
||||
* Get all plugins that feature a given property/class method.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
getPluginsByProp(prop) {
|
||||
return this._plugins.filter(plugin => prop in plugin);
|
||||
}
|
||||
/**
|
||||
* Lightweight plugin dependency management to require plugins and code mods on demand.
|
||||
*
|
||||
* This uses the `dependencies` stanza (a `Set`) exposed by `puppeteer-extra` plugins.
|
||||
*
|
||||
* @todo Allow objects as depdencies that contains opts for the requested plugin.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
resolvePluginDependencies() {
|
||||
// Request missing dependencies from all plugins and flatten to a single Set
|
||||
const missingPlugins = this._plugins
|
||||
.map(p => p._getMissingDependencies(this._plugins))
|
||||
.reduce((combined, list) => {
|
||||
return new Set([...combined, ...list]);
|
||||
}, new Set());
|
||||
if (!missingPlugins.size) {
|
||||
debug('no dependencies are missing');
|
||||
return;
|
||||
}
|
||||
debug('dependencies missing', missingPlugins);
|
||||
// Loop through all dependencies declared missing by plugins
|
||||
for (let name of [...missingPlugins]) {
|
||||
// Check if the dependency hasn't been registered as plugin already.
|
||||
// This might happen when multiple plugins have nested dependencies.
|
||||
if (this.pluginNames.includes(name)) {
|
||||
debug(`ignoring dependency '${name}', which has been required already.`);
|
||||
continue;
|
||||
}
|
||||
// We follow a plugin naming convention, but let's rather enforce it <3
|
||||
name = name.startsWith('puppeteer-extra-plugin')
|
||||
? name
|
||||
: `puppeteer-extra-plugin-${name}`;
|
||||
// In case a module sub resource is requested print out the main package name
|
||||
// e.g. puppeteer-extra-plugin-stealth/evasions/console.debug => puppeteer-extra-plugin-stealth
|
||||
const packageName = name.split('/')[0];
|
||||
let dep = null;
|
||||
try {
|
||||
// Try to require and instantiate the stated dependency
|
||||
dep = require(name)();
|
||||
// Register it with `puppeteer-extra` as plugin
|
||||
this.use(dep);
|
||||
}
|
||||
catch (err) {
|
||||
console.warn(`
|
||||
A plugin listed '${name}' as dependency,
|
||||
which is currently missing. Please install it:
|
||||
|
||||
yarn add ${packageName}
|
||||
|
||||
Note: You don't need to require the plugin yourself,
|
||||
unless you want to modify it's default settings.
|
||||
`);
|
||||
throw err;
|
||||
}
|
||||
// Handle nested dependencies :D
|
||||
if (dep.dependencies.size) {
|
||||
this.resolvePluginDependencies();
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Order plugins that have expressed a special placement requirement.
|
||||
*
|
||||
* This is useful/necessary for e.g. plugins that depend on the data from other plugins.
|
||||
*
|
||||
* @todo Support more than 'runLast'.
|
||||
* @todo If there are multiple plugins defining 'runLast', sort them depending on who depends on whom. :D
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
orderPlugins() {
|
||||
debug('orderPlugins:before', this.pluginNames);
|
||||
const runLast = this._plugins
|
||||
.filter(p => p.requirements.has('runLast'))
|
||||
.map(p => p.name);
|
||||
for (const name of runLast) {
|
||||
const index = this._plugins.findIndex(p => p.name === name);
|
||||
this._plugins.push(this._plugins.splice(index, 1)[0]);
|
||||
}
|
||||
debug('orderPlugins:after', this.pluginNames);
|
||||
}
|
||||
/**
|
||||
* Lightweight plugin requirement checking.
|
||||
*
|
||||
* The main intent is to notify the user when a plugin won't work as expected.
|
||||
*
|
||||
* @todo This could be improved, e.g. be evaluated by the plugin base class.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
checkPluginRequirements(opts = {}) {
|
||||
for (const plugin of this._plugins) {
|
||||
for (const requirement of plugin.requirements) {
|
||||
if (opts.context === 'launch' &&
|
||||
requirement === 'headful' &&
|
||||
opts.options.headless) {
|
||||
console.warn(`Warning: Plugin '${plugin.name}' is not supported in headless mode.`);
|
||||
}
|
||||
if (opts.context === 'connect' && requirement === 'launch') {
|
||||
console.warn(`Warning: Plugin '${plugin.name}' doesn't support puppeteer.connect().`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Call plugins sequentially with the same values.
|
||||
* Plugins that expose the supplied property will be called.
|
||||
*
|
||||
* @param prop - The plugin property to call
|
||||
* @param values - Any number of values
|
||||
* @private
|
||||
*/
|
||||
async callPlugins(prop, ...values) {
|
||||
for (const plugin of this.getPluginsByProp(prop)) {
|
||||
await plugin[prop].apply(plugin, values);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Call plugins sequentially and pass on a value (waterfall style).
|
||||
* Plugins that expose the supplied property will be called.
|
||||
*
|
||||
* The plugins can either modify the value or return an updated one.
|
||||
* Will return the latest, updated value which ran through all plugins.
|
||||
*
|
||||
* @param prop - The plugin property to call
|
||||
* @param value - Any value
|
||||
* @return The new updated value
|
||||
* @private
|
||||
*/
|
||||
async callPluginsWithValue(prop, value) {
|
||||
for (const plugin of this.getPluginsByProp(prop)) {
|
||||
const newValue = await plugin[prop](value);
|
||||
if (newValue) {
|
||||
value = newValue;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
exports.PuppeteerExtra = PuppeteerExtra;
|
||||
/**
|
||||
* The **default export** will behave exactly the same as the regular puppeteer
|
||||
* (just with extra plugin functionality) and can be used as a drop-in replacement.
|
||||
*
|
||||
* Behind the scenes it will try to require either `puppeteer`
|
||||
* or [`puppeteer-core`](https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#puppeteer-vs-puppeteer-core)
|
||||
* from the installed dependencies.
|
||||
*
|
||||
* @example
|
||||
* // javascript import
|
||||
* const puppeteer = require('puppeteer-extra')
|
||||
*
|
||||
* // typescript/es6 module import
|
||||
* import puppeteer from 'puppeteer-extra'
|
||||
*
|
||||
* // Add plugins
|
||||
* puppeteer.use(...)
|
||||
*/
|
||||
const defaultExport = (() => {
|
||||
return new PuppeteerExtra(...requireVanillaPuppeteer());
|
||||
})();
|
||||
exports.default = defaultExport;
|
||||
/**
|
||||
* An **alternative way** to use `puppeteer-extra`: Augments the provided puppeteer with extra plugin functionality.
|
||||
*
|
||||
* This is useful in case you need multiple puppeteer instances with different plugins or to add plugins to a non-standard puppeteer package.
|
||||
*
|
||||
* @example
|
||||
* // js import
|
||||
* const { addExtra } = require('puppeteer-extra')
|
||||
*
|
||||
* // ts/es6 import
|
||||
* import { addExtra } from 'puppeteer-extra'
|
||||
*
|
||||
* // Patch e.g. puppeteer-firefox and add plugins
|
||||
* const puppeteer = addExtra(require('puppeteer-firefox'))
|
||||
* puppeteer.use(...)
|
||||
*
|
||||
* @param puppeteer Any puppeteer API-compatible puppeteer implementation or version.
|
||||
* @return A fresh PuppeteerExtra instance using the provided puppeteer
|
||||
*/
|
||||
const addExtra = (puppeteer) => new PuppeteerExtra(puppeteer);
|
||||
exports.addExtra = addExtra;
|
||||
/**
|
||||
* Attempt to require puppeteer or puppeteer-core from dependencies.
|
||||
* To stay backwards compatible with the existing default export we have to do some gymnastics here.
|
||||
*
|
||||
* @return Either a Puppeteer instance or an Error, which we'll throw later if need be.
|
||||
* @private
|
||||
*/
|
||||
function requireVanillaPuppeteer() {
|
||||
try {
|
||||
return [require('puppeteer'), undefined];
|
||||
}
|
||||
catch (_) {
|
||||
// noop
|
||||
}
|
||||
try {
|
||||
return [require('puppeteer-core'), undefined];
|
||||
}
|
||||
catch (err) {
|
||||
return [undefined, err];
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=index.js.map
|
||||
1
node_modules/puppeteer-extra/dist/index.js.map
generated
vendored
Normal file
1
node_modules/puppeteer-extra/dist/index.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
33
node_modules/puppeteer-extra/dist/puppeteer-legacy.d.ts
generated
vendored
Normal file
33
node_modules/puppeteer-extra/dist/puppeteer-legacy.d.ts
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
// @ts-nocheck
|
||||
// NOTE: The above comment is crucial for all this to work
|
||||
// The puppeteer project caused a type breaking shift in v6 while switching from @types/puppeteer to built-in types
|
||||
// This type definition file is only relevant when puppeteer < v6 is being used,
|
||||
// if we don't instruct TS to skip checking this file it would cause errors when pptr >= v6 is used (e.g. ChromeArgOptions is missing)
|
||||
import {} from 'puppeteer'
|
||||
import { Browser, ConnectOptions, ChromeArgOptions, LaunchOptions, FetcherOptions, BrowserFetcher} from "puppeteer"
|
||||
|
||||
// Make puppeteer-extra typings backwards compatible with puppeteer < v6
|
||||
// In pptr >= v6 they switched to built-in types and the `@types/puppeteer` package is not needed anymore.
|
||||
// This is essentially a shim for `PuppeteerNode`, which is found in pptr >= v6 and missing in `@types/puppeteer`.
|
||||
// Requires the `@types/puppeteer` package to be installed when using pptr < v6, `@types/puppeteer` will be ignored by TS when built-in types are available.
|
||||
interface VanillaPuppeteer {
|
||||
/** Attaches Puppeteer to an existing Chromium instance */
|
||||
connect(options?: ConnectOptions): Promise<Browser>
|
||||
/** The default flags that Chromium will be launched with */
|
||||
defaultArgs(options?: ChromeArgOptions): string[]
|
||||
/** Path where Puppeteer expects to find bundled Chromium */
|
||||
executablePath(): string
|
||||
/** The method launches a browser instance with given arguments. The browser will be closed when the parent node.js process is closed. */
|
||||
launch(options?: LaunchOptions): Promise<Browser>
|
||||
/** This methods attaches Puppeteer to an existing Chromium instance. */
|
||||
createBrowserFetcher(
|
||||
options?: FetcherOptions
|
||||
): BrowserFetcher
|
||||
}
|
||||
|
||||
declare module 'puppeteer' {
|
||||
interface PuppeteerNode extends VanillaPuppeteer {}
|
||||
}
|
||||
declare module 'puppeteer-core' {
|
||||
interface PuppeteerNode extends VanillaPuppeteer {}
|
||||
}
|
||||
87
node_modules/puppeteer-extra/package.json
generated
vendored
Normal file
87
node_modules/puppeteer-extra/package.json
generated
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
{
|
||||
"name": "puppeteer-extra",
|
||||
"version": "3.3.6",
|
||||
"description": "Teach puppeteer new tricks through plugins.",
|
||||
"repository": "berstend/puppeteer-extra",
|
||||
"author": "berstend",
|
||||
"license": "MIT",
|
||||
"typings": "dist/index.d.ts",
|
||||
"main": "dist/index.cjs.js",
|
||||
"module": "dist/index.esm.js",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"clean": "rimraf dist/*",
|
||||
"prebuild": "run-s clean",
|
||||
"build": "run-s build:tsc build:rollup ambient-dts",
|
||||
"build:tsc": "tsc --module commonjs",
|
||||
"build:rollup": "rollup -c rollup.config.ts",
|
||||
"docs": "documentation readme --quiet --shallow --github --markdown-theme transitivebs --readme-file readme.md --section API ./src/index.ts",
|
||||
"postdocs": "npx prettier --write readme.md",
|
||||
"test:ts": "ava -v --config ava.config-ts.js",
|
||||
"test:js": "ava -v --serial --concurrency 1 --fail-fast",
|
||||
"test": "run-p test:js test:ts",
|
||||
"test-ci": "run-s test",
|
||||
"ambient-dts": "run-s ambient-dts-copy ambient-dts-fix-path",
|
||||
"ambient-dts-copy": "copyfiles -u 1 \"src/**/*.d.ts\" dist",
|
||||
"ambient-dts-fix-path": "replace-in-files --string='/// <reference path=\"../src/' --replacement='/// <reference path=\"../dist/' 'dist/**/*.d.ts'"
|
||||
},
|
||||
"keywords": [
|
||||
"puppeteer",
|
||||
"puppeteer-extra",
|
||||
"flash",
|
||||
"stealth",
|
||||
"prefs",
|
||||
"user-preferences",
|
||||
"chrome",
|
||||
"headless",
|
||||
"pupeteer"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^18.0.0",
|
||||
"@types/puppeteer": "*",
|
||||
"ava": "^2.4.0",
|
||||
"documentation-markdown-themes": "^12.1.5",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"puppeteer": "^10.2.0",
|
||||
"puppeteer-extra-plugin": "^3.2.3",
|
||||
"puppeteer-extra-plugin-anonymize-ua": "^2.4.6",
|
||||
"rimraf": "^3.0.0",
|
||||
"rollup": "^1.27.5",
|
||||
"rollup-plugin-commonjs": "^10.1.0",
|
||||
"rollup-plugin-node-resolve": "^5.2.0",
|
||||
"rollup-plugin-sourcemaps": "^0.4.2",
|
||||
"rollup-plugin-typescript2": "^0.25.2",
|
||||
"ts-node": "^8.5.4",
|
||||
"tslint": "^5.20.1",
|
||||
"tslint-config-prettier": "^1.18.0",
|
||||
"tslint-config-standard": "^9.0.0",
|
||||
"typescript": "4.4.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/debug": "^4.1.0",
|
||||
"debug": "^4.1.1",
|
||||
"deepmerge": "^4.2.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/puppeteer": "*",
|
||||
"puppeteer": "*",
|
||||
"puppeteer-core": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"puppeteer": {
|
||||
"optional": true
|
||||
},
|
||||
"puppeteer-core": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/puppeteer": {
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
"gitHead": "39248f1f5deeb21b1e7eb6ae07b8ef73f1231ab9"
|
||||
}
|
||||
609
node_modules/puppeteer-extra/readme.md
generated
vendored
Normal file
609
node_modules/puppeteer-extra/readme.md
generated
vendored
Normal file
@@ -0,0 +1,609 @@
|
||||
# puppeteer-extra [](https://github.com/berstend/puppeteer-extra/actions) [](https://extra.community) [](https://www.npmjs.com/package/puppeteer-extra) [](https://www.npmjs.com/package/puppeteer-extra) [](https://www.npmjs.com/package/puppeteer-extra)
|
||||
|
||||
> A light-weight wrapper around [`puppeteer`](https://github.com/GoogleChrome/puppeteer) and [friends](#more-examples) to enable cool [plugins](#plugins) through a clean interface.
|
||||
|
||||
<a href="https://github.com/berstend/puppeteer-extra"><img src="https://i.imgur.com/qtlnoQL.png" width="279px" height="187px" align="right" /></a>
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
yarn add puppeteer puppeteer-extra
|
||||
# - or -
|
||||
npm install puppeteer puppeteer-extra
|
||||
|
||||
# puppeteer-extra works with any puppeteer version:
|
||||
yarn add puppeteer@2.0.0 puppeteer-extra
|
||||
```
|
||||
|
||||
## Quickstart
|
||||
|
||||
```js
|
||||
// puppeteer-extra is a drop-in replacement for puppeteer,
|
||||
// it augments the installed puppeteer with plugin functionality.
|
||||
// Any number of plugins can be added through `puppeteer.use()`
|
||||
const puppeteer = require('puppeteer-extra')
|
||||
|
||||
// Add stealth plugin and use defaults (all tricks to hide puppeteer usage)
|
||||
const StealthPlugin = require('puppeteer-extra-plugin-stealth')
|
||||
puppeteer.use(StealthPlugin())
|
||||
|
||||
// Add adblocker plugin to block all ads and trackers (saves bandwidth)
|
||||
const AdblockerPlugin = require('puppeteer-extra-plugin-adblocker')
|
||||
puppeteer.use(AdblockerPlugin({ blockTrackers: true }))
|
||||
|
||||
// That's it, the rest is puppeteer usage as normal 😊
|
||||
puppeteer.launch({ headless: true }).then(async browser => {
|
||||
const page = await browser.newPage()
|
||||
await page.setViewport({ width: 800, height: 600 })
|
||||
|
||||
console.log(`Testing adblocker plugin..`)
|
||||
await page.goto('https://www.vanityfair.com')
|
||||
await page.waitForTimeout(1000)
|
||||
await page.screenshot({ path: 'adblocker.png', fullPage: true })
|
||||
|
||||
console.log(`Testing the stealth plugin..`)
|
||||
await page.goto('https://bot.sannysoft.com')
|
||||
await page.waitForTimeout(5000)
|
||||
await page.screenshot({ path: 'stealth.png', fullPage: true })
|
||||
|
||||
console.log(`All done, check the screenshots. ✨`)
|
||||
await browser.close()
|
||||
})
|
||||
```
|
||||
|
||||
The above example uses the [`stealth`](/packages/puppeteer-extra-plugin-stealth) and [`adblocker`](/packages/puppeteer-extra-plugin-adblocker) plugin, which need to be installed as well:
|
||||
|
||||
```bash
|
||||
yarn add puppeteer-extra-plugin-stealth puppeteer-extra-plugin-adblocker
|
||||
# - or -
|
||||
npm install puppeteer-extra-plugin-stealth puppeteer-extra-plugin-adblocker
|
||||
```
|
||||
|
||||
If you'd like to see debug output just run your script like so:
|
||||
|
||||
```bash
|
||||
DEBUG=puppeteer-extra,puppeteer-extra-plugin:* node myscript.js
|
||||
```
|
||||
|
||||
### More examples
|
||||
|
||||
<details>
|
||||
<summary><strong>TypeScript usage</strong></summary><br/>
|
||||
|
||||
> `puppeteer-extra` and most plugins are written in TS,
|
||||
> so you get perfect type support out of the box. :)
|
||||
|
||||
```ts
|
||||
import puppeteer from 'puppeteer-extra'
|
||||
|
||||
import AdblockerPlugin from 'puppeteer-extra-plugin-adblocker'
|
||||
import StealthPlugin from 'puppeteer-extra-plugin-stealth'
|
||||
|
||||
puppeteer.use(AdblockerPlugin()).use(StealthPlugin())
|
||||
|
||||
puppeteer
|
||||
.launch({ headless: false, defaultViewport: null })
|
||||
.then(async browser => {
|
||||
const page = await browser.newPage()
|
||||
await page.goto('https://bot.sannysoft.com')
|
||||
await page.waitForTimeout(5000)
|
||||
await page.screenshot({ path: 'stealth.png', fullPage: true })
|
||||
await browser.close()
|
||||
})
|
||||
```
|
||||
|
||||
> Please check this [wiki](https://github.com/berstend/puppeteer-extra/wiki/TypeScript-usage) entry in case you have TypeScript related import issues.
|
||||
|
||||

|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Playwright usage</strong></summary><br/>
|
||||
|
||||
[`playright-extra`](/packages/playwright-extra) with plugin support is available as well.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Multiple puppeteers with different plugins</strong></summary><br/>
|
||||
|
||||
```js
|
||||
const vanillaPuppeteer = require('puppeteer')
|
||||
|
||||
const { addExtra } = require('puppeteer-extra')
|
||||
const AnonymizeUA = require('puppeteer-extra-plugin-anonymize-ua')
|
||||
|
||||
async function main() {
|
||||
const pptr1 = addExtra(vanillaPuppeteer)
|
||||
pptr1.use(
|
||||
AnonymizeUA({
|
||||
customFn: ua => 'Hello1/' + ua.replace('Chrome', 'Beer')
|
||||
})
|
||||
)
|
||||
|
||||
const pptr2 = addExtra(vanillaPuppeteer)
|
||||
pptr2.use(
|
||||
AnonymizeUA({
|
||||
customFn: ua => 'Hello2/' + ua.replace('Chrome', 'Beer')
|
||||
})
|
||||
)
|
||||
|
||||
await checkUserAgent(pptr1)
|
||||
await checkUserAgent(pptr2)
|
||||
}
|
||||
|
||||
main()
|
||||
|
||||
async function checkUserAgent(pptr) {
|
||||
const browser = await pptr.launch({ headless: true })
|
||||
const page = await browser.newPage()
|
||||
await page.goto('https://httpbin.org/headers', {
|
||||
waitUntil: 'domcontentloaded'
|
||||
})
|
||||
const content = await page.content()
|
||||
console.log(content)
|
||||
await browser.close()
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Using with <code>puppeteer-cluster</code></strong></summary><br/>
|
||||
|
||||
> [puppeteer-cluster](https://github.com/thomasdondorf/puppeteer-cluster) allows you to create a cluster of puppeteer workers and plays well together with `puppeteer-extra`.
|
||||
|
||||
```js
|
||||
const { Cluster } = require('puppeteer-cluster')
|
||||
const vanillaPuppeteer = require('puppeteer')
|
||||
|
||||
const { addExtra } = require('puppeteer-extra')
|
||||
const Stealth = require('puppeteer-extra-plugin-stealth')
|
||||
const Recaptcha = require('puppeteer-extra-plugin-recaptcha')
|
||||
|
||||
async function main() {
|
||||
// Create a custom puppeteer-extra instance using `addExtra`,
|
||||
// so we could create additional ones with different plugin config.
|
||||
const puppeteer = addExtra(vanillaPuppeteer)
|
||||
puppeteer.use(Stealth())
|
||||
puppeteer.use(Recaptcha())
|
||||
|
||||
// Launch cluster with puppeteer-extra
|
||||
const cluster = await Cluster.launch({
|
||||
puppeteer,
|
||||
maxConcurrency: 2,
|
||||
concurrency: Cluster.CONCURRENCY_CONTEXT
|
||||
})
|
||||
|
||||
// Define task handler
|
||||
await cluster.task(async ({ page, data: url }) => {
|
||||
await page.goto(url)
|
||||
|
||||
const { hostname } = new URL(url)
|
||||
const { captchas } = await page.findRecaptchas()
|
||||
console.log(`Found ${captchas.length} captcha on ${hostname}`)
|
||||
|
||||
await page.screenshot({ path: `${hostname}.png`, fullPage: true })
|
||||
})
|
||||
|
||||
// Queue any number of tasks
|
||||
cluster.queue('https://bot.sannysoft.com')
|
||||
cluster.queue('https://www.google.com/recaptcha/api2/demo')
|
||||
cluster.queue('http://www.wikipedia.org/')
|
||||
|
||||
await cluster.idle()
|
||||
await cluster.close()
|
||||
console.log(`All done, check the screenshots. ✨`)
|
||||
}
|
||||
|
||||
// Let's go
|
||||
main().catch(console.warn)
|
||||
```
|
||||
|
||||
For using with TypeScript, just change your imports to:
|
||||
|
||||
```ts
|
||||
import { Cluster } from 'puppeteer-cluster'
|
||||
import vanillaPuppeteer from 'puppeteer'
|
||||
|
||||
import { addExtra } from 'puppeteer-extra'
|
||||
import Stealth from 'puppeteer-extra-plugin-stealth'
|
||||
import Recaptcha from 'puppeteer-extra-plugin-recaptcha'
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Using with <code>chrome-aws-lambda</code></strong></summary><br/>
|
||||
|
||||
> If you plan to use [chrome-aws-lambda](https://github.com/alixaxel/chrome-aws-lambda) with the [`stealth`](/packages/puppeteer-extra-plugin-stealth) plugin, you'll need to modify the default args to remove the
|
||||
> `--disable-notifications` flag to pass all the tests.
|
||||
|
||||
```js
|
||||
const chromium = require('chrome-aws-lambda')
|
||||
const { addExtra } = require('puppeteer-extra')
|
||||
const puppeteerExtra = addExtra(chromium.puppeteer)
|
||||
|
||||
const launch = async () => {
|
||||
puppeteerExtra
|
||||
.launch({
|
||||
args: chromium.args,
|
||||
defaultViewport: chromium.defaultViewport,
|
||||
executablePath: await chromium.executablePath,
|
||||
headless: chromium.headless
|
||||
})
|
||||
.then(async browser => {
|
||||
const page = await browser.newPage()
|
||||
await page.goto('https://www.spacejam.com/archive/spacejam/movie/jam.htm')
|
||||
await page.waitForTimeout(10 * 1000)
|
||||
await browser.close()
|
||||
})
|
||||
}
|
||||
|
||||
launch() // Launch Browser
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Using with <code>Kikobeats/browserless</code></strong></summary><br/>
|
||||
|
||||
> [Kikobeats/browserless](https://github.com/Kikobeats/browserless) is a puppeteer-like Node.js library for interacting with Headless production scenarios.
|
||||
|
||||
```js
|
||||
const puppeteer = require('puppeteer-extra')
|
||||
const StealthPlugin = require('puppeteer-extra-plugin-stealth')
|
||||
puppeteer.use(StealthPlugin())
|
||||
|
||||
const browserless = require('browserless')({ puppeteer })
|
||||
|
||||
const saveBufferToFile = (buffer, fileName) => {
|
||||
const wstream = require('fs').createWriteStream(fileName)
|
||||
wstream.write(buffer)
|
||||
wstream.end()
|
||||
}
|
||||
|
||||
browserless
|
||||
.screenshot('https://bot.sannysoft.com', { device: 'iPhone 6' })
|
||||
.then(buffer => {
|
||||
const fileName = 'screenshot.png'
|
||||
saveBufferToFile(buffer, fileName)
|
||||
console.log(`your screenshot is here: `, fileName)
|
||||
})
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
## Plugins
|
||||
|
||||
#### 🔥 [`puppeteer-extra-plugin-stealth`](/packages/puppeteer-extra-plugin-stealth)
|
||||
|
||||
- Applies various evasion techniques to make detection of puppeteer harder.
|
||||
|
||||
#### 🏴 [`puppeteer-extra-plugin-recaptcha`](/packages/puppeteer-extra-plugin-recaptcha)
|
||||
|
||||
- Solves reCAPTCHAs and hCaptchas automatically, using a single line of code: `page.solveRecaptchas()`.
|
||||
|
||||
#### [`puppeteer-extra-plugin-adblocker`](/packages/puppeteer-extra-plugin-adblocker)
|
||||
|
||||
- Very fast & efficient blocker for ads and trackers. Reduces bandwidth & load times.
|
||||
|
||||
#### [`puppeteer-extra-plugin-devtools`](/packages/puppeteer-extra-plugin-devtools)
|
||||
|
||||
- Makes puppeteer browser debugging possible from anywhere.
|
||||
- Creates a secure tunnel to make the devtools frontend (**incl. screencasting**) accessible from the public internet
|
||||
|
||||
#### [`puppeteer-extra-plugin-repl`](/packages/puppeteer-extra-plugin-repl)
|
||||
|
||||
- Makes quick puppeteer debugging and exploration fun with an interactive REPL.
|
||||
|
||||
#### [`puppeteer-extra-plugin-block-resources`](/packages/puppeteer-extra-plugin-block-resources)
|
||||
|
||||
- Blocks resources (images, media, css, etc.) in puppeteer.
|
||||
- Supports all resource types, blocking can be toggled dynamically.
|
||||
|
||||
#### [`puppeteer-extra-plugin-flash`](/packages/puppeteer-extra-plugin-flash)
|
||||
|
||||
- Allows flash content to run on all sites without user interaction.
|
||||
|
||||
#### [`puppeteer-extra-plugin-anonymize-ua`](/packages/puppeteer-extra-plugin-anonymize-ua)
|
||||
|
||||
- Anonymizes the user-agent on all pages.
|
||||
- Supports dynamic replacing, so the browser version stays intact and recent.
|
||||
|
||||
#### [`puppeteer-extra-plugin-user-preferences`](/packages/puppeteer-extra-plugin-user-preferences)
|
||||
|
||||
- Allows setting custom Chrome/Chromium user preferences.
|
||||
- Has itself a plugin interface which is used by e.g. [`puppeteer-extra-plugin-font-size`](/packages/puppeteer-extra-plugin-font-size).
|
||||
|
||||
> Check out the [packages folder](/packages/) for more plugins.
|
||||
|
||||
### Community Plugins
|
||||
|
||||
_These plugins have been generously contributed by members of the community._
|
||||
_Please note that they're hosted outside the main project and not under our control or supervision._
|
||||
|
||||
#### [`puppeteer-extra-plugin-minmax`](https://github.com/Stillerman/puppeteer-extra-minmax)
|
||||
|
||||
- Minimize and maximize puppeteer in real time.
|
||||
- Great for manually solving captchas.
|
||||
|
||||
#### [`puppeteer-extra-plugin-portal`](https://github.com/claabs/puppeteer-extra-plugin-portal)
|
||||
|
||||
- Use the Chromium screencast API to remotely view and interact with puppeteer sessions.
|
||||
- Great for remotely intervening when an automated task gets stuck, like captchas.
|
||||
|
||||
> Please check the `Contributing` section below if you're interested in creating a plugin as well.
|
||||
|
||||
---
|
||||
|
||||
## Contributors
|
||||
|
||||
<a href="https://github.com/berstend/puppeteer-extra/graphs/contributors">
|
||||
<img src="https://contributors-img.firebaseapp.com/image?repo=berstend/puppeteer-extra" />
|
||||
</a>
|
||||
|
||||
## Further info
|
||||
|
||||
<details>
|
||||
<summary><strong>Contributing</strong></summary><br/>
|
||||
|
||||
PRs and new plugins are welcome! 🎉 The plugin API for `puppeteer-extra` is clean and fun to use. Have a look the [PuppeteerExtraPlugin](/packages/puppeteer-extra-plugin) base class documentation to get going and check out the [existing plugins](./packages/) (minimal example is the [anonymize-ua](/packages/puppeteer-extra-plugin-anonymize-ua/index.js) plugin) for reference.
|
||||
|
||||
We use a [monorepo](/) powered by [Lerna](https://github.com/lerna/lerna#--use-workspaces) (and yarn workspaces), [ava](https://github.com/avajs/ava) for testing, TypeScript for the core, the [standard](https://standardjs.com/) style for linting and [JSDoc](http://usejsdoc.org/about-getting-started.html) heavily to auto-generate markdown [documentation](https://github.com/documentationjs/documentation) based on code. :-)
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Kudos</strong></summary><br/>
|
||||
|
||||
- Thanks to [skyiea](https://github.com/skyiea) for [this PR](https://github.com/GoogleChrome/puppeteer/pull/1806) that started the project idea.
|
||||
- Thanks to [transitive-bullshit](https://github.com/transitive-bullshit) for [suggesting](https://github.com/berstend/puppeteer-extra/issues/2) a modular plugin design, which was fun to implement.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Compatibility</strong></summary><br/>
|
||||
|
||||
`puppeteer-extra` and all plugins are [tested continously](https://github.com/berstend/puppeteer-extra/actions) in a matrix of current (stable & LTS) NodeJS and puppeteer versions.
|
||||
We never broke compatibility and still support puppeteer down to very early versions from 2018.
|
||||
|
||||
A few plugins won't work in headless mode (it's noted if that's the case) due to Chrome limitations (e.g. the [`user-preferences`](/packages/puppeteer-extra-plugin-user-preferences) plugin), look into `xvfb-run` if you still require a headless experience in these circumstances.
|
||||
|
||||
</details>
|
||||
|
||||
## Changelog
|
||||
|
||||
<details>
|
||||
<summary><code>2.1.6 ➠ 3.1.1</code></summary>
|
||||
|
||||
### `2.1.6` ➠ `3.1.1`
|
||||
|
||||
Big refactor, the core is now **written in TypeScript** 🎉
|
||||
That means out of the box type safety for fellow TS users and nice auto-completion in VSCode for JS users. Also:
|
||||
|
||||
- A new [`addExtra`](#addextrapuppeteer) export, to **patch any puppeteer compatible library with plugin functionality** (`chrome-aws-lambda`, etc). This also allows for multiple puppeteer instances with different plugins.
|
||||
|
||||
The API is backwards compatible, I bumped the major version just in case I missed something. Please report any issues you might find with the new release. :)
|
||||
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
## API
|
||||
|
||||
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->
|
||||
|
||||
#### Table of Contents
|
||||
|
||||
- [class: PuppeteerExtra](#class-puppeteerextra)
|
||||
- [.use(plugin)](#useplugin)
|
||||
- [.launch(options?)](#launchoptions)
|
||||
- [.connect(options?)](#connectoptions)
|
||||
- [.defaultArgs(options?)](#defaultargsoptions)
|
||||
- [.executablePath()](#executablepath)
|
||||
- [.createBrowserFetcher(options?)](#createbrowserfetcheroptions)
|
||||
- [.plugins](#plugins)
|
||||
- [.getPluginData(name?)](#getplugindataname)
|
||||
- [defaultExport()](#defaultexport)
|
||||
- [addExtra(puppeteer)](#addextrapuppeteer)
|
||||
|
||||
### class: [PuppeteerExtra](https://github.com/berstend/puppeteer-extra/blob/dc8b90260a927c0c66c4585c5a56092ea9c35049/packages/puppeteer-extra/src/index.ts#L67-L474)
|
||||
|
||||
Modular plugin framework to teach `puppeteer` new tricks.
|
||||
|
||||
This module acts as a drop-in replacement for `puppeteer`.
|
||||
|
||||
Allows PuppeteerExtraPlugin's to register themselves and
|
||||
to extend puppeteer with additional functionality.
|
||||
|
||||
Example:
|
||||
|
||||
```javascript
|
||||
const puppeteer = require('puppeteer-extra')
|
||||
puppeteer.use(require('puppeteer-extra-plugin-anonymize-ua')())
|
||||
puppeteer.use(
|
||||
require('puppeteer-extra-plugin-font-size')({ defaultFontSize: 18 })
|
||||
)
|
||||
;(async () => {
|
||||
const browser = await puppeteer.launch({ headless: false })
|
||||
const page = await browser.newPage()
|
||||
await page.goto('http://example.com', { waitUntil: 'domcontentloaded' })
|
||||
await browser.close()
|
||||
})()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### .[use(plugin)](https://github.com/berstend/puppeteer-extra/blob/dc8b90260a927c0c66c4585c5a56092ea9c35049/packages/puppeteer-extra/src/index.ts#L85-L107)
|
||||
|
||||
- `plugin` **PuppeteerExtraPlugin**
|
||||
|
||||
Returns: **this** The same `PuppeteerExtra` instance (for optional chaining)
|
||||
|
||||
The **main interface** to register `puppeteer-extra` plugins.
|
||||
|
||||
Example:
|
||||
|
||||
```javascript
|
||||
puppeteer.use(plugin1).use(plugin2)
|
||||
```
|
||||
|
||||
- **See: [PuppeteerExtraPlugin]**
|
||||
|
||||
---
|
||||
|
||||
#### .[launch(options?)](https://github.com/berstend/puppeteer-extra/blob/dc8b90260a927c0c66c4585c5a56092ea9c35049/packages/puppeteer-extra/src/index.ts#L153-L177)
|
||||
|
||||
- `options` **Puppeteer.LaunchOptions?** See [puppeteer docs](https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#puppeteerlaunchoptions).
|
||||
|
||||
Returns: **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)<Puppeteer.Browser>**
|
||||
|
||||
The method launches a browser instance with given arguments. The browser will be closed when the parent node.js process is closed.
|
||||
|
||||
Augments the original `puppeteer.launch` method with plugin lifecycle methods.
|
||||
|
||||
All registered plugins that have a `beforeLaunch` method will be called
|
||||
in sequence to potentially update the `options` Object before launching the browser.
|
||||
|
||||
Example:
|
||||
|
||||
```javascript
|
||||
const browser = await puppeteer.launch({
|
||||
headless: false,
|
||||
defaultViewport: null
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### .[connect(options?)](https://github.com/berstend/puppeteer-extra/blob/dc8b90260a927c0c66c4585c5a56092ea9c35049/packages/puppeteer-extra/src/index.ts#L189-L208)
|
||||
|
||||
- `options` **Puppeteer.ConnectOptions?** See [puppeteer docs](https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#puppeteerconnectoptions).
|
||||
|
||||
Returns: **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)<Puppeteer.Browser>**
|
||||
|
||||
Attach Puppeteer to an existing Chromium instance.
|
||||
|
||||
Augments the original `puppeteer.connect` method with plugin lifecycle methods.
|
||||
|
||||
All registered plugins that have a `beforeConnect` method will be called
|
||||
in sequence to potentially update the `options` Object before launching the browser.
|
||||
|
||||
---
|
||||
|
||||
#### .[defaultArgs(options?)](https://github.com/berstend/puppeteer-extra/blob/dc8b90260a927c0c66c4585c5a56092ea9c35049/packages/puppeteer-extra/src/index.ts#L215-L217)
|
||||
|
||||
- `options` **Puppeteer.ChromeArgOptions?** See [puppeteer docs](https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#puppeteerdefaultargsoptions).
|
||||
|
||||
Returns: **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)<[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)>**
|
||||
|
||||
The default flags that Chromium will be launched with.
|
||||
|
||||
---
|
||||
|
||||
#### .[executablePath()](https://github.com/berstend/puppeteer-extra/blob/dc8b90260a927c0c66c4585c5a56092ea9c35049/packages/puppeteer-extra/src/index.ts#L220-L222)
|
||||
|
||||
Returns: **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)**
|
||||
|
||||
Path where Puppeteer expects to find bundled Chromium.
|
||||
|
||||
---
|
||||
|
||||
#### .[createBrowserFetcher(options?)](https://github.com/berstend/puppeteer-extra/blob/dc8b90260a927c0c66c4585c5a56092ea9c35049/packages/puppeteer-extra/src/index.ts#L229-L233)
|
||||
|
||||
- `options` **Puppeteer.FetcherOptions?** See [puppeteer docs](https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#puppeteercreatebrowserfetcheroptions).
|
||||
|
||||
Returns: **Puppeteer.BrowserFetcher**
|
||||
|
||||
This methods attaches Puppeteer to an existing Chromium instance.
|
||||
|
||||
---
|
||||
|
||||
#### .[plugins](https://github.com/berstend/puppeteer-extra/blob/dc8b90260a927c0c66c4585c5a56092ea9c35049/packages/puppeteer-extra/src/index.ts#L283-L285)
|
||||
|
||||
Type: **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)<PuppeteerExtraPlugin>**
|
||||
|
||||
Get a list of all registered plugins.
|
||||
|
||||
---
|
||||
|
||||
#### .[getPluginData(name?)](https://github.com/berstend/puppeteer-extra/blob/dc8b90260a927c0c66c4585c5a56092ea9c35049/packages/puppeteer-extra/src/index.ts#L310-L315)
|
||||
|
||||
- `name` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?** Filter data by optional plugin name
|
||||
|
||||
Collects the exposed `data` property of all registered plugins.
|
||||
Will be reduced/flattened to a single array.
|
||||
|
||||
Can be accessed by plugins that listed the `dataFromPlugins` requirement.
|
||||
|
||||
Implemented mainly for plugins that need data from other plugins (e.g. `user-preferences`).
|
||||
|
||||
- **See: [PuppeteerExtraPlugin]/data**
|
||||
|
||||
---
|
||||
|
||||
### [defaultExport()](https://github.com/berstend/puppeteer-extra/blob/dc8b90260a927c0c66c4585c5a56092ea9c35049/packages/puppeteer-extra/src/index.ts#L494-L496)
|
||||
|
||||
Type: **[PuppeteerExtra](#puppeteerextra)**
|
||||
|
||||
The **default export** will behave exactly the same as the regular puppeteer
|
||||
(just with extra plugin functionality) and can be used as a drop-in replacement.
|
||||
|
||||
Behind the scenes it will try to require either `puppeteer`
|
||||
or [`puppeteer-core`](https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#puppeteer-vs-puppeteer-core)
|
||||
from the installed dependencies.
|
||||
|
||||
Example:
|
||||
|
||||
```javascript
|
||||
// javascript import
|
||||
const puppeteer = require('puppeteer-extra')
|
||||
|
||||
// typescript/es6 module import
|
||||
import puppeteer from 'puppeteer-extra'
|
||||
|
||||
// Add plugins
|
||||
puppeteer.use(...)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### [addExtra(puppeteer)](https://github.com/berstend/puppeteer-extra/blob/dc8b90260a927c0c66c4585c5a56092ea9c35049/packages/puppeteer-extra/src/index.ts#L519-L520)
|
||||
|
||||
- `puppeteer` **VanillaPuppeteer** Any puppeteer API-compatible puppeteer implementation or version.
|
||||
|
||||
Returns: **[PuppeteerExtra](#puppeteerextra)** A fresh PuppeteerExtra instance using the provided puppeteer
|
||||
|
||||
An **alternative way** to use `puppeteer-extra`: Augments the provided puppeteer with extra plugin functionality.
|
||||
|
||||
This is useful in case you need multiple puppeteer instances with different plugins or to add plugins to a non-standard puppeteer package.
|
||||
|
||||
Example:
|
||||
|
||||
```javascript
|
||||
// js import
|
||||
const puppeteerVanilla = require('puppeteer')
|
||||
const { addExtra } = require('puppeteer-extra')
|
||||
|
||||
// ts/es6 import
|
||||
import puppeteerVanilla from 'puppeteer'
|
||||
import { addExtra } from 'puppeteer-extra'
|
||||
|
||||
// Patch provided puppeteer and add plugins
|
||||
const puppeteer = addExtra(puppeteerVanilla)
|
||||
puppeteer.use(...)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
Copyright © 2018 - 2023, [berstend̡̲̫̹̠̖͚͓̔̄̓̐̄͛̀͘](mailto:github@berstend.com?subject=[GitHub]%20PuppeteerExtra). Released under the MIT License.
|
||||
|
||||
<!-- Markdown footnotes (for links) -->
|
||||
|
||||
[puppeteerextraplugin]: https://github.com/berstend/puppeteer-extra/tree/master/packages/puppeteer-extra-plugin 'PuppeteerExtraPlugin Documentation'
|
||||
Reference in New Issue
Block a user