【スターターキットNo.2】テキスト分析機能(自動タグ付け/可視化)つき汎用Webスクレイピングツールをさらす

# Easy Customizable Scraper

[前回のスターターキット](https://qiita.com/Makotunes/items/dfde330b5054d7c06e0f)のアクセスが良かったので、第２弾をやります。
今回も簡単に利用でき、簡単に拡張可能な形でスターターキット提供します。

## コンセプト

![screencapture-mockers-io-scanner-2020-02-29-15_20_39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/514619/c77b7b8f-2b77-d5ad-e2e1-a50af08f294b.png)

テキスト分析機能つき汎用Webスクレイピングツールです。

以下のような特徴で、ユーザーの開発スタートを支援します。

- 簡単設定
- カスタマイズ性
- テキスト分析機能(タグ付け/可視化)

ソースコードはこちら
https://github.com/makotunes/easy-customizable-scraper


## 用途例

- キュレーションメディアの記事収集と自動タグ付け等
- レコメンドエンジン

このアルゴリズムは、私の個人開発しているプロダクトの機能に利用されています。
https://mockers.io/scanner

## 要素技術

- Webスクレイピング
- 自動言語判別
- 形態素解析
- 特徴タグ付けアルゴリズム(オリジナル)
- ２次元マップ可視化技術(オリジナル)



## 依存関係

- Docker

## インストール

１〜２時間程度かかります。

```Shell:build.sh
docker build -t scanner .
```

or

```Shell
./build.sh
```

## 実行

```Shell:run.sh
docker run --rm -it -v "$PWD":/usr/src/app \
--name scanner --force scanner  \
-e 'ENTRY_URL=http://recipe.hacarus.com/' \
-e 'ALLOW_RULE=/recipe/' \
-e 'IMAGE_XPATH=//*[@id="root"]/div/div/section/div/div/div[1]/figure/img' \
-e 'DOCUMENT_XPATH=//td/text()|//p/text()' \
-e 'PAGE_LIMIT=2000' \
-e 'EXCLUDE_REG=\d(年|月|日|時|分|秒|ｇ|\u4eba|\u672c|cm|ml|g|\u5206\u679a\u5ea6)|hacarusinc|allrightsreserved' \
scanner:latest /usr/src/app/entrypoint.sh
```

or 

```Shell
./run.sh
```

## 簡単設定

Dockerコンテナの環境変数に指定することで以下の設定ができます。
最低限ENTRY_URLさえあれば自動でページスキャンしてテキストを引っ張り出します。
オプション指定がない場合、キュレーションメディア用の最適化されており、記事のテキストを抽出するなど全自動で行えます。


| Environment Variable | Description                                                                                  |
|----------------------|----------------------------------------------------------------------------------------------|
| ENTRY_URL            | (必須) スキャンの開始するサイトトップURL。サイト内は自動でスキャンされる。 |
| ALLOW_RULE           | スキャン許可URLフィルター。                                                          |
| DENY_RULE            | スキャン拒否URLフィルター。許可URLフィルターより優先される。                                                         |
| IMAGE_XPATH          | ページで取得したい画像をXPATHで指定。                                                              |
| DOCUMENT_XPATH       | ページ内でテキストを抽出する範囲の最上位ノードのXPATH。                                                        |
| PAGE_LIMIT           | スキャンされるページの最大数制限。 -1は無制限。                            |
| EXCLUDE_REG          | 形態素解析により抽出しない単語を正規表現で定義。                         |


## Result

result/res.json

## カスタマイズ

customディレクトリにスクレイピングや後処理を拡張できます。


### custom/_formatter.py

PythonのScrapyの[セレクター](https://docs.scrapy.org/en/latest/topics/selectors.html)が引数です。
XPATHなどで、欲しい情報を個別に指定し、戻り値に追加します。
ここの実装はいわゆる普通のWebスクレイピングです。

```Python:custom/_formatter.py
def formatter(sel):
    res = {}

    n_howtomake = int(len(sel.xpath('//*[@id="root"]/div/div/section/div/div/div[2]/div[1]/table[2]/tbody/tr/td/text()').extract()) / 2)
    res["n_howtomake"] = n_howtomake

    return res
```


### custom/_finalizer.py

最終出力のJSONをカスタマイズできます。
自由に構造を整形したり、適宜分析機能を追加するなどに利用してください。
下の例では抽出した値の相関を分析しています。


```Python:custom/_finalizer.py
import pandas as pd

def finalizer(res):
    pages = res["scatter"]
    pages = list(map(lambda x: x["user_meta"], pages))
    df = pd.DataFrame(pages)

    corr_df = df.loc[:, ["time", "n_howtomake", "n_components"]].corr()

    res["analyzed"] = {}
    res["analyzed"]["correlation"] = {}
    res["analyzed"]["correlation"]["time-n_howtomake"] = corr_df.loc["time", "n_howtomake"]

    return res
```

## 使用例

ここからは、スクレイピングと分析を行う、本ツールの使用例になります。

[無料の料理レシピサイト](http://recipe.hacarus.com/)の分析をやってみます。
**アクセスできない場合、シークレットモードで開いてみてください。**

これらの結果はすべてresultディレクトリに格納されます。

### 調理時間、材料数、作り方の手順の数の分布を視覚化する

```Python:custom/_finalizer.py
import matplotlib.pyplot as plt
import pandas as pd

def finalizer(res):

    pages = res["scatter"]
    pages = list(map(lambda x: x["user_meta"], pages))
    df = pd.DataFrame(pages)

    fig = plt.figure()
    x = df["time"]
    y = df["n_howtomake"]
    plt.scatter(x, y)
    plt.savefig('./result/time-n_howtomake.png')

    fig = plt.figure()
    x = df["time"]
    y = df["n_components"]
    plt.scatter(x, y)
    plt.savefig('./result/time-n_components.png')

    fig = plt.figure()
    x = df["n_howtomake"]
    y = df["n_components"]
    plt.scatter(x, y)
    plt.savefig('./result/n_howtomake-n_components.png')
    
    return res
```

#### 結果

##### 調理時間：作り方

![time-n_howtomake.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/514619/5a4c2010-a296-d344-1217-dd4778c5d162.png)

##### 調理時間：材料数

![time-n_components.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/514619/84e37f59-20fc-a40f-bb54-680509bd1701.png)

##### 作り方：材料数

![n_howtomake-n_components.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/514619/4fb6f67b-adbf-2c9c-52c0-f0580999a28f.png)


### 調理時間、材料数、作り方の手順の数の各々の相関をしらべる

```Python:custom/_finalizer.py
import matplotlib.pyplot as plt
import pandas as pd

def finalizer(res):
    pages = res["scatter"]
    pages = list(map(lambda x: x["user_meta"], pages))
    df = pd.DataFrame(pages)

    corr_df = df.loc[:, ["time", "n_howtomake", "n_components"]].corr()

    res["analyzed"] = {}
    res["analyzed"]["correlation"] = {}
    res["analyzed"]["correlation"]["time-n_howtomake"] = corr_df.loc["time", "n_howtomake"]
    res["analyzed"]["correlation"]["time-n_components"] = corr_df.loc["time", "n_components"]
    res["analyzed"]["correlation"]["n_howtomake-n_components"] = corr_df.loc["n_howtomake", "n_components"]

    fig = plt.figure()
    
    return res
```

#### 結果

##### 調理時間：作り方

`0.30457219729662316`

##### 調理時間：材料数

`0.3949520467754227`

##### 作り方：材料数

`0.6869899620517819`


### 各レシピを特徴づけるキーワードを3語程度選び出す

result/tagged.csv

|title                           |tag1  |tag2     |tag3    |
|--------------------------------|------|---------|--------|
|なすとトマトの中華和え(１５分)                |なす    |トマト      |大葉      |
|ぶりの照り焼き(45分)                    |両面    |照り焼き     |水気      |
|おでん風煮(2時間)                      |大根    |こんにゃく    |竹輪      |
|大根とツナのサラダ(15分)                  |ツナ    |大根       |わかめ     |
|鶏の照り焼き丼(20分)                    |片栗粉   |にんにく     |れんこん    |
|筑前煮(６０分)                        |れんこん  |ごぼう      |こんにゃく   |
|白菜とわかめの酢の物(15分)                 |白菜    |わかめ      |しめじ     |
|鮭のホイル焼き(25分)                    |玉ねぎ   |しめじ      |ピーマン    |
|キャベツとハムの粒マスタード和え(１５分)           |キャベツ  |しめじ      |ハム      |
|えのきとワカメの和え物(15分)                |えのき   |わかめ      |きゅうり    |
|里芋のおやき(３０分)                     |里芋    |片栗粉      |桜えび     |
|鶏肉と里芋の煮物(60分)                   |里芋    |鶏肉       |相性      |
|焼き万願寺唐辛子(10分)                   |万願寺唐辛子|かつお節     |作り方     |
|肉じゃが(45分)                       |玉ねぎ   |牛肉       |じゃがいも   |
|鰆の幽庵焼き(１５分(漬け込む時間は省く))          |冷蔵庫   |鰆        |ゆず      |
|オクラの煮びたし(１０分(冷やす時間は除く))         |オクラ   |しょうが     |オクラ     |
|春菊と油揚げの煮びたし(15分)                |春菊    |油揚げ      |春菊      |
|しいたけのツナマヨ焼き(１０分)                |マヨネーズ |塩コショウ    |しいたけ    |
|コールスロー(15分)                     |キャベツ  |マヨネーズ    |きゅうり    |
|じゃがいもとタコのガーリック炒め(２０分)           |にんにく  |じゃがいも    |タコ      |
|棒棒鶏(３０分)                        |しょうが  |トマト      |きゅうり    |
|アボカドのチーズ焼き(15分)                 |アボカド  |ハム       |チーズ     |
|キャベツと大葉のさっぱり和え(１０分)             |大葉    |キャベツ     |大葉      |
|カニカマサラダ(10分)                    |レタス   |きゅうり     |サラダ     |
|ズッキーニともやしのナムル(１５分)              |ズッキーニ |もやし      |粗熱      |
|春雨サラダ(１５分)                      |春雨    |きゅうり     |ハム      |
|白菜と油揚げのみぞれ煮(３０分)                |大根    |白菜       |油揚げ     |
|牛肉とれんこんの甘辛炒め(30分)               |れんこん  |にんにく     |牛肉      |
|豚丼(30分)                         |しょうが  |しめじ      |レタス     |
|紅白なます(30分)                      |ゆず皮   |大根       |部分      |
|里芋のガーリック焼き(３０分)                 |里芋    |にんにく     |香り      |
|ブロッコリーのごまみそ和え(10分)              |ブロッコリー|和風       |みそ      |
|ブロッコリーのゴマ和え(１５分)                |ブロッコリー|出汁醤油     |粗熱      |
|かぶの甘酢漬け(１時間)                    |ゆず    |甘酢       |昆布      |
|さんまのしょうが煮(３０分)                  |さんま   |しょうが     |圧力      |
|スパゲティーサラダ(２０分)                  |大根    |きゅうり     |スパゲッティ  |
|切り干し大根の煮物(２５分)                  |切り干し大根|油揚げ      |短冊      |
|なすとオクラの和え物(１０分)                 |なす    |オクラ      |出汁醤油    |
|なすと厚揚げのおろしあん(30分)               |厚揚げ   |なす       |片栗粉     |
|ごぼうのごまマヨサラダ(15分)                |ごぼう   |好み       |一味      |
|水菜と長いものわさび和え(１５分)               |水菜    |長いも      |わさび     |
|ピーマンのじゃこ炒め(１５分)                 |ピーマン  |雑魚       |顆粒和風だし  |
|なすと豚肉のごまみそ丼(20分)                |なす    |丼        |ピーマン    |
|ピリ辛豆腐ステーキ(30分)                  |豆腐    |しょうが     |白ネギ     |
|白菜とハムの青じそサラダ(20分)               |白菜    |大葉       |ハム      |
|鮭のシャリアピンソースがけ(30分)              |鮭     |にんにく     |ソース     |
|白菜のさっぱりサラダ(15分)                 |白菜    |きゅうり     |サラダ     |
|かぶと肉団子の煮物(30分)                  |しょうが  |鶏ミンチ     |片栗粉     |
|ごぼうの梅おかか煮(４５分)                  |ごぼう   |かつお節     |圧力鍋     |
|切り干し大根とほうれん草の和え物(20分(水に戻す時間は除く))|ほうれん草 |切り干し大根   |熱湯      |
|かぼちゃと揚げの煮物(20分)                 |かぼちゃ  |油揚げ      |揚げ      |
|さつまいものレモン煮(30分)                 |さつまいも |レモン汁     |レモン     |
|菜の花の辛子和え(15分)                   |菜の花   |練りからし    |長さ      |
|かぼちゃとこんにゃくの煮物(30分)              |こんにゃく |かぼちゃ     |熱湯      |
|ゆず入り湯豆腐(１時間)                    |豆腐    |春菊       |好み      |
|大根と厚揚げの煮物(６０分)                  |厚揚げ   |大根       |彩り      |
|小松菜ぎょうざ(45分)                    |小松菜   |にんにく     |しょうが    |
|水菜と油揚げの煮びたし(15分)                |油揚げ   |水菜       |食感      |
|ふろふき大根(３０分以上)                   |大根    |味噌       |いりごま    |
|春菊の白和え(１５分)                     |春菊    |豆腐       |白和え     |
|なすのホイル焼き(15分)                   |なす    |生姜       |ホイル     |
|えびとニラの中華風卵炒め(30分)               |玉ねぎ   |ニラ       |えび      |
|ししゃもの南蛮漬け(３０分)                  |ししゃも  |南蛮漬け     |ピーマン    |
|八宝菜(３０分)                        |豚肉    |白菜       |玉ねぎ     |
|ブロッコリーのわさマヨ和え(１５分)              |ブロッコリー|食感       |わさび     |
|鶏のすき煮(30分)                      |鶏肉    |鶏もも肉     |しいたけ    |
|里芋の梅おかか和え(35分)                  |里芋    |梅干し      |かつお節    |
|ブロッコリーの磯和え(15分)                 |ブロッコリー|出汁醤油     |焼き海苔    |
|焼き鳥丼(20分)                       |鶏肉    |鶏もも肉     |白ネギ     |
|ほうれん草のお浸し(10分)                  |かつお節  |ほうれん草    |10分     |
|さんまの梅しそロール(45分)                 |片栗粉   |さんま      |大葉      |
|きゅうりとトマトの土佐酢和え(３０分)             |トマト   |きゅうり     |かつお節    |
|さばの味噌煮(30分)                     |さば    |味噌       |しょうが    |
|エリンギのバター炒め(15分)                 |エリンギ  |バター      |エリンギ    |
|さつまいもとクリームチーズのサラダ(２0分)          |さつまいも |マヨネーズ    |塩コショウ   |
|薄揚げの納豆キムチ詰め(15分)                |キムチ   |納豆       |長ネギ     |
|鮭の味噌ヨーグルト漬け(１５分(漬け込む時間は除く))     |味噌    |鮭        |ヨーグルト   |
|五目豆(４５分)                        |ごぼう   |れんこん     |こんにゃく   |
|新生姜と水菜の肉巻き(３０分)                 |新生姜   |水菜       |肉       |
|小松菜とツナの和え物(１５分)                 |小松菜   |ツナ       |水気      |
|手羽中と大根の煮物(４５分)                  |大根    |手羽中      |弱火      |
|手羽先の照り焼き(60分)                   |表面    |手羽先      |にんにく    |
|ほうれん草の梅和え(15分)                  |ほうれん草 |梅        |梅干し     |
|なめこおろし(１５分)                     |なめこ   |大葉       |かつお節    |
|簡単タンドリーチキン(１時間以上)               |1時間   |塩コショウ    |タンドリーチキン|
|あさりの酒蒸し(15分)                    |あさり   |にんにく     |みじん切り   |
|ピーマンの肉詰め(３０分)                   |玉ねぎ   |ピーマン     |肉       |
|ちくわの磯辺揚げ(15分)                   |竹輪    |青のり      |衣       |
|長いもの梅和え(10分)                    |長いも   |かつお節     |梅干し     |
|水菜とアボカドのサラダ(１５分)                |アボカド  |水菜       |豆腐      |
|酢鶏(20分)                         |鶏肉    |鶏がらスープの素 |一口      |
|鯛の西京焼き(１５分(漬け込む時間は除く))          |鯛     |冷蔵庫      |魚       |
|きゅうりの塩昆布和え(10分)                 |きゅうり  |塩昆布      |乱切り     |
|なすの煮びたし(20分)                    |なす    |しょうが     |作り方     |
|ごぼうと人参の肉巻き(30分)                 |ごぼう   |肉        |にんにく    |
|大根・里芋・イカの煮物(40分)                |イカ    |大根       |里芋      |
|回鍋肉(30分)                        |豚肉    |にんにく     |片栗粉     |
|ほうれん草と干しえびのゴマ和え(１５分)            |ほうれん草 |干しエビ     |干しえび    |
|里芋のそぼろ煮(３０分)                    |里芋    |片栗粉      |鶏ミンチ    |
|三度豆と人参のおかか和え(１０分)               |三度豆   |湯        |出汁醤油    |
|中華丼(30分)                        |チンゲン菜 |しめじ      |豚肉      |
|きゅうりとたこの酢の物(20分)                |きゅうり  |たこ       |わかめ     |
|新玉ねぎのコンソメ煮込み(45分)               |片栗粉   |鶏ミンチ     |新玉ねぎ    |
|れんこんのきんぴら(１５分)                  |れんこん  |いりごま     |中火      |
|野菜たっぷり牛丼(20分)                   |玉ねぎ   |ニラ       |しめじ     |
|ホタテとチンゲン菜のクリーム煮(２０分)            |片栗粉   |にんにく     |チンゲン菜   |
|ほうれん草とごぼうの白和え(60分)              |ごぼう   |豆腐       |ほうれん草   |
|さんまの蒲焼き(３０分)                    |さんま   |ごま       |大葉      |
|ひじきの炒め煮(６０分)                    |ひじき   |油揚げ      |大豆      |
|オクラの納豆和え(１０分)                   |かつお節  |オクラ      |納豆      |
|じゃこのサラダ(１０分)                    |縮緬雑魚  |貝割れ大根    |水菜      |
|里芋のホットサラダ(45分)                  |里芋    |ほうれん草    |ベーコン    |
|かぼちゃのサラダ(１５分)                   |かぼちゃ  |ヨーグルト    |きゅうり    |
|豆腐のきのこあんかけ(１０分)                 |豆腐    |しめじ      |えのき     |
|春巻き(60分)                        |しょうが  |春雨       |ニラ      |
|れんこんのはさみ焼き(３０分)                 |れんこん  |しょうが     |鶏ミンチ    |
|高野豆腐の含め煮(30分)                   |高野豆腐  |竹串       |水気      |
|豚ミンチと白菜の炒め物(15分)                |春雨    |白菜       |にんにく    |
|いわしのさっぱり煮(４５分)                  |いわし   |しょうが     |長ネギ     |
|れんこんのカレー炒め(１５分)                 |れんこん  |OLIVE OIL|カレー粉    |
|ささみの中華風サラダ(25分)                 |ささみ   |もやし      |きゅうり    |
|茄子と豚肉のピリ辛味噌炒め(30分)              |豚肉    |茄子       |豆板醤     |
|ささみのから揚げ(30分)                   |ささみ   |にんにく     |しょうが    |


## アイデア募集

このツールを使ってどんなことがしたいですか？
ニーズがあれば、今後のアップデートで対応するかもしれません。
コメントお待ちしております。