はじめに
エンジニアになって半年が経過したので、振り返りのために、今まで投稿してきた記事のテキストデータをスクレイピングで取得して、ワードクラウドを作ってみました。
その際の手順を残したいと思います。
完成形
こんなのができました。
「コンポーネント」とでっかく出ているのは恐らくVue.js「コンポーネント」入門でコンポーネントコンポーネント言いまくってるからですね。後はherokuとかDockerとかFlaskとか、そういえば記事書いたなぁというものがちょこちょこあり、懐かしい気持ちになりました。「変更」や「追加」といった汎用的な言葉が多く出ているので、お好みによってストップワード設定しても良いかもですね。
ちなみに、自分のはてなブログの方も同様にスクレイピングしてワードクラウドを作ってみました。こちらはTwitterのヘッダー画像にしているので、ぜひ見てみてください。(全然違うこと書いてあって面白いですね。)
環境
- Mac
- Python3
を使って作成していきます。
大まかな手順
- スクレイピングしてテキストデータを取得
- 形態素解析器(MeCab)を通して単語に分割する
- ワードクラウドを作成する
という手順で進めます。
スクレイピング
Qiita APIのget itemsを使用します。
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形式で返ってきます。
[
{
"rendered_body": "<h1>Example1</h1>",
(略)
"title": "Example title 1",
(略)
},
{
"rendered_body": "<h1>Example2</h1>",
(略)
"title": "Example title 2",
(略)
},
・・・
]
この中からrendered_body
とtitle
を抜き出してワードクラウドに利用します。
上記のコードをPythonのコードに落とし込むと、このようになります。
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に関してはこちらの記事が詳しくて良いです。)
$ pip install requests
$ pip install json
$ pip install beautifulsoup4
下から3行目のsoup.find_all(["p","li","h1","h2","h3","h4","table"])
で、読み取るhtmlタグを指定しています。当初は全テキストを読み取ろうとしたのですが、埋め込んだコードも含まれてしまい、結果作成したワードクラウドがforとかifとかコードでよく出てくるワードばっかになってしまったので、テキスト部だけを抜き出すべくこのような指定をしています。この辺はお好みで調整してください。
形態素解析
スクレイピングした日本語テキストは英語と違って単語に分割されてないため、そのままワードクラウド生成ライブラリに突っ込んでもうまくいきません。そのため、形態素解析を行って単語に分割(分かち書き)します。今回はMecabという形態素解析器を使用します。こちらの記事をかなり参考にさせていただきました。
まずMecabの導入に必要なライブラリをインストールします。
brew install mecab mecab-ipadic git curl xz
次に、Mecab本体の導入をします。
brew install mecab mecab-ipadic
terminalでmecab
と打って、文章を入力すると、形態素解析を実行してくれます。(終了はControl+C)
$ mecab
すもももももももものうち
すもも 名詞,一般,*,*,*,*,すもも,スモモ,スモモ
も 助詞,係助詞,*,*,*,*,も,モ,モ
もも 名詞,一般,*,*,*,*,もも,モモ,モモ
も 助詞,係助詞,*,*,*,*,も,モ,モ
もも 名詞,一般,*,*,*,*,もも,モモ,モモ
の 助詞,連体化,*,*,*,*,の,ノ,ノ
うち 名詞,非自立,副詞可能,*,*,*,うち,ウチ,ウチ
EOS
これで準備は完了です。後はPythonで形態素解析を実行するコードを書きましょう。Pythonのコードはこちらの記事を参考にさせていただきました。
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
しておきましょう。
$ pip install mecab-python3
下から5行目のif word_type in ["形容詞","名詞"]:
で、outputに含める単語を「形容詞」と「名詞」に限定しています。副詞や動詞を含めたければこの配列に追加することで対応できます。
ワードクラウドの作成
前工程まででスクレイピングしたテキストを単語に分割することができたので、最後にワードクラウドのライブラリに突っ込んで完成させましょう。
まずワードクラウドライブラリのREADMEに従って、pip install
しましょう。
また、画面描画用のライブラリmatplotlibもインストールしましょう。
$ pip install wordcloud
$ pip install matplotlib
続いて、以下のようにPythonのコードを書きます。Pythonのコードはこちらの記事を参考にさせていただきました。
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 =
以降でストップワードの指定をしています。ここで記載された単語はワードクラウド上に表示されなくなります。「もの」や「こと」など意味が無いけど頻度が多くてデカデカと表示されてしまう単語はここで指定してあげましょう。
最後にこれらをまとめてスクレイピング〜ワードクラウドの生成までを一括処理するファイルを作成しましょう。
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を実行すると、ログにこんな感じのメッセージが吐き出された後、ワードクラウドの画面が開きます。
scrape GoFのデザインパターンを勉強する
scrape DDDの頻出用語をなんとなく理解する
(中略)
scrape AtCoder400点アルゴリズムまとめ(Java編)
scrape AWS ソリューションアーキテクト-アソシエイトを取りたい
start mecab analysis
end mecab analysis
start create wordcloud
end create wordcloud
now showing
実際はここから品詞やストップワードの調整をして、完成になると思います。楽しいのでぜひ色々といじってみてください。
おわりに
ワードクラウド作ってみるとどういうアウトプットをしてきたのか視覚的に分かるので良いですね。スクレイピングする対象をはてなブログとかTwitterとかに変えてみてもまた違った結果が出てきて面白いと思います。