画像クローラー 

キーワードに沿った画像を大量に集めて、まとめてダウンロードすることができるWebツール、[画像クローラー](https://taptappun.net/tools/image_crawl)を作りましたのでご紹介します。[こちらから](https://taptappun.net/tools/image_crawl)

Mashup Awardsという開発者コンテストにも応募しました。[作品詳細](https://hacklog.jp/works/51698)

[ソースコード](https://github.com/TakuKobayashi/citore)も一応公開しています。[ソースコード](https://github.com/TakuKobayashi/citore)

※ディープラーニングのエンジニアリング Advent Calendar 2017ですが手法などについてではなくデータ集めについてが中心になります。

# [画像クローラー](https://taptappun.net/tools/image_crawl)について

## 動いている環境
 * さくらのVPS
 * AWS S3
 * CentOS 6.7
 * Ruby 2.4系
 * Rails 5.1系
 * MySQL 5.7系
 * Redis 2系
 * 主な使用ライブラリ: [httpclient](https://github.com/nahi/httpclient)(通信), [Nokogiri](https://github.com/sparklemotion/nokogiri)(Webスクレイピング) [Sidekiq](https://github.com/mperham/sidekiq)(ワーカーキュー),
 [FastImage](https://github.com/sdsykes/fastimage), ([MeCab](http://taku910.github.io/mecab/), [mecab-ipadic-neologd](https://github.com/neologd/mecab-ipadic-neologd),[Natto](https://github.com/buruzaemon/natto)(MeCabのRubyラッパー)), 各種SNSのライブラリやAPI

## 使い方
1.webページに行き、集めたい画像のキーワードを入力して画像を集める(集め終わるまで大体5分程かかります)
![ezgif-3-fdafe8ddfd.gif](https://qiita-image-store.s3.amazonaws.com/0/72596/34cc7c68-707e-ca2e-bcfe-4932c0f6818d.gif)


2.出来上がった頃に再びサイトを訪れてダウンロードする。(1回につき最大500枚の画像をまとめています)
![ezgif-3-7a13f9c0b3.gif](https://qiita-image-store.s3.amazonaws.com/0/72596/710804bb-9aa4-4cc4-1427-bd90f537e3b5.gif)

3.zipを展開するとなんかそれらしい画像が集められているのがわかると思います。
![ezgif-3-676e2de821.gif](https://qiita-image-store.s3.amazonaws.com/0/72596/6d0b030a-c3c1-a686-465f-6035e533b10f.gif)

## 管理ツール
管理ツールも作成しています。以下のように、画像とそれに付随したタグ(title)や画像の収集元の情報も保持しています。(これらのデータもzipの中に含めるかどうかはニーズ次第で)
![admin_tools.png](https://qiita-image-store.s3.amazonaws.com/0/72596/a665c165-e3e7-4990-bc52-ff64dec42fb0.png)


## 対応状況
現在、以下のWebサービスから検索して画像を集められるようにしています。

 * Google画像検索(元画像のサイズで取得しています)
 * Twitter
 * Flickr
 * ニコニコ静画
 * getty-images
 * Webサイト

今後、対応予定

 * Instagram
 * Pixiv
 * Facebook
 * Pinterest
 * 楽天
 * Amazon

他、対応希望のサイトやサービスなどありましたら、実装したいと思います。
また、画像以外にも動画、音楽、PDF、3Dモデル、各種テキストの収集も現在実装しています。また、追加の機能や情報が必要でしたら実装します。

# 機械学習・ディープラーニング
## つくるきっかけ

```
1. エロく見える画像をたくさん集めたかった
2. 2次元キャラ対話Botを作りたかった
```

そのために自然言語処理、機械学習・ディープラーニングの勉強をしましたが、
結局、ほとんどの時間がデータ集めに費やしたので、ここらへんをうまくやるためのツールを作成することにしました。

## 結論
<b><font color="#FF0000">学習させるために大量のデータを集めるのが一番大変!!</font></b>

## 勉強したこと
挙げると大量にありすぎてキリがないので大いに参考さてせていただいた文献を各種挙げていきます。

 * ディープラーニング全般
   * [深層学習生き地獄](https://www.slideshare.net/chabudaigaeshi/ss-70358029)
   * [はじめての深層学習（ディープラーニング）プログラミング](http://gihyo.jp/book/2017/978-4-7741-8534-7)

 * [Tensorflow](https://www.tensorflow.org/), [Chainer](https://chainer.org/), [FastText](https://github.com/facebookresearch/fastText)
 * RNN, [TF-IDF](https://ja.wikipedia.org/wiki/Tf-idf), cos類似度推定法, Word2Vec, [マルコフ連鎖](https://ja.wikipedia.org/wiki/%E3%83%9E%E3%83%AB%E3%82%B3%E3%83%95%E9%80%A3%E9%8E%96)
   * [ついに明かされる「りんな」の“脳内”　マイクロソフト、「女子高生AI」の自然言語処理アルゴリズムを公開](http://www.itmedia.co.jp/news/articles/1605/27/news110.html)
   * [TF-IDF Cos類似度推定法](https://qiita.com/nmbakfm/items/6bb91b89571dd68fcea6)
   * [テキスト分類器fastTextを用いた文章の感情極性判定](https://qiita.com/takumi_TKHS/items/d5131e08f0b4e36eed13)
   * [Facebookが公開した10億語を数分で学習するfastTextで一体何ができるのか](https://deepage.net/bigdata/machine_learning/2016/08/28/fast_text_facebook.html)
   * [【エヴァンゲリオン】アスカっぽいセリフをDeepLearningで自動生成してみる](https://qiita.com/S346/items/24e875e3c5ac58f55810)

などなどなど 
ここらへんの内容を駆使して、[りんな](https://www.rinna.jp/)のような自然な会話ができるBotを実現するためのアルゴリズムの構築の勉強をしていました。

一応TF-IDFによるキーワード抽出 + MySQLを使っての検索キーワードの最適化を実装しました。該当部分の処理はこちら
https://github.com/TakuKobayashi/citore/blob/master/server/app/models/datapool/hatsugen_komachi.rb
後述のデータ収集時のタグ付けにも応用することができます。

# 目的のデータを集める手法
基本的にはGoogle画像検索などのWebサービス検索エンジンを活用

## 検索エンジンを活用
Google画像検索やFlickerなどのSNSには多くの画像があり、また検索エンジンが優秀なため、目的のデータを集めるにはこれらのサービスを活用する(自動化させるバッチを記述する)ことで目的のデータを集めることができます。現在、画像クローラーで実装したサービスにおける画像のキーワードとの結びつきは以下の通り。

|サービス|タグにしたもの|ソースコード|
|---|---|---|
|Google画像検索|検索したキーワード|[コード](https://github.com/TakuKobayashi/citore/blob/master/server/app/models/datapool/google_image_search.rb)|
|Twitter|ツイート文(上記tf-idfでキーワード抽出)|[コード](https://github.com/TakuKobayashi/citore/blob/master/server/app/models/datapool/twitter_image_metum.rb)|
|Flickr|APIにあるtitle|[コード](https://github.com/TakuKobayashi/citore/blob/master/server/app/models/datapool/frickr_image_metum.rb)|
|ニコニコ静画|APIから取得できたtitle|[コード](https://github.com/TakuKobayashi/citore/blob/master/server/app/models/datapool/niconico_image_metum.rb)|
|getty-images|APIから取得できたtitle|[コード](https://github.com/TakuKobayashi/citore/blob/master/server/app/models/datapool/getty_image_metum.rb)|
|Webサイト|後述|[コード](https://github.com/TakuKobayashi/citore/blob/master/server/app/models/datapool/web_site_image_metum.rb)|

大体APIなどにあるtitleはその画像がどんな画像なのか表しているので、画像にタグをつける分には有効でした。

## Webページからデータを取得
Webページからデータを取得する際、幾つかの工夫が必要でしたのでご紹介します。
### Webページから画像のデータを取得する
webサイトにおいて画像を表示する場合HTMLは基本的に以下のように書きます。
```
<img src="url">
```
そのため、基本的にimgタグを検索し、そのsrcの中の値をHTMLから取得し、この値を基に画像のデータを取得します。
しかし、このsrcの値の中身は複数種類あるため、それぞれに応じたURLを自動整形する必要があります。

|ケース  |例  |対応策  |
|---|---|---|
|絶対URL|http://〜|そのまま|
|rootパス|/image.jpg|取得元のURLのホストとrootパスを結合|
|相対パス|image.jpg|取得元のURLのホストとパスに相対パスを結合|
|Base64|data:image〜;base64|文字列を正規表現で置換し、Base64のデータの部分だけbinaryにencodeしてそのままファイル保存|

さらに、一部imgタグがついているのに画像ファイルじゃないものも存在したため、一旦ファイルをダウンロードしてそのファイルが画像かどうか判別しています。詳しい処理は[こちら](https://github.com/TakuKobayashi/citore/blob/master/server/app/models/datapool/image_metum.rb)
これにより、約99%はどのwebサイトからも画像のデータを取得することができるようになりました。
※なおこの処理を作成しているときほどtypoされているものを恨めしく思ったことはありませんでした。

### Webページの画像が何なのか類推する
HTMLの中にはその画像がどんな画像なのか示すヒントがあります。それを基に画像にタグを付けています。
類推の方法は以下の通り

1. imgタグ内のaltタグの値
2. 1がなかったり、空っぽだったら、imgタグ内のtitleタグの値
3. 2がなかったり、空っぽだったら、imgタグ内のnameタグの値
4. 3がなかったり、空っぽだったら、imgタグ内の本文の値
5. 4もなかったら、サイトのtitleタグの値

類推中、絵文字や文字化けするような文字があった場合全てそれらを除去して見るようにしています。これで大体のサイトでその画像がの画像がどんな画像なのか示すヒントを取得できるようになりました。(他にいい方法があるんですかね?)

## Google画像検索による画像の収集について
おそらく最も画像検索のときに使うであろうGoogle画像検索を使っての画像収集の手法についてご紹介します。

1. https://www.google.co.jp/search?q=keyword&tbm=isch これでkeywordで検索された画像が取得できます。(tbm=ischこれが画像検索ということ意味するものです)
2. 上記URLを実行した限りだと、75件ぐらいまでしか取れないので、ブラウザで解析したところスクロールページのページ番号を表す、startとijnをキーにした値をURLにつけるとページにまたがって検索できました。(調べた方法については以下のようにネットワークプロファイラを開き、送られているリクエストの値を読んで類推しました)
![network_profile.pn](https://qiita-image-store.s3.amazonaws.com/0/72596/056fa0ec-fb08-7a4e-da30-91636851eeaa.png)

3. Googleの画像検索で取得されたHTMLのimgタグのデータを取得してしまうと小さいサムネイル画像になってしまいました。そこで、Google画像検索結果のHTMLの中にはどうやらaタグの中に元画像のURLとその画像が存在するwebサイトのURLが含まれているようだったので、aタグの中の値からその情報を取得するようにしました。(aタグの中のimgurlキーとimgrefurlキーがそれに該当)

以上の要領でデータを取得するのと同時に、Webページから画像データを取得する手法も併用して更に多くのデータを集めるようにしています。(詳しいソースコードは[こちら](https://github.com/TakuKobayashi/citore/blob/master/server/app/models/datapool/google_image_search.rb))

# まとめ
とにかく大量の画像を収集することに特化したWebツールを作りましたので紹介しました。
使っていただければ幸いです。
個人的にもこのツールを使って各種ディープラーニングの画像分類を勧めていきたいと思います。
また、ご要望などありましたらブラッシュアップや機能を追加していきたいと思います。