投稿日:
2019年10月4日
最終更新日:
【サイトキャプチャ自動化】NightmareJSを使って大量の画面のキャプチャを自動で保存しよう【PhantomJS】
YouTubeも見てね♪
ねこじゃすり
猫を魅了する魔法の装備品!
Anker PowerCor
旅行には必須の大容量モバイルバッテリー!
[ノースフェイス] THE NORTH FACE メンズ アウター マウンテンライトジャケット
防水暴風で耐久性抜群なので旅行で大活躍です!
ペヤング ソースやきそば 120g×18個
とりあえず保存食として買っておけば間違いなし!
レッドブル エナジードリンク 250ml×24本
翼を授けよう!
ドラゴンクエスト メタリックモンスターズギャラリー メタルキング
みんな大好き経験値の塊をデスクに常備しておこう!
Bauhutte ( バウヒュッテ ) 昇降式 L字デスク ブラック BHD-670H-BK
メインデスクの横に置くのにぴったりなおしゃれな可動式ラック!
目次
大量のURLの画面キャプチャを自動化したい
もはやキャプチャ保存は人間のやる作業ではない
サイト開発等をしている場合、開発中の各画面のキャプチャを保存したいというケースがありますよね。
しかし、人力でブラウザで全てのページを開いてキャプチャツールを使って保存、、、なんて作業をするのはとても骨が折れます。
そんな時は、NightmareJSを使って自動化しちゃいましょう!
nightmareとは?
NightmareJSとは、スクレイピングなどを行う際に多く利用されるPhantomJSという有名なヘッドレスブラウザをさらに扱いやすくしたラッパーツールです。
A high-level browser automation library.
Nightmare
PhantomJSを使うとこう書いていた部分が、
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
phantom.create(function (ph) {
ph.createPage(function (page) {
page.open('http://yahoo.com', function (status) {
page.evaluate(function () {
var el =
document.querySelector('input[title="Search"]');
el.value = 'github nightmare';
}, function (result) {
page.evaluate(function () {
var el = document.querySelector('.searchsubmit');
var event = document.createEvent('MouseEvent');
event.initEvent('click', true, false);
el.dispatchEvent(event);
}, function (result) {
ph.exit();
});
});
});
});
});
|
こうなる。
1
2
3
4
|
yield Nightmare()
.goto('http://yahoo.com')
.type('input[title="Search"]', 'github nightmare')
.click('.searchsubmit');
|
神かよ!!!
って事で早速使ってみました。
手順
phantomjsのインストール
nightmarejsはPhantomejsに依存しているのでまずはそちらをインストールします。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
yarn add v1.17.3
warning package.json: No license field
warning No license field
[1/4] 🔍 Resolving packages...
[2/4] 🚚 Fetching packages...
[3/4] 🔗 Linking dependencies...
[4/4] 🔨 Building fresh packages...
success Saved lockfile.
warning No license field
success Saved 91 new dependencies.
info Direct dependencies
└─ phantomjs@2.1.7
info All dependencies
├─ ansi-styles@2.2.1
├─ asn1@0.2.4
├─ async@2.6.3
├─ aws-sign2@0.6.0
├─ balanced-match@1.0.0
├─ bcrypt-pbkdf@1.0.2
├─ bl@1.0.3
├─ brace-expansion@1.1.11
├─ caseless@0.11.0
├─ chalk@1.1.3
├─ combined-stream@1.0.8
├─ commander@2.20.0
├─ concat-map@0.0.1
├─ concat-stream@1.5.0
├─ core-util-is@1.0.2
├─ cryptiles@2.0.5
├─ dashdash@1.14.1
├─ debug@0.7.4
├─ delayed-stream@1.0.0
├─ ecc-jsbn@0.1.2
├─ escape-string-regexp@1.0.5
├─ extend@3.0.2
├─ extract-zip@1.5.0
├─ extsprintf@1.3.0
├─ fd-slicer@1.0.1
├─ forever-agent@0.6.1
├─ form-data@1.0.1
├─ fs-extra@0.26.7
├─ fs.realpath@1.0.0
├─ generate-function@2.3.1
├─ generate-object-property@1.2.0
├─ getpass@0.1.7
├─ glob@7.1.4
├─ graceful-fs@4.2.2
├─ har-validator@2.0.6
├─ has-ansi@2.0.0
├─ hasha@2.2.0
├─ hawk@3.1.3
├─ http-signature@1.1.1
├─ inflight@1.0.6
├─ inherits@2.0.4
├─ is-my-ip-valid@1.0.0
├─ is-my-json-valid@2.20.0
├─ is-property@1.0.2
├─ is-stream@1.1.0
├─ is-typedarray@1.0.0
├─ isarray@1.0.0
├─ isexe@2.0.0
├─ isstream@0.1.2
├─ json-schema@0.2.3
├─ json-stringify-safe@5.0.1
├─ jsonfile@2.4.0
├─ jsonpointer@4.0.1
├─ jsprim@1.4.1
├─ kew@0.7.0
├─ klaw@1.3.1
├─ lodash@4.17.15
├─ mime-db@1.40.0
├─ mime-types@2.1.24
├─ minimatch@3.0.4
├─ minimist@0.0.8
├─ mkdirp@0.5.0
├─ node-uuid@1.4.8
├─ oauth-sign@0.8.2
├─ pend@1.2.0
├─ phantomjs@2.1.7
├─ pinkie@2.0.4
├─ process-nextick-args@1.0.7
├─ progress@1.1.8
├─ qs@5.2.1
├─ readable-stream@2.0.6
├─ request-progress@2.0.1
├─ request@2.67.0
├─ rimraf@2.7.1
├─ safer-buffer@2.1.2
├─ sntp@1.0.9
├─ sshpk@1.16.1
├─ string_decoder@0.10.31
├─ stringstream@0.0.6
├─ strip-ansi@3.0.1
├─ supports-color@2.0.0
├─ throttleit@1.0.0
├─ tough-cookie@2.2.2
├─ tunnel-agent@0.4.3
├─ tweetnacl@0.14.5
├─ typedarray@0.0.6
├─ util-deprecate@1.0.2
├─ verror@1.10.0
├─ which@1.2.14
├─ xtend@4.0.2
└─ yauzl@2.4.1
✨ Done in 36.27s.
|
NightmareJSのインストール
次にNightmareJSをインストールします。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
|
yarn add v1.17.3
warning package.json: No license field
warning No license field
[1/4] 🔍 Resolving packages...
warning nightmare > electron > electron-download > nugget > progress-stream > through2 > xtend > object-keys@0.4.0:
[2/4] 🚚 Fetching packages...
[3/4] 🔗 Linking dependencies...
[4/4] 🔨 Building fresh packages...
success Saved lockfile.
warning No license field
success Saved 85 new dependencies.
info Direct dependencies
└─ nightmare@3.0.2
info All dependencies
├─ @types/node@8.10.53
├─ ajv@6.10.2
├─ array-find-index@1.0.2
├─ asynckit@0.4.0
├─ aws4@1.8.0
├─ buffer-from@1.1.1
├─ camelcase-keys@2.1.0
├─ camelcase@2.1.1
├─ clone@1.0.4
├─ code-point-at@1.1.0
├─ commander@1.0.4
├─ currently-unhandled@0.4.1
├─ decamelize@1.2.0
├─ deep-defaults@1.0.5
├─ deep-extend@0.6.0
├─ defaults@1.0.3
├─ electron-download@3.3.0
├─ electron@2.0.18
├─ enqueue@1.0.2
├─ error-ex@1.3.2
├─ es6-promise@4.2.8
├─ fast-deep-equal@2.0.1
├─ fast-json-stable-stringify@2.0.0
├─ find-up@1.1.2
├─ function-source@0.1.0
├─ har-schema@2.0.0
├─ home-path@1.0.6
├─ hosted-git-info@2.8.4
├─ indent-string@2.1.0
├─ ini@1.3.5
├─ is-arrayish@0.2.1
├─ is-finite@1.0.2
├─ is-fullwidth-code-point@1.0.0
├─ is-utf8@0.2.1
├─ jsesc@0.5.0
├─ json-schema-traverse@0.4.1
├─ keypress@0.1.0
├─ load-json-file@1.1.0
├─ loud-rejection@1.6.0
├─ map-obj@1.0.1
├─ meow@3.7.0
├─ minimist@1.2.0
├─ minstache@1.2.0
├─ mkdirp@0.5.1
├─ ms@2.0.0
├─ multiline@1.0.2
├─ nightmare@3.0.2
├─ normalize-package-data@2.5.0
├─ nugget@2.0.1
├─ object-assign@4.1.1
├─ object-keys@0.4.0
├─ parse-json@2.2.0
├─ path-exists@2.1.0
├─ path-parse@1.0.6
├─ path-type@1.1.0
├─ performance-now@2.1.0
├─ pretty-bytes@1.0.4
├─ progress-stream@1.2.0
├─ psl@1.4.0
├─ punycode@1.4.1
├─ rc@1.2.8
├─ read-pkg-up@1.0.1
├─ read-pkg@1.1.0
├─ redent@1.0.0
├─ repeating@2.0.1
├─ resolve@1.12.0
├─ safe-buffer@5.1.2
├─ semver@5.7.1
├─ signal-exit@3.0.2
├─ single-line-log@1.1.2
├─ sliced@1.0.1
├─ spdx-correct@3.1.0
├─ spdx-exceptions@2.2.0
├─ speedometer@0.1.4
├─ split2@2.2.0
├─ string-width@1.0.2
├─ strip-bom@2.0.0
├─ strip-indent@1.0.1
├─ strip-json-comments@2.0.1
├─ sumchecker@1.3.1
├─ through2@2.0.5
├─ trim-newlines@1.0.0
├─ uri-js@4.2.2
├─ uuid@3.3.3
└─ validate-npm-package-license@3.0.4
✨ Done in 93.50s.
|
スクリーンショットを保存
まずは試しに、Googleで検索した結果をキャプチャ保存するスクリプトを書いてみます。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
const Nightmare = require('nightmare')
const nightmare = Nightmare({ show: true})// ブラウザの設定
nightmare
.goto('https://google.com') // 表示するURL
.type('input[type=text]', 'blogenist') //タイピング対象のセレクタと入力値
.click('input[name=btnK]')// クリック対象のセレクタ
.wait('#resultStats') // 表示されるまで待つセレクタ
.screenshot("./sample.png") // キャプチャの保存設定
.end() // 終了
.catch(error => {
console.error('Search failed:', error)
})
|
また、yarn
で簡単に起動するためにpackage.json
のscripts
に以下の起動スクリプトを追記しておきます。
1
2
3
4
5
6
7
8
9
10
|
{
"scripts": {
"capture": "node ./capture.js" // 追加
},
"devDependencies": {
"nightmare": "^3.0.2",
"phantomjs": "^2.1.7"
},
"dependencies": {}
}
|
確認
では、実際にyarn capture
で起動してみましょう。
正しく検索操作とキャプチャ保存も出来ていますね♪
複数画面を自動キャプチャ保存
では、応用として複数画面のキャプチャを自動で保存してみましょう。
今回は、config.json
というファイルにキャプチャしたいページを管理し、ループ処理で自動保存する形式にしようと思います。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
{
"pages": [
{
"name": "ページ1",
"url": "https://blogenist.jp/2019/09/09/9157/"
},
{
"name": "ページ2",
"url": "https://blogenist.jp/2019/09/08/9128/"
},
{
"name": "ページ3",
"url": "https://blogenist.jp/2019/09/06/9121/"
}
]
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
const Nightmare = require('nightmare')
const fs = require('fs');
const config = require('./config.json');
config.pages.forEach((page) => {
const nightmare = Nightmare({ show: false,width: 1920})
const dist = `./dist/${page.name}/`;
const fileName = `${page.name}.png`;
if (!fs.existsSync(dist)) {
fs.mkdirSync(dist);
}
nightmare
.goto(page.url)
.wait(1000)
.screenshot(`${dist}/${fileName}`)
.end() // 終了
.catch(error => {
console.error('Search failed:', error)
})
});
|
レスポンシブも対応
さらに以下のようにデバイス情報を追記し、
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
{
"pages": [
{
"name": "ページ1",
"url": "https://blogenist.jp/2019/09/09/9157/"
},
{
"name": "ページ2",
"url": "https://blogenist.jp/2019/09/08/9128/"
},
{
"name": "ページ3",
"url": "https://blogenist.jp/2019/09/06/9121/"
}
],
"devices": [
{
"name": "PC",
"width": 1920,
"height": 1080
},
{
"name": "Tablet",
"width": 768,
"height": 1024
}
]
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
const Nightmare = require('nightmare')
const fs = require('fs');
const config = require('./config.json');
config.devices.forEach((device) => {
config.pages.forEach((page) => {
const nightmare = Nightmare({ show: false,width: device.width, height: device.height})
const dist = `./dist/${page.name}/`;
const fileName = `${device.name}-${page.name}.png`;
if (!fs.existsSync(dist)) {
fs.mkdirSync(dist);
}
nightmare
.goto(page.url)
.wait(1000)
.screenshot(`${dist}/${fileName}`)
.end()
})
});
});
|
ネストループする事で一気に2端末分のレスポンシブデザインの確認をするためのキャプチャも取れてしまいます・・・!
かなり便利です!!!
スクロール領域のキャプチャ
次は縦スクロールが発生する画面のキャプチャを撮ってみましょう。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
const Nightmare = require('nightmare')
const fs = require('fs');
const config = require('./config.json');
config.pages.forEach((page) => {
const nightmare = Nightmare({ show: false,width: device.width, height: device.height})
const dist = `./dist/${page.name}/`;
const fileName = `${device.name}-${page.name}.png`;
if (!fs.existsSync(dist)) {
fs.mkdirSync(dist);
}
nightmare
.goto(page.url)
.wait(1000)
.evaluate(() => {
return {
width: document.body.scrollWidth,
height: document.body.scrollHeight
};
})
.then(({ width, height }) => {
nightmare.viewport(width, height);
})
.then(() => {
nightmare.screenshot(`${dist}/${fileName}`)
.end()
.catch(error => {
console.error('Search failed:', error)
})
})
});
|
確認
正常にスクロールが発生する画面でも全体のキャプチャが取れました。
終わりに
以上のように、簡単に画面キャプチャを撮る事が出来ました。
たくさんの画面キャプチャを取らないといけない場合は、あらかじめ導入しておくととても便利ですので是非試して見てください♪