browser.js

Created Diff never expires
8 removals
Words removed8
Total words676
Words removed (%)1.18
267 lines
9 additions
Words added10
Total words678
Words added (%)1.47
268 lines
const puppeteer = require('puppeteer');
const chromium = require('chrome-aws-lambda');

const fs = require('fs');
const fs = require('fs');
const URL = require('url').URL;
const URL = require('url').URL;
const URLParse = require('url').parse;
const URLParse = require('url').parse;


const [, , ...args] = process.argv;
const [, , ...args] = process.argv;


/**
/**
* There are two ways for Browsershot to communicate with puppeteer:
* There are two ways for Browsershot to communicate with puppeteer:
* - By giving a options JSON dump as an argument
* - By giving a options JSON dump as an argument
* - Or by providing a temporary file with the options JSON dump,
* - Or by providing a temporary file with the options JSON dump,
* the path to this file is then given as an argument with the flag -f
* the path to this file is then given as an argument with the flag -f
*/
*/
const request = args[0].startsWith('-f ')
const request = args[0].startsWith('-f ')
? JSON.parse(fs.readFileSync(new URL(args[0].substring(3))))
? JSON.parse(fs.readFileSync(new URL(args[0].substring(3))))
: JSON.parse(args[0]);
: JSON.parse(args[0]);


const requestsList = [];
const requestsList = [];


const getOutput = async (page, request) => {
const getOutput = async (page, request) => {
let output;
let output;


if (request.action == 'requestsList') {
if (request.action == 'requestsList') {
output = JSON.stringify(requestsList);
output = JSON.stringify(requestsList);


return output;
return output;
}
}


if (request.action == 'evaluate') {
if (request.action == 'evaluate') {
output = await page.evaluate(request.options.pageFunction);
output = await page.evaluate(request.options.pageFunction);


return output;
return output;
}
}


output = await page[request.action](request.options);
output = await page[request.action](request.options);


return output.toString('base64');
return output.toString('base64');
};
};


const callChrome = async () => {
const callChrome = async () => {
let browser;
let browser;
let page;
let page;
let output;
let output;
let remoteInstance;
let remoteInstance;


try {
try {
if (request.options.remoteInstanceUrl || request.options.browserWSEndpoint ) {
if (request.options.remoteInstanceUrl || request.options.browserWSEndpoint ) {
// default options
// default options
let options = {
let options = {
ignoreHTTPSErrors: request.options.ignoreHttpsErrors
ignoreHTTPSErrors: request.options.ignoreHttpsErrors
};
};


// choose only one method to connect to the browser instance
// choose only one method to connect to the browser instance
if ( request.options.remoteInstanceUrl ) {
if ( request.options.remoteInstanceUrl ) {
options.browserURL = request.options.remoteInstanceUrl;
options.browserURL = request.options.remoteInstanceUrl;
} else if ( request.options.browserWSEndpoint ) {
} else if ( request.options.browserWSEndpoint ) {
options.browserWSEndpoint = request.options.browserWSEndpoint;
options.browserWSEndpoint = request.options.browserWSEndpoint;
}
}


try {
try {
browser = await puppeteer.connect( options );
browser = await chromium.puppeteer.connect( options );


remoteInstance = true;
remoteInstance = true;
} catch (exception) { /** does nothing. fallbacks to launching a chromium instance */}
} catch (exception) { /** does nothing. fallbacks to launching a chromium instance */}
}
}


if (!browser) {
if (!browser) {
browser = await puppeteer.launch({
browser = await chromium.puppeteer.launch({
ignoreHTTPSErrors: request.options.ignoreHttpsErrors,
ignoreHTTPSErrors: request.options.ignoreHttpsErrors,
executablePath: request.options.executablePath,
executablePath: await chromium.executablePath,
args: request.options.args || []
args: [...chromium.args, ...(request.options.args || [])],
});
});
}
}


page = await browser.newPage();
page = await browser.newPage();


if (request.options && request.options.disableJavascript) {
if (request.options && request.options.disableJavascript) {
await page.setJavaScriptEnabled(false);
await page.setJavaScriptEnabled(false);
}
}


await page.setRequestInterception(true);
await page.setRequestInterception(true);


page.on('request', request => {
page.on('request', request => {
requestsList.push({
requestsList.push({
url: request.url(),
url: request.url(),
});
});
request.continue();
request.continue();
});
});


if (request.options && request.options.disableImages) {
if (request.options && request.options.disableImages) {
page.on('request', request => {
page.on('request', request => {
if (request.resourceType() === 'image')
if (request.resourceType() === 'image')
request.abort();
request.abort();
else
else
request.continue();
request.continue();
});
});
}
}


if (request.options && request.options.blockDomains) {
if (request.options && request.options.blockDomains) {
var domainsArray = JSON.parse(request.options.blockDomains);
var domainsArray = JSON.parse(request.options.blockDomains);
page.on('request', request => {
page.on('request', request => {
const hostname = URLParse(request.url()).hostname;
const hostname = URLParse(request.url()).hostname;
domainsArray.forEach(function(value){
domainsArray.forEach(function(value){
if (hostname.indexOf(value) >= 0) request.abort();
if (hostname.indexOf(value) >= 0) request.abort();
});
});
request.continue();
request.continue();
});
});
}
}


if (request.options && request.options.blockUrls) {
if (request.options && request.options.blockUrls) {
var urlsArray = JSON.parse(request.options.blockUrls);
var urlsArray = JSON.parse(request.options.blockUrls);
page.on('request', request => {
page.on('request', request => {
urlsArray.forEach(function(value){
urlsArray.forEach(function(value){
if (request.url().indexOf(value) >= 0) request.abort();
if (request.url().indexOf(value) >= 0) request.abort();
});
});
request.continue();
request.continue();
});
});
}
}


if (request.options && request.options.dismissDialogs) {
if (request.options && request.options.dismissDialogs) {
page.on('dialog', async dialog => {
page.on('dialog', async dialog => {
await dialog.dismiss();
await dialog.dismiss();
});
});
}
}


if (request.options && request.options.userAgent) {
if (request.options && request.options.userAgent) {
await page.setUserAgent(request.options.userAgent);
await page.setUserAgent(request.options.userAgent);
}
}


if (request.options && request.options.device) {
if (request.options && request.options.device) {
const devices = puppeteer.devices;
const devices = chromium.puppeteer.devices;
const device = devices[request.options.device];
const device = devices[request.options.device];
await page.emulate(device);
await page.emulate(device);
}
}


if (request.options && request.options.emulateMedia) {
if (request.options && request.options.emulateMedia) {
await page.emulateMediaType(request.options.emulateMedia);
await page.emulateMediaType(request.options.emulateMedia);
}
}


if (request.options && request.options.viewport) {
if (request.options && request.options.viewport) {
await page.setViewport(request.options.viewport);
await page.setViewport(request.options.viewport);
}
}


if (request.options && request.options.extraHTTPHeaders) {
if (request.options && request.options.extraHTTPHeaders) {
await page.setExtraHTTPHeaders(request.options.extraHTTPHeaders);
await page.setExtraHTTPHeaders(request.options.extraHTTPHeaders);
}
}


if (request.options && request.options.authentication) {
if (request.options && request.options.authentication) {
await page.authenticate(request.options.authentication);
await page.authenticate(request.options.authentication);
}
}


if (request.options && request.options.cookies) {
if (request.options && request.options.cookies) {
await page.setCookie(...request.options.cookies);
await page.setCookie(...request.options.cookies);
}
}


if (request.options && request.options.timeout) {
if (request.options && request.options.timeout) {
await page.setDefaultNavigationTimeout(request.options.timeout);
await page.setDefaultNavigationTimeout(request.options.timeout);
}
}


const requestOptions = {};
const requestOptions = {};


if (request.options && request.options.networkIdleTimeout) {
if (request.options && request.options.networkIdleTimeout) {
requestOptions.waitUntil = 'networkidle';
requestOptions.waitUntil = 'networkidle';
requestOptions.networkIdleTimeout = request.options.networkIdleTimeout;
requestOptions.networkIdleTimeout = request.options.networkIdleTimeout;
} else if (request.options && request.options.waitUntil) {
} else if (request.options && request.options.waitUntil) {
requestOptions.waitUntil = request.options.waitUntil;
requestOptions.waitUntil = request.options.waitUntil;
}
}


await page.goto(request.url, requestOptions);
await page.goto(request.url, requestOptions);


if (request.options && request.options.disableImages) {
if (request.options && request.options.disableImages) {
await page.evaluate(() => {
await page.evaluate(() => {
let images = document.getElementsByTagName('img');
let images = document.getElementsByTagName('img');
while (images.length > 0) {
while (images.length > 0) {
images[0].parentNode.removeChild(images[0]);
images[0].parentNode.removeChild(images[0]);
}
}
});
});
}
}


if (request.options && request.options.types) {
if (request.options && request.options.types) {
for (let i = 0, len = request.options.types.length; i < len; i++) {
for (let i = 0, len = request.options.types.length; i < len; i++) {
let typeOptions = request.options.types[i];
let typeOptions = request.options.types[i];
await page.type(typeOptions.selector, typeOptions.text, {
await page.type(typeOptions.selector, typeOptions.text, {
'delay': typeOptions.delay,
'delay': typeOptions.delay,
});
});
}
}
}
}


if (request.options && request.options.selects) {
if (request.options && request.options.selects) {
for (let i = 0, len = request.options.selects.length; i < len; i++) {
for (let i = 0, len = request.options.selects.length; i < len; i++) {
let selectOptions = request.options.selects[i];
let selectOptions = request.options.selects[i];
await page.select(selectOptions.selector, selectOptions.value);
await page.select(selectOptions.selector, selectOptions.value);
}
}
}
}


if (request.options && request.options.clicks) {
if (request.options && request.options.clicks) {
for (let i = 0, len = request.options.clicks.length; i < len; i++) {
for (let i = 0, len = request.options.clicks.length; i < len; i++) {
let clickOptions = request.options.clicks[i];
let clickOptions = request.options.clicks[i];
await page.click(clickOptions.selector, {
await page.click(clickOptions.selector, {
'button': clickOptions.button,
'button': clickOptions.button,
'clickCount': clickOptions.clickCount,
'clickCount': clickOptions.clickCount,
'delay': clickOptions.delay,
'delay': clickOptions.delay,
});
});
}
}
}
}


if (request.options && request.options.addStyleTag) {
if (request.options && request.options.addStyleTag) {
await page.addStyleTag(JSON.parse(request.options.addStyleTag));
await page.addStyleTag(JSON.parse(request.options.addStyleTag));
}
}


if (request.options && request.options.addScriptTag) {
if (request.options && request.options.addScriptTag) {
await page.addScriptTag(JSON.parse(request.options.addScriptTag));
await page.addScriptTag(JSON.parse(request.options.addScriptTag));
}
}


if (request.options.delay) {
if (request.options.delay) {
await page.waitFor(request.options.delay);
await page.waitFor(request.options.delay);
}
}


if (request.options.selector) {
if (request.options.selector) {
const element = await page.$(request.options.selector);
const element = await page.$(request.options.selector);
if (element === null) {
if (element === null) {
throw {type: 'ElementNotFound'};
throw {type: 'ElementNotFound'};
}
}


request.options.clip = await element.boundingBox();
request.options.clip = await element.boundingBox();
}
}


if (request.options.function) {
if (request.options.function) {
let functionOptions = {
let functionOptions = {
polling: request.options.functionPolling,
polling: request.options.functionPolling,
timeout: request.options.functionTimeout || request.options.timeout
timeout: request.options.functionTimeout || request.options.timeout
};
};
await page.waitForFunction(request.options.function, functionOptions);
await page.waitForFunction(request.options.function, functionOptions);
}
}


output = await getOutput(page, request);
output = await getOutput(page, request);


if (!request.options.path) {
if (!request.options.path) {
console.log(output);
console.log(output);
}
}


if (remoteInstance && page) {
if (remoteInstance && page) {
await page.close();
await page.close();
}
}


await remoteInstance ? browser.disconnect() : browser.close();
await remoteInstance ? browser.disconnect() : browser.close();
} catch (exception) {
} catch (exception) {
if (browser) {
if (browser) {


if (remoteInstance && page) {
if (remoteInstance && page) {
await page.close();
await page.close();
}
}


await remoteInstance ? browser.disconnect() : browser.close();
await remoteInstance ? browser.disconnect() : browser.close();
}
}


console.error(exception);
console.error(exception);


if (exception.type === 'ElementNotFound') {
if (exception.type === 'ElementNotFound') {
process.exit(2);
process.exit(2);
}
}


process.exit(1);
process.exit(1);
}
}
};
};


callChrome();
callChrome();