# モンストのキャラクターのプロフィールが知りたい [ミクシィ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) ジル・ド・レ