owned this note
owned this note
Published
Linked with GitHub
# モンストのキャラクターのプロフィールが知りたい
[ミクシィ20新卒AdventCalendar2019](https://adventar.org/calendars/4207) 6日目担当の[@patchgi](https://twitter.com/patchgi)です.
←前日 [死ぬまでにやりたいこと](https://hackmd.io/@takunoko/B1Ij7F-nH)
静岡出身だけど, 富士山登ったことないなぁ...
**富士山は静岡のものだけどね**
翌日→[人工知能でロウソク足予測](https://qiita.com/july1997/items/33ab007aea5f28c411c2)
今回はモンスト好きな筆者が苦手なプログラミングを片手に 自分の趣味に没頭したお話です.
記事内容の9割が箇条書き + 拙い文章力で書かれているんで読みにくかったらすみません
## 自己紹介
- 都内の大学院の研究室に所属する男
- モンストが好き
![](https://i.imgur.com/VYcsKwv.jpg)
## 概要
モンストのキャラクターの誕生日を通知する君を作るために辿った道筋
## モチベーション
よりモンストの世界を身近に感じたいという願望 + AdventCalendarを途切らせてはならないという使命感
## やったこと
- [XFLAG DICTIONARY](https://dic.xflag.com/monsterstrike/)からモンスターのプロフィールをスクレイピング
- 普通にXFLAG DICTIONARYを使えよ!って思う人もいるかもだけど, 名前でしか検索できないし, 一覧性が低いし, CSVとかを通してみたかっし, オタクだから!!それだけ!!!
## XFLAG DICTIONARY とは
> モンスターストライク(モンスト)の公式モンスタープロフィール特設サイト。ゲーム内では語られないキャラクター達の一面や関係性など様々な情報掲載中!(XFLAG DICTIONARYより)
モンストに出てくるキャラクターの簡単なプロフィールがまとまっているサイト(公式)
[XFLAG DICTIONARY](https://dic.xflag.com/monsterstrike/)
![](https://i.imgur.com/N4a7QLs.png)
## 調査編
XFLAG DICTIONARYがスクレイピング可能なサイトかを調べる.
### 調査項目
- robots.txt
- クローラに対してどのURLにアクセスして良いか、してはいけないかが書いてある.
- **やったこと**
- robots.txtを目視で確認
- 一応昔書いたrobots.txtのパーサを使って確認
- https://gist.github.com/patchgi/dc58c20d17cca7d40b23db1018e06292
- JSで書かれているサイトか
- HTMLやCSSで書かれているサイトであれば, サイトがホストしてる静的なファイルを適当にパースすればいい感じにスクレイピングできる(簡単!!)
- **But** そうでなかった場合, スクレイピングする前にサイトのJSを事前に実行しなくてはならない.
- **やったこと**
- XFLAG DICTIONARYでJSを切った状態でページの状態を確認
- JS OFF(ChromeApp)
- [ChromeWebStore](https://chrome.google.com/webstore/detail/jsoff/kjhbibcocglfnpllfodaiabanmmegomm)
- 必要な情報(キャラクターのプロフィール)を取得するためにどんな情報が欲しいか
- **やったこと**
- 実際にサイトに行ってDeveloperToolとにらめっこ
### 結果
- [robots.txt](https://dic.xflag.com/robots.txt)
- **result: 多分大丈夫...**
- JSで書かれているサイトか
- JSあり
- ![](https://i.imgur.com/bJIX6ai.png)
- JSなし
- ![](https://i.imgur.com/6wuZpiG.png)
- **result: JSで書かれてた...**
- 必要な情報(キャラクターのプロフィール)を取得するためにどんな情報が欲しいか
- 各キャラクターのプロフィールを取得するには, そのキャラクターのプロフィールページのリンクを取得する必要がある.
``` https://dic.xflag.com/monsterstrike/character/{キャラクターのID}```
- キャラクターのIDが分かれば, 各キャラクターのプロフィールページのリンクがわかる. このIDが連番になっていれば楽だったが,そうは問屋が卸さなかったのでこのIDのリストをスクレイピングで取得する.
- 各キャラクターのIDは, キャラクターリストページの各キャラクターの画像のファイル名と同じ & 他にそれっぽい情報がなかったから, 画像のファイル名からキャラクターのIDを抽出する.
- **result: キャラクターのリストページから各キャラクターの画像のファイル名を取得し, 紐づけられたIDを抽出する必要がある**
## 構想編
### 実装項目
- スクレイピング
- ページをJSを実行された状態でDOMを取りたい
- headless chromeとかPhantomJSが扱える言語なら何でもいい
- データ保存
- DBで管理するまでもないけど, いい感じに確認とかしたい
- CSV(GoogleSpreadSheet)に保存
GoogleSpreadSheetを簡単に操作するっていうと,GoogleAppScript(GAS)が一番最初に頭に浮かんだから, 言語は**GAS**にした。でも, GASってheadlessChromeとかを扱えるライブラリとかってあるんだろうか?って思って調べたらライブラリではないけどぽいのがあった[PhantomJSCloud](https://phantomjscloud.com/index.html). ページのURLを投げると, JSを実行した状態のHTMLtxtを返してくれるサービスらしい. 調べた感じ, 1日500pageまでなら無料で使えるらしい. XFLAG DICTIONARYに登録されているキャラクターは現在(2019/12/04)300未満なため, 運用するなら問題なさそう.(デバッグするなら別だけど)これを使おうと思う.
余談だけど, PhantomJSって随分前にメンテが終了した気がしたけど, こういう形で残っていて感慨深かった.
### 構想まとめ
- 言語: GAS
- JS実行: PhantomJSCloudのAPIを利用
- データ管理: CSV(GoogleSpreadSheet)
GASを採用した理由は他にも, 「実行環境を準備しなくてもいい.」 「通知をするための定期実行の仕組みがデフォでサポートされてて楽そう」ってのがある.
## 実装編
https://gist.github.com/patchgi/847b931c6bc4f16b1b28ce70f0ada246
↑最終的に書いたコード
![](https://i.imgur.com/WECm9n0.png)
↑取ってきたプロフィールデータ一部
### 実装システムの流れ
1. キャラクターリストページをPhantomJSCloudに投げ, JSが実行された状態でのHTMLtxtを取得
2. 返ってきたHTMLtxtをパースし, 各キャラクターに紐づけられたIDのリストを取得
3. 作ったIDリストを元に, 各キャラクターのプロフィールページのリンクを作成し, 再びPhantomJSCloudに投げJSが実行された状態でのHTMLtxtを取得
4. 返ってきたHTMLtxtをパースし, プロフィール情報を抽出
5. 抽出したプロフィール情報をGoogleSpreadSheetに書き込み
今回はスクレイピングまで...通知とかは後日やる
### 実装を終えて
#### Keep
- GoogleSpreadSheetの扱いはめちゃ楽だった.
- 環境構築をする必要がなかった.
- GAS自体あまり触ったことなかったけど, ほぼJavaScriptだからそんなにつまづくことがなかった.
#### Problem
- GASではES6の記法が使えなかった...
- ES6でかけるようにしてる人もいたけど, 面倒くさそうだったし, そこまでやったら環境構築楽っていうメリットがなさそう... っていう謎のプライドが発生してやらなかった.
- やればよかった
- GASはJavaScriptっぽいくせに, DOMのパーサがないから, 正規表現とかを使って要素を抽出することになった...
- (正確にはパーサのライブラリあったけど, うまく動かなかった)
- headless browserの部分を外部のサービスに委託したから, 1リクエストに結構時間がかかる(1リクエスト5 ~ 10秒くらい)
- インフラとかそこらへんに対する知識一切ないけど, リクエストに時間がかかるおかげで, サイト(XFLAG DICTIONARY)へはそんなに負荷はかかってないんじゃないかなぁ...
- リクエストに時間がかかるせいで, GASの1回の実行時間上限を超えてしまう.
- 何回かに分けて実行した
#### Try
- 使い慣れてる言語でやる.
- 「CSV扱いたい」とか「環境構築が楽」って理由だけで, GASを採用したけど, よくよく考えるとCSVならGoogleSpreadSheetとかに拘る必要ないし, PythonとかRubyとか使い慣れてる言語でやればよかったなぁ...
- でも, 普段使わないツールを使うのはそこそこ楽しかった
- それにしてもGASを使うのはセンスがなかった感もある...
## 終わりに
- 目的のデータを取ってくることができてよかった
- あとは, 取ってきたデータを煮るなり焼くなり好きに遊ぶだけ!
- 誕生日の表記が統一されていないので, そこは気をつけたい
- 例
- ![](https://i.imgur.com/rAFM3ec.png)
- ![](https://i.imgur.com/b2GCQgb.png)
- 今回は進化前のプロフィールのみを取得したけど, 一部進化するとプロフィールが変わるキャラクターがいるのでそこも取りたい
- 後日このデータをどう使ったかとかの記事を書くかも...
- こういうWebスクレイピングの記事をあげるの少し怖いんだけど, そんなに負荷をかけているわけでもないし, 営利目的で収集しているわけでもないし, 会員限定の情報とかを抜いてるわけでもないし, 大丈夫だとは思っている...
[Webスクレイピングの法律周りの話をしよう!](https://qiita.com/nezuq/items/3cc9772118ad112c18dc)
[Webスクレイピングの注意事項一覧](https://qiita.com/nezuq/items/c5e827e1827e7cb29011)
- **問題がありそうだったらこの記事取り下げます**
以上, モンストのキャラクターの誕生日を知りたい男の辿った道筋でしたー
(ジル・ド・レと誕生日が一緒だったから今度運極作ろうと思う.)
- ![ジル・ド・レ](https://i.imgur.com/7VKcmAZ.png)
ジル・ド・レ