- 投稿日:2020-02-15T19:43:09+09:00
Puppeteer Tips
Puppeteer?
読み方は「ぱぺてぃあ」。
Node.jsのライブラリでChromeを操作しDOMの要素を取得、ステータスコードを取得、レスポンスタイムを計測・・等々できます。
※Chromeのデベロッパーツールで見れる情報は(たぶん)全てpuppeteerで取得できるSample
「サイト内の各ページのタイトルが予測した値になっているか?」という自動テストをPuppeteerを利用して処理してみます。
大まかな流れは下記のようになります。
1. テストデータをCSVファイルから読み込み
2. 1行ずつループし、取得した値と予測した値を比較
3. 結果表示Code
https://github.com/yusukeito58/puppeteer-template
$ tree -I node_modules . ├── package.json └── src ├── data │ └── title.test.csv ├── lib │ └── output.js └── test └── title // テスト・処理内容応じてにディレクトリを切って、実行ファイル(index.js)と説明ファイル(README.md)を置くといい感じ ├── README.md // テスト概要や実行方法を記載 └── index.js // 実行ファイル
index.jsconst puppeteer = require('puppeteer'); const papa = require('papaparse'); const assert = require('assert'); const fs = require('fs'); const root = '../../' const { showTestStart, showResult } = require(root + 'lib/output'); // メイン処理 (async () => { console.time('Processing time'); // テスト対象のサイト const domain = 'https://www.google.com'; // テスト対象のデータ ※ Listを直接コードに書く、CSVから読み込む etc... file = fs.readFileSync(root + 'data/title.test.csv', 'utf8') dataList = papa.parse(file, { header: true, skipEmptyLines: true }).data; // カウンタ初期化 let count = 0; // エラー一覧 let errorList = []; // ブラウザ起動 const browser = await puppeteer.launch(); for (const data of dataList) { count += 1; // アクセス先のURLを生成 const url = domain + data.path; // 進捗を表示 showTestStart(url, count, dataList); // ページ生成 const page = await browser.newPage(); // JSやCSSの読み込みを無視 await page.setRequestInterception(true); page.on('request', (interceptedRequest) => { if (url === interceptedRequest.url()) { interceptedRequest.continue(); } else { interceptedRequest.abort(); } }); // テスト対象のURLにアクセス(返り値にresponseが返る) await page.goto(url); // ページタイトル取得 const title = await page.title(); try { // 予期された結果と比較 assert.equal(title, data.title); console.log('✅ ' + 'Expected result'); } catch (err) { console.log('❌ ' + 'Unexpected result'); console.log(err.message); errorList.push(err.message); } console.log('\n'); // ページ閉じる await page.close(); } // ブラウザ閉じる await browser.close() showResult(errorList); console.timeEnd('Processing time'); })();
lib/output.jsexports.showTestStart = (currentUrl, index, urls) => { const color = '\u001b[44m\u001b[37m'; const reset = '\u001b[0m'; console.log(`${color} ? ${currentUrl} | ${index} / ${urls.length} ${reset}`); }; exports.showResult = (errorList) => { let msg = ''; if (errorList.length === 0) { msg = '✅ ???Congratulation for passing!!???'; } else { msg = '❌ Failed the test...?'; } console.log('\n' + msg + '\n'); };
data/title.test.csvurl,title /,Google /search/howsearchworks/,Google Search - Discover How Google Search Workspackage.json{ "name": "puppeteer-template", "version": "1.0.0", "description": "", "main": "index.js", "directories": { "test": "test" }, "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "yusukeito58", "license": "MIT", "dependencies": { "assert": "^2.0.0", "papaparse": "^5.1.1", "puppeteer": "^2.1.1" } }
実行
サンプルで用意したプログラムを実行してみます。
$ git clone https://github.com/yusukeito58/puppeteer-template.git $ npm i $ cd src/test/title # 実行 $ node index.js結果
Tips
個人的に利用頻度が多い処理をまとめておきます。
特定要素の有無を判定
例. 検索ボタンがあるか確認
// 要素を取得 const hasElement = async (page, selector) => { const item = await page.$(); // selectorを引数で受け取るようにするともっと汎用的に使える if (item) { return true; } else { return false; } }; (async () => { for (...) { : const selector = 'center > input.gNO89b'; ret = await hasElement(page, selector); : } }();UserAgentを指定
例.デバイスを「iPhone X」に設定
const devices = require('puppeteer/DeviceDescriptors'); // テストデバイス const device = devices['iPhone X']; (async () => { for (...) { : // デバイス設定 await page.emulate(device); : } }();JSやCSSなどの読み込みを無視
処理速度が数倍違ってきます。
(async () => { for (...) { : await page.setRequestInterception(true); page.on('request', (interceptedRequest) => { if (url === interceptedRequest.url()) { interceptedRequest.continue(); } else { interceptedRequest.abort(); } }); : } }();テストデータをCSVファイルから取得
url,title /,Google /search/howsearchworks/,Google Search - Discover How Google Search Worksconst papa = require('papaparse'); const fs = require('fs'); : (async () => { : // テストデータ取得 file = fs.readFileSync(root + 'data/title.test.csv', 'utf8') dataList = papa.parse(file, { header: true, skipEmptyLines: true }).data; : )();非同期に対象ページにアクセス
データが大量にあった場合、直列的に対象ページにアクセスすると処理時間を要するため、非同期に同時処理すると処理時間が短縮されます。
安定しないケースもあるので、検証が必要かも知れません。(もっと良い方法ありそう)
例. 大量の対象URLが全て正常(ステータスコードが200である)か確認する// ステータスコードを取得 const getStatusCode = (browser, url) => { return new Promise(async (resolve) => { const page = await browser.newPage(); await page.setDefaultNavigationTimeout(0); await page.setRequestInterception(true); page.on('request', (interceptedRequest) => { if (url === interceptedRequest.url()) { interceptedRequest.continue(); } else { interceptedRequest.abort(); } }); const response = await page.goto(url); // ステータスコードを返却(true:200台) const result = { 'url': url, 'status': response.ok() } await page.close(); resolve(result); }) } : (async () => { : for (let url of urls) { allResponse.push(getStatusCode(browser, url)) // あまり大量だとPCがが唸る・・・ } errors = await Promise.all(allResponse) // 非同期実行 .then(results => { // エラーとなった情報だけにフィルタリング return results.filter(result => !result.status) }) : )();配列を〇〇個ごとに分割
Puppeteerから少し外れますが、前項の非同期処理を行う前処理です。同時実行する個数に調整する際に利用します。
const divideArrIntoPieces = (arr, n) => { let arrList = []; let idx = 0; while(idx < arr.length){ arrList.push(arr.splice(idx, idx + n)); } return arrList; } (async () => { : urlList = divideArrIntoPieces(allUrl, 10); for (let urls of urlList) { for (let url of urls) { : } } }();画像を保存
// ダウンロード対象 imgUrl = 'https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png'; // ローカルの保存先 const imgPath = './images/image.jpg'; // 画像ダウンロード const viewSource = await page.goto(imgUrl); // ローカルに保存 fs.writeFileSync(imgPath, await viewSource.buffer());参考
- Puppeteer : https://github.com/puppeteer/puppeteer
- Examples : https://github.com/puppeteer/examples
- API Document : https://github.com/puppeteer/puppeteer/blob/master/docs/api.md
- Assert : https://nodejs.org/api/assert.html
- Papaparse : https://www.papaparse.com
- 投稿日:2020-02-15T10:40:03+09:00
nvm環境でnpm自体を一発アップデートするコマンド
コマンド一発でnpm自身を最新化する方法
nvm環境でnpm自体のアップデートがうまく行かなかったのでコマンド一発で成功する方法を公開しときます。
たぶん、WindowsやMac両方動くと思います。やり方
以下、bashコマンドラインで実行してください。
(ヒアドキュメント使ってるのでcatから下部のEOFまでコピーしてね)$ cat <<EOF > npm_update.sh && chmod +x npm_update.sh && ./npm_update.sh && rm -rf ./npm_update.sh #!/usr/bin/bash cd "$PROGRAMFILES"/nodejs rm npm npx npm.cmd npx.cmd mv node_modules/npm node_modules/npm2 node node_modules/npm2/bin/npm-cli.js i -g npm@latest rm -rf node_modules/npm2/ EOFやってる事
実行ファイル生成
↓
実行権限を付与
↓
実行してnpmアップデート
↓
削除して終了上記にたどり着くまでの失敗
失敗1:「npm install -g npm」を実行してみた
まずは正攻法のやり方として「$ npm install -g npm」を実行してみると以下エラー。
C:\WINDOWS\system32>npm install -g npm npm ERR! code EEXIST npm ERR! path C:\Program Files\nodejs\npm.cmd npm ERR! Refusing to delete C:\Program Files\nodejs\npm.cmd: is outside C:\Program Files\nodejs\node_modules\npm and not a link npm ERR! File exists: C:\Program Files\nodejs\npm.cmd npm ERR! Remove the existing file and try again, or run npm npm ERR! with --force to overwrite files recklessly. npm ERR! A complete log of this run can be found in: npm ERR! C:\Users\inukujira\AppData\Roaming\npm-cache\_logs\2020-02-15T00_43_01_988Z-debug.log失敗2:「npm-windows-upgrade」を実行してみた
「npm-windows-upgrade」というモジュールを使えばいいというissueを見つけたのでインストールして実行してみた。
しかしうまくいかず...。C:\WINDOWS\system32>npm-windows-upgrade npm-windows-upgrade v6.0.1 ? Which version do you want to install? 6.13.7 Checked system for npm installation: According to PowerShell: C:\Program Files\nodejs According to npm: C:\Program Files\nodejs Decided that npm is installed in C:\Program Files\nodejs Upgrading npm... - Upgrading npm (fallback method)... \ You wanted to install npm 6.13.7, but the installed version is 6.13.4. A common reason is an attempted "npm install npm" or "npm upgrade npm". As of today, the only solution is to completely uninstall and then reinstall Node.js. For a small tutorial, please see https://github.com/felixrieseberg/npm-windows-upgrade#usage. Please consider reporting your trouble to https://aka.ms/npm-issues. Debug Information: node: 12.16.0 | v8: 7.8.279.23-node.31 | uv: 1.34.0 | zlib: 1.2.11 | brotli: 1.0.7 | ares: 1.15.0 | modules: 72 | nghttp2: 1.40.0 | napi: 5 | llhttp: 2.0.4 | http_parser: 2.9.3 | openssl: 1.1.1d | cldr: 35.1 | icu: 64.2 | tz: 2019c | unicode: 12.1 | os: win32 x64
- 投稿日:2020-02-15T10:40:03+09:00
nvm環境のnpm自体をコマンド一発で最新化する方法
コマンド一発でnpm自身を最新化する方法
nvm環境でnpm自体のアップデートがうまく行かなかったのでコマンド一発で成功する方法を公開しときます
やり方
以下、bashコマンドラインで実行するだけの簡単なお仕事
ヒアドキュメント使ってるのでcatから下部のEOFまでコピーしてね
(Macの場合は「$PROGRAMFILES」環境変数とれないので書き換えればOK)$ cat <<EOF > npm_update.sh && chmod +x npm_update.sh && ./npm_update.sh && rm -rf ./npm_update.sh #!/usr/bin/bash cd "$PROGRAMFILES"/nodejs rm npm npx npm.cmd npx.cmd mv node_modules/npm node_modules/npm2 node node_modules/npm2/bin/npm-cli.js i -g npm@latest rm -rf node_modules/npm2/ EOFやってる事
実行ファイル生成
↓
実行権限を付与
↓
実行してnpmアップデート
↓
削除して終了上記にたどり着くまでの失敗
失敗1:「npm install -g npm」を実行してみた
まずは正攻法のやり方として「$ npm install -g npm」を実行してみると以下エラー。
C:\WINDOWS\system32>npm install -g npm npm ERR! code EEXIST npm ERR! path C:\Program Files\nodejs\npm.cmd npm ERR! Refusing to delete C:\Program Files\nodejs\npm.cmd: is outside C:\Program Files\nodejs\node_modules\npm and not a link npm ERR! File exists: C:\Program Files\nodejs\npm.cmd npm ERR! Remove the existing file and try again, or run npm npm ERR! with --force to overwrite files recklessly. npm ERR! A complete log of this run can be found in: npm ERR! C:\Users\inukujira\AppData\Roaming\npm-cache\_logs\2020-02-15T00_43_01_988Z-debug.log失敗2:「npm-windows-upgrade」を実行してみた
「npm-windows-upgrade」というモジュールを使えばいいというissueを見つけたのでインストールして実行してみた。
しかしうまくいかず...。C:\WINDOWS\system32>npm-windows-upgrade npm-windows-upgrade v6.0.1 ? Which version do you want to install? 6.13.7 Checked system for npm installation: According to PowerShell: C:\Program Files\nodejs According to npm: C:\Program Files\nodejs Decided that npm is installed in C:\Program Files\nodejs Upgrading npm... - Upgrading npm (fallback method)... \ You wanted to install npm 6.13.7, but the installed version is 6.13.4. A common reason is an attempted "npm install npm" or "npm upgrade npm". As of today, the only solution is to completely uninstall and then reinstall Node.js. For a small tutorial, please see https://github.com/felixrieseberg/npm-windows-upgrade#usage. Please consider reporting your trouble to https://aka.ms/npm-issues. Debug Information: node: 12.16.0 | v8: 7.8.279.23-node.31 | uv: 1.34.0 | zlib: 1.2.11 | brotli: 1.0.7 | ares: 1.15.0 | modules: 72 | nghttp2: 1.40.0 | napi: 5 | llhttp: 2.0.4 | http_parser: 2.9.3 | openssl: 1.1.1d | cldr: 35.1 | icu: 64.2 | tz: 2019c | unicode: 12.1 | os: win32 x64