Edited at

Pythonを使ってQiitaのランクイン記事から技術のトレンドを追ってみた

Qiitaのウィークリーメールのランキングを見ていたところ、あることを感じました。

"以前に比べて、機械学習の記事のランクインが減ってる"

そこで、Pythonを使って実際にQiitaでランクインした記事からタグを日付毎に集計して、トレンドを追ってみました。


集計対象

2018/06/20-2018/09/26までの、Qiitaのウィークリーメールに掲載された、Top10ランキングに登場した記事に付与されているタグ

本文を形態素解析して単語集計しても良かったですが、まずは簡単な部分からはじめました。


分析手順

まずメールを1枚ずつ、手動でYYYY-mm-dd.htmlといった形式で保存しました。

メールの先頭の部分に"メールをブラウザで開く"というリンクがあったのでそれをクリックして表示されたページを保存しました。

次にjupyter notebook上で以下の文を入力していきました。

%matplotlib inline

from bs4 import BeautifulSoup
from collections import defaultdict
from datetime import datetime
from qiita_v2.client import QiitaClient
import matplotlib.pyplot as plt
import json
import re
import glob

QiitaのAPIを呼ぶため、QiitaClientをimportしています。

Qiita APIに関しては以下のページを参考にしました。

[https://vaaaaaanquish.hatenablog.com/entry/2018/02/26/233805]

事前に

!pip install qiita_v2

とかしておく必要があります。

次にhtmlファイルを開いてランクインした記事からタグを取ってきます。

記事は 


<a href="http://qiita.com/username/items/abdebdakf"


みたいな感じでリンクが貼られているので、.find_all("a", href=re.compile("items"))とやって抽出しています。

データを格納する部分は、本当はpandasのDataFrameの方が良かったと思います。ただ追加方法がよくわからなかったのでdictでお茶を濁しました。:stuck_out_tongue:

# dic = dict()

def read_file(filename, dic, client):
with open(filename) as f:
# ファイル名から日付を取得します
dat = re.match("(.*).html", filename).group(1)
# 日付に対応したdictを生成します
dic[datetime.strptime(dat,"%Y-%m-%d")] = defaultdict(int)
# HTMLを読み込みます
page = BeautifulSoup(f.read(),"lxml")
for p in page.find_all("a", href=re.compile("items")):
print(p["href"])
# URLのitems以下の数値(=itemid)だけを取得します
match = re.match("http://qiita.com/.*/items/(.*)", p["href"])
if match != None:
#print (match.group(1))
#api = "https://qiita.com/api/v2/items/" + match.group(1)
#print(api)
#r = requests.get(api)
# 取得したitemidを使って記事を取得します
r = client.get_item(match.group(1))
j = r.to_json()

# tagを取得して、dictの中に入れます
for tag in j['tags']:
print(tag["name"], end=",")
dic[datetime.strptime(dat,"%Y-%m-%d")][tag["name"]] += 1
print("")
return True

次にカレントディレクトリからhtmlファイルの一覧を取得するコードです。

def read_all():

dic = dict()
file = glob.glob("*.html")
print(file)
client = QiitaClient(config_file = "config.yml")
for f in file:
read_file(f, dic, client)
return dic

config.ymlは以下のような感じで書きます。


config.yml

ACCESS_TOKEN: 123abcde


アクセストークンは https://qiita.com/settings/applications で「個人用アクセストークン」にread権限を付けて発行して、その時表示されたTokenをコピペしてください。

ここまで記入したら、実行します。

dic = read_all()

dic

実行した結果、次の様に出力されました。

result.png

実行結果をcsvに書き出します。

import csv

# dicデータをCSV形式に出力します。
def print_dic(dic):
with open("dic.csv", "w+") as f:
writer = csv.writer(f, lineterminator='\n') # 改行コード(\n)を指定しておく
for dat in dic:
for tag in dic[dat]:
writer.writerow((dat.strftime("%Y-%m-%d"), tag, dic[dat][tag]))
return

print_dic(dic)

保存されたcsvファイルをダウンロードして、結果を見てみました。以下は日付ごとに件数の多かった順です(途中一部省略しています)

2018-06-20.png

2018-06-27.png

2018-07-04.png

2018-07-11.png

2018-07-18.png

2018-07-25.png

2018-08-29.png

2018-09-12.png

2018-09-19.png

2018-09-26.png

ざっと見た感想ですが、7月だけやけに機械学習やDeepLearningが盛り上がっています。あとJavaScriptは全体的に多いです。

週・タグごとに多かった順にも並べてみました。

count.png

JavaScriptとPythonが多いです。7/25だけ機械学習が盛り上がっています。

"Python", "機械学習", "データ分析", "JavaScript"で週ごとの件数をPlotしてみました。本当は折れ線グラフの方がいいんでしょうが、dictを使ったせいか変な線になったので点にしました。OrderedDictでも使えばよかったのでしょうか。

# タグごとに出力

def plot_by_tag(tag):
y = []
for dat in dic.keys():
if tag in dic[dat]:
y.append(dic[dat][tag])
else:
y.append(0)
plt.plot(list(dic.keys()), y, 'o', label = tag)

# タグの検出
def find_tags(dic):
tags = []
for dat in dic.keys():
for le in dic[dat].keys():
tags.append(le)
return tags

# tags = find_tags(dic)
tags = ["Python", "機械学習", "データ分析", "JavaScript"]
for t in tags:
plot_by_tag(t)
plt.legend()

結果:

tag_plot.png

ちょっと見づらいですが7月にPython/機械学習が上がっていて、ほかはJavaScriptが多いことがわかります。

ちなみにmatplotlibは素の状態では日本語が化けます。以下のサイトを参考にして日本語対応させました。

https://qiita.com/tatsuya-takahashi/items/13bfc01d05282c07e3f0


結論

Qiitaの中では機械学習ブームが終わったのかと思いましたが、単に7月だけ盛り上がっていただけでした。

ランクインしてない記事の動向なんかも、APIから記事一覧を取得して記事を開いてタグを抽出すればよさそうです。ただしAPIが認証ありで1000回/h(無しだと60回/h)なのでウェイトを入れたり一工夫必要そうです。


2018/10/03 追記

10/03分もタグを集計してみました。Javascript, Pythonが少しだけ多いです。


        {'AWS': 3,

'AWSArtifact': 1,
'C#': 1,
'CSV': 1,
'CUI': 1,
'CleanArchitecture': 1,
'DeepLearning': 1,
'EC2': 1,
'Emacs': 1,
'Excel': 1,
'GUI': 1,
'GitHub': 1,
'Go': 2,
'GoogleCloudPlatform': 1,
'GoogleColaboratory': 1,
'Instagram': 1,
'JavaScript': 3,
'LINEmessagingAPI': 1,
'Linux': 1,
'Mac': 1,
'MySQL': 1,
'Node.js': 1,
'PDF': 1,
'PostgreSQL': 1,
'PyConJP': 1,
'Python': 4,
'Redis': 1,
'SQL': 1,
'SSH': 1,
'SublimeText3': 1,
'TPU': 1,
'UI': 1,
'UIデザイン': 1,
'UX': 1,
'UXデザイン関連': 1,
'VSCode': 2,
'Visual': 1,
'WebAPI': 1,
'Webサービス': 1,
'docker': 1,
'gocui': 1,
'golang': 1,
'ikea': 1,
'map': 1,
'moffers': 1,
'motd': 1,
'oracle': 1,
'pandas': 1,
'まとめ': 1,
'アラサー': 1,
'アーキテクチャ': 1,
'オブジェクト指向': 3,
'カンファレンス・勉強会メモ': 1,
'キャリア': 1,
'コメント': 1,
'位置情報': 1,
'契約': 1,
'未経験エンジニア': 1,
'機械学習': 1,
'環境構築': 1,
'要件定義': 1,
'設計': 1,
'転職': 1,
'転職ドラフト': 1,
'開発プロセス': 1,
'非機能要件': 1})}