├── .gitignore ├── .eslintrc.js ├── package.json ├── README.md ├── CHANGELOG.md └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | screenshot.* 3 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "extends": "makina", 3 | }; 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "puppeteer-screenshot-cli", 3 | "version": "1.5.0", 4 | "engines": { 5 | "node": ">=6.4.0" 6 | }, 7 | "description": "Simple wrapper around Puppeteer to take screenshot from command line", 8 | "repository": "github:mabhub/puppeteer-screenshot-cli", 9 | "main": "index.js", 10 | "bin": { 11 | "puppeteer-screenshot": "./index.js" 12 | }, 13 | "keywords": [ 14 | "puppeteer", 15 | "screenshot", 16 | "cli" 17 | ], 18 | "author": "Benjamin Marguin ", 19 | "license": "ISC", 20 | "dependencies": { 21 | "command-line-args": "~5.0.2", 22 | "command-line-usage": "~4.1.0", 23 | "puppeteer": "~1.19.0" 24 | }, 25 | "scripts": { 26 | "version": "git changelog -t $npm_package_version && git add CHANGELOG.md" 27 | }, 28 | "devDependencies": { 29 | "eslint": "~6.3.0", 30 | "eslint-config-makina": "~1.0.1" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Puppeteer screenshot CLI 2 | 3 | Simple wrapper around [Puppeteer](https://github.com/GoogleChrome/puppeteer) to take screenshot from command line. 4 | 5 | ## Usage 6 | 7 | ```shell 8 | npm i [-g] puppeteer-screenshot-cli 9 | 10 | puppeteer-screenshot --url 'http://perdu.com' --selector 'h1' --output ./perdu.jpg 11 | puppeteer-screenshot -u 'http://perdu.com' -s 'body' -o - > /tmp/perdu.jpg 12 | puppeteer-screenshot 'http://perdu.com' > perdu.jpg 13 | 14 | ``` 15 | 16 | ### Options 17 | 18 | ``` 19 | Headless screenshot with Puppeteer 20 | 21 | -u, --url string URL to navigate page to. The url should include scheme, e.g. https://. 22 | 23 | -o, --output string The file path to save the image to. If path is a relative path, then it is 24 | resolved relative to current working directory. If no path is provided, the 25 | image won't be saved to the disk. 26 | 27 | -s, --selector string A CSS selector of an element to wait for. 28 | Default: body 29 | 30 | -t, --type string Specify screenshot type, can be either jpeg or png. 31 | Default: png 32 | 33 | -q, --quality number The quality of the image, between 0-100. Not applicable to png images. 34 | 35 | -w, --width number Viewport width in pixels 36 | Default: 800 37 | 38 | -h, --height number Viewport height in pixels 39 | Default: 600 40 | 41 | --timeout number Maximum time to wait for in milliseconds. 42 | Default: 30000 43 | 44 | -f, --fullPage When true, takes a screenshot of the full scrollable page. 45 | Defaults: false. 46 | 47 | --headless Whether to run browser in headless mode. 48 | Default: true 49 | 50 | -?, --help This help 51 | ``` 52 | 53 | ## See also 54 | 55 | - [puppeteer-trace-cli](https://www.npmjs.com/package/puppeteer-trace-cli) 56 | Simple wrapper around [Puppeteer](https://github.com/GoogleChrome/puppeteer) to trace webpage from command line. 57 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | 1.5.0 / 2021-01-29 3 | ================== 4 | 5 | * Bump lodash, acorn & https-proxy-agent 6 | * Add `--useragent` to set user agent 7 | 8 | 1.4.3 / 2019-09-11 9 | ================== 10 | 11 | * Setup and enforce eslint-config-makina as ESLint ruleset 12 | * Upgrade Puppeteer for security concerns 13 | 14 | 1.4.2 / 2019-01-03 15 | ================== 16 | 17 | * Fix vulnerabilities through `npm audit fix` 18 | 19 | 1.4.1 / 2018-02-13 20 | ================== 21 | 22 | * Remove extraneous space after `--timeout` flag definition 23 | * Return 1 as exit code on any catched exception 24 | 25 | 1.4.0 / 2018-02-12 26 | ================== 27 | 28 | * Debug `--headless` switch by inverting behavior 29 | * Offer a new flag for setting up default timeout duration 30 | * Avoid asking Puppeteer to clip element on fullpage capture 31 | * Catch errors from any calls to Puppeteer to finally close browser 32 | 33 | 1.3.1 / 2018-02-12 34 | ================== 35 | 36 | * Add cross reference to puppeteer-trace-cli 37 | * Remove an irregular whitespace 38 | * Update readme file to match current `--help` content 39 | 40 | 1.3.0 / 2018-02-11 41 | ================== 42 | 43 | * Improve main args processing 44 | * Unhide `--headless` option in `--help` 45 | * Use help texts from Puppeteer 46 | * Remove default type & quality settings 47 | * Improve `--help` and corresponding texts in readme 48 | 49 | 1.2.0 / 2018-02-10 50 | ================== 51 | 52 | * Redirect picture stream to stdout when `--output -` or `-o -` 53 | * Redirect picture stream to stdout when no `--output` given 54 | * Define minimum required node version to 6.4.0 55 | 56 | 1.1.1 / 2018-02-09 57 | ================== 58 | 59 | * Create command for updating changelog when releasing new version 60 | * Indicate default viewport in readme file 61 | * Change default suggested install source from Github to npm 62 | * Define github repository in package.json 63 | * Create changelog and rename main readme 64 | 65 | 1.1.0 / 2018-02-09 66 | =================== 67 | 68 | * Add eslint rules 69 | * Use STDout insead of console log & define exit codes 70 | * Use a constant for EOL char 71 | * Define language for readme code block 72 | 73 | 1.0.0 / 2018-02-09 74 | =================== 75 | 76 | * Add keywords, author, and signature 77 | * Enable command line access from package install 78 | * Create minimalist Readme 79 | * Ignore node_modules directory & default screenshot files 80 | 81 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const puppeteer = require('puppeteer'); 4 | 5 | const EOL = '\n'; 6 | 7 | const argsDef = [ 8 | /* eslint-disable no-multi-spaces */ 9 | { name: 'url', alias: 'u', type: String, description: `URL to navigate page to. The url should include scheme, e.g. https://.${EOL}`, defaultOption: true }, 10 | { name: 'output', alias: 'o', type: String, description: `The file path to save the image to. If path is a relative path, then it is resolved relative to current working directory. If no path is provided, the image won't be saved to the disk.${EOL}` }, 11 | { name: 'selector', alias: 's', type: String, description: `A CSS selector of an element to wait for. \n[italic]{Default: body}${EOL}` }, 12 | { name: 'type', alias: 't', type: String, description: `Specify screenshot type, can be either jpeg or png. \n[italic]{Default: png}${EOL}` }, 13 | { name: 'quality', alias: 'q', type: Number, description: `The quality of the image, between 0-100. Not applicable to png images.${EOL}` }, 14 | { name: 'width', alias: 'w', type: Number, description: `Viewport width in pixels \n[italic]{Default: 800}${EOL}` }, 15 | { name: 'height', alias: 'h', type: Number, description: `Viewport height in pixels \n[italic]{Default: 600}${EOL}` }, 16 | { name: 'useragent', type: String, description: `The user agent of the browser \n[italic]{Default: undefined}${EOL}` }, 17 | { name: 'timeout', type: Number, description: `Maximum time to wait for in milliseconds. \n[italic]{Default: 30000}${EOL}` }, 18 | { name: 'fullPage', alias: 'f', type: Boolean, description: `When true, takes a screenshot of the full scrollable page. \n[italic]{Defaults: false}.${EOL}` }, 19 | { name: 'noheadless', type: Boolean, description: `Allow disabling headless mode. \n[italic]{Default: false}${EOL}` }, 20 | { name: 'help', alias: '?', type: Boolean, description: `This help${EOL}` }, 21 | /* eslint-enable no-multi-spaces */ 22 | ]; 23 | 24 | const args = require('command-line-args')(argsDef); 25 | const usage = require('command-line-usage')({ header: 'Headless screenshot with Puppeteer', optionList: argsDef }); 26 | 27 | const doCapture = async function doCapture ({ 28 | url, 29 | output, 30 | type, 31 | quality, 32 | noheadless, 33 | selector = 'body', 34 | width = 800, 35 | height = 600, 36 | useragent = undefined, 37 | timeout = 30000, 38 | fullPage = false, 39 | }) { 40 | const browser = await puppeteer.launch({ headless: !noheadless }); 41 | const page = await browser.newPage(); 42 | 43 | page.setDefaultNavigationTimeout(timeout); 44 | 45 | try { 46 | if (useragent) { 47 | await page.setUserAgent(useragent); 48 | } 49 | 50 | await page.setViewport({ width, height }); 51 | 52 | await page.goto(url, { waitUntil: ['load', 'networkidle0'] }); 53 | 54 | await page.waitForSelector(selector, { visible: true, timeout }); 55 | 56 | const outputPath = output === '-' ? undefined : output; 57 | 58 | const picture = await page.screenshot({ 59 | type: type === 'jpg' ? 'jpeg' : type, 60 | quality, 61 | fullPage, 62 | path: outputPath, 63 | clip: !fullPage && await (await page.$(selector)).boundingBox(), 64 | }); 65 | 66 | if (!outputPath) { 67 | process.stdout.write(picture); 68 | } 69 | } catch (error) { 70 | await browser.close(); 71 | process.exitCode = 1; 72 | throw error; 73 | } 74 | 75 | await browser.close(); 76 | }; 77 | 78 | 79 | if (args.help || !args.url) { 80 | !args.help && process.stderr.write(`No url provided.${EOL}`); 81 | process.stderr.write(usage); 82 | process.exitCode = 1; 83 | } else { 84 | doCapture(args); 85 | } 86 | --------------------------------------------------------------------------------