自分のQiita記事をスクレイピングしてワードクラウドを作る

# はじめに
エンジニアになって半年が経過したので、振り返りのために、今まで投稿してきた記事のテキストデータをスクレイピングで取得して、ワードクラウドを作ってみました。
その際の手順を残したいと思います。

# 完成形
こんなのができました。
<img width="900" alt="スクリーンショット 2020-05-08 10.43.08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214279/c23a602b-289b-eccb-b5da-fc994d8ffa89.png">
「コンポーネント」とでっかく出ているのは恐らく[Vue.js「コンポーネント」入門](https://qiita.com/kiyokiyo_kzsby/items/980c1dc45e00d2d3cbb4)でコンポーネントコンポーネント言いまくってるからですね。後はherokuとかDockerとかFlaskとか、そういえば記事書いたなぁというものがちょこちょこあり、懐かしい気持ちになりました。「変更」や「追加」といった汎用的な言葉が多く出ているので、お好みによってストップワード設定しても良いかもですね。
ちなみに、[自分のはてなブログ](https://kiyokiyo-kzsby.hatenablog.com/)の方も同様にスクレイピングしてワードクラウドを作ってみました。こちらは[Twitter](https://twitter.com/kiyokiyo_kzsby)のヘッダー画像にしているので、ぜひ見てみてください。（全然違うこと書いてあって面白いですね。）

# 環境

- Mac
- Python3

を使って作成していきます。

# 大まかな手順

1. スクレイピングしてテキストデータを取得
2. 形態素解析器（MeCab）を通して単語に分割する
3. ワードクラウドを作成する

という手順で進めます。

# スクレイピング
[Qiita API](https://qiita.com/api/v2/docs)の[get items](https://qiita.com/api/v2/docs#get-apiv2items)を使用します。
RequestURLの構文は以下の通りです。

```
https://qiita.com/api/v2/items?page={{ページ番号}}&per_page={{1ページあたりの記事数}}&query=user%3A{{ユーザID}}
```

例えば、私（kiyokiyo_kzsby）の記事を100記事取得したい場合は、以下のリクエストを送ればOKです。

```
https://qiita.com/api/v2/items?page=1&per_page=100&query=user%3Akiyokiyo_kzsby
```

レスポンスはJSON形式で返ってきます。

```json
[
  {
    "rendered_body": "<h1>Example1</h1>",
    (略)
    "title": "Example title 1",
    (略)
  },
  {
    "rendered_body": "<h1>Example2</h1>",
    (略)
    "title": "Example title 2",
    (略)
  },
  ・・・
]
```

この中から`rendered_body`と`title`を抜き出してワードクラウドに利用します。

上記のコードをPythonのコードに落とし込むと、このようになります。

```python:qiita_scraper.py
import requests
import json
from bs4 import BeautifulSoup

def scrape_all(user_id):
    text = ""
    r = requests.get("https://qiita.com/api/v2/items?page=1&per_page=100&query=user%3A" + user_id)
    json_list = json.loads(r.text)
    for article in json_list:
        print("scrape " + article["title"])
        text += article["title"]
        content = article["rendered_body"]
        soup = BeautifulSoup(content, "html.parser")
        for valid_tag in soup.find_all(["p","li","h1","h2","h3","h4","table"]):
            text += valid_tag.text
    return text
```

`requests`はHTTPリクエストを実行するライブラリ、`json`はJSONを取り扱うライブラリ、`BeautifulSoup`はhtmlを取り扱うライブラリです。それぞれ`pip install`で入れておきましょう。（BeautifulSoupに関しては[こちらの記事](https://qiita.com/itkr/items/513318a9b5b92bd56185)が詳しくて良いです。）

```terminal
$ pip install requests
$ pip install json
$ pip install beautifulsoup4
```

下から3行目の`soup.find_all(["p","li","h1","h2","h3","h4","table"])`で、読み取るhtmlタグを指定しています。当初は全テキストを読み取ろうとしたのですが、埋め込んだコードも含まれてしまい、結果作成したワードクラウドがforとかifとかコードでよく出てくるワードばっかになってしまったので、テキスト部だけを抜き出すべくこのような指定をしています。この辺はお好みで調整してください。

# 形態素解析
スクレイピングした日本語テキストは英語と違って単語に分割されてないため、そのままワードクラウド生成ライブラリに突っ込んでもうまくいきません。そのため、形態素解析を行って単語に分割（分かち書き）します。今回はMecabという形態素解析器を使用します。[こちらの記事](https://qiita.com/Sak1361/items/47e9ec464ccc770cd65c)をかなり参考にさせていただきました。

まずMecabの導入に必要なライブラリをインストールします。

```terminal
brew install mecab mecab-ipadic git curl xz
```

次に、Mecab本体の導入をします。

```terminal
brew install mecab mecab-ipadic
```

terminalで`mecab`と打って、文章を入力すると、形態素解析を実行してくれます。（終了はControl+C）

```terminal
$ mecab
すもももももももものうち
すもも	名詞,一般,*,*,*,*,すもも,スモモ,スモモ
も	助詞,係助詞,*,*,*,*,も,モ,モ
もも	名詞,一般,*,*,*,*,もも,モモ,モモ
も	助詞,係助詞,*,*,*,*,も,モ,モ
もも	名詞,一般,*,*,*,*,もも,モモ,モモ
の	助詞,連体化,*,*,*,*,の,ノ,ノ
うち	名詞,非自立,副詞可能,*,*,*,うち,ウチ,ウチ
EOS
```

これで準備は完了です。後はPythonで形態素解析を実行するコードを書きましょう。Pythonのコードは[こちらの記事](https://qiita.com/kenmatsu4/items/02034e5688cc186f224b)を参考にさせていただきました。

```mecab.py
import MeCab as mc

def mecab_analysis(text):
    print("start mecab analysis")
    t = mc.Tagger('-Ochasen')
    node = t.parseToNode(text)
    output = []
    while(node):
        if node.surface != "":
            word_type = node.feature.split(",")[0]
            if word_type in ["形容詞","名詞"]:
                output.append(node.surface)
        node = node.next
    print("end mecab analysis")
    return output
```

MeCabのライブラリを使用するので、`pip install`しておきましょう。

```terminal
$ pip install mecab-python3
```

下から5行目の`if word_type in ["形容詞","名詞"]:`で、outputに含める単語を「形容詞」と「名詞」に限定しています。副詞や動詞を含めたければこの配列に追加することで対応できます。

# ワードクラウドの作成
前工程まででスクレイピングしたテキストを単語に分割することができたので、最後にワードクラウドのライブラリに突っ込んで完成させましょう。
まず[ワードクラウドライブラリのREADME](https://github.com/amueller/word_cloud/blob/master/README.md)に従って、`pip install`しましょう。
また、画面描画用のライブラリmatplotlibもインストールしましょう。

```terminal
$ pip install wordcloud
$ pip install matplotlib
```

続いて、以下のようにPythonのコードを書きます。Pythonのコードは[こちらの記事](https://qiita.com/kenmatsu4/items/9b6ac74f831443d29074)を参考にさせていただきました。

```word_cloud.py
import matplotlib.pyplot as plt
from wordcloud import WordCloud

def create_wordcloud(text):
    print("start create wordcloud")

    # 環境に合わせてフォントのパスを指定する。
    fpath = "/System/Library/Fonts/ヒラギノ明朝 ProN.ttc"

    # ストップワードの設定
    stop_words = [ u'てる', u'いる', u'なる', u'れる', u'する', u'ある', u'こと', u'これ', u'さん', u'して', \
             u'くれる', u'やる', u'くださる', u'そう', u'せる', u'した',  u'思う',  \
             u'それ', u'ここ', u'ちゃん', u'くん', u'', u'て',u'に',u'を',u'は',u'の', u'が', u'と', u'た', u'し', u'で', \
             u'ない', u'も', u'な', u'い', u'か', u'ので', u'よう', u'', u'もの', u'今週', u'まとめ',u'ため', \
             u'指定', u'場合', u'以下', u'作成', u'よう', u'部分', u'ファイル', u'利用', u'使用']

    wordcloud = WordCloud(background_color="white",font_path=fpath, width=800, height=500, \
                          stopwords=set(stop_words)).generate(text)
    print("end create wordcloud")

    print("now showing")
    plt.figure(figsize=(15,12))
    plt.imshow(wordcloud)
    plt.axis("off")
    plt.show()
```

上から6行目の`fpath = "/System/Library/Fonts/ヒラギノ明朝 ProN.ttc"`の部分でフォントのパスを指定しています。使用しているPCによってパスやフォント名が違う可能性があるので、適宜調整してください。
上から8行目の`stop_words =`以降でストップワードの指定をしています。ここで記載された単語はワードクラウド上に表示されなくなります。「もの」や「こと」など意味が無いけど頻度が多くてデカデカと表示されてしまう単語はここで指定してあげましょう。

最後にこれらをまとめてスクレイピング〜ワードクラウドの生成までを一括処理するファイルを作成しましょう。

```main.py
from qiita_scraper import scrape_all
from mecab import mecab_analysis
from word_cloud import create_wordcloud

text = scrape_all("kiyokiyo_kzsby")
wordlist = mecab_analysis(text)
create_wordcloud(" ".join(wordlist))
```

4行目の`scrape_all`の引数にQiitaのuser_idを渡してあげています。ここを変えてあげることで別のユーザのワードクラウドを作成することもできます。

main.pyを実行すると、ログにこんな感じのメッセージが吐き出された後、ワードクラウドの画面が開きます。

```terminal
scrape GoFのデザインパターンを勉強する
scrape DDDの頻出用語をなんとなく理解する
(中略)
scrape AtCoder400点アルゴリズムまとめ(Java編)
scrape AWS ソリューションアーキテクト-アソシエイトを取りたい
start mecab analysis
end mecab analysis
start create wordcloud
end create wordcloud
now showing
```

はいどーん！！
<img width="900" alt="スクリーンショット 2020-05-08 10.43.08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214279/c23a602b-289b-eccb-b5da-fc994d8ffa89.png">

実際はここから品詞やストップワードの調整をして、完成になると思います。楽しいのでぜひ色々といじってみてください。

# おわりに
ワードクラウド作ってみるとどういうアウトプットをしてきたのか視覚的に分かるので良いですね。スクレイピングする対象をはてなブログとかTwitterとかに変えてみてもまた違った結果が出てきて面白いと思います。