📊
AtCoderの自分のパフォーマンスを円グラフにする
きっかけ
精進グラフのようなグラフ(そしてAtCoderのマイプロフィールにはないグラフ)を作ってみたい、と思い作りました。また、スクレイピングの練習になれば、と思い作りました。
実行環境
AnacondaのSpyder Pythonのバージョンは3.8.3 IPythonのバージョンは 7.16.1
MacOS Catalina バージョン10.15.6
注意点
ウェブスクレイピングはいくつかのウェブサイトの規約に反する可能性がある。 例えば、短文投稿サイトのツイッターではサービス利用規約によって明示的に禁止されており[3]、APIの利用が必須となる。
(Wikipedia WEBスクレイピングより抜粋)
例えば、Amazonは利用規約にスクレイピングを禁止していることを書いている。スクレイピングによる大量アクセスで、サーバに負荷をかけてしまうからである。岡崎市立中央図書館事件など事件に発達することがある。
Pythonで実装
テンプレート
atcoder_per.py
import requests
from bs4 import BeautifulSoup
def main(username):#usernameにあなたのユーザーネームを入れる
site = requests.get('https://atcoder.jp/users/'+username+'/history/json')
data = BeautifulSoup(site.text, 'html.parser')
#スクレイピング
S = str(data.text)
say = ('"Performance":',',"InnerPerformance"')
return search(S,say)
def search(S,say):
'''
----------
S : str
スクレイピングした情報を入れる。
say : tuple
探す言葉
Returns
-------
ans : list
全てのSの中にあるsay[0]とsay[1]の間にある情報を戻り値とする
'''
ans = []
num = 0
l = []
for i in range(len(S)):
try:
if S[i:i+len(say[num])] == say[num]:
if num == 0:
l.append(i+len(say[0]))
else:
l.append(i)
num = (num+1)%2
except:
break
i = 0
for i in range(len(l)//2):
ans.append(S[l[i*2]:l[i*2+1]])
return ans
if __name__ == "__main__":
main("")
円グラフ
main.py
import matplotlib.pyplot as plt
from atcoder_per import main
def types(x):#種類(黒、灰色......赤)
l = list(set([color(i) for i in x]))
d = []
if'black'in l:
d.append('black')
if'gray'in l:
d.append('gray')
if'brown'in l:
d.append('brown')
if'green'in l:
d.append('green')
if'lightblue'in l:
d.append('lightblue')
if'blue'in l:
d.append('blue')
if'yellow'in l:
d.append('yellow')
if'orange'in l:
d.append('orange')
if'red'in l:
d.append('red')
return d
def color(a):#xの色を返す
x = int(a)
if x <= 0:
return "black"
if x < 400:
return "gray"
if x < 800:
return "brown"
if x < 1200:
return "green"
if x < 1600:
return "lightblue"
if x < 2000:
return "blue"
if x < 2400:
return "yellow"
if x < 2800:
return "orange"
return "red"
def colors(x):
l = {"black":0,"gray":0,"brown":0,"green":0,"lightblue":0,"blue":0,"yellow":0,"orange":0,"red":0}
for i in x:
l[color(i)] = l[color(i)]+1
ans = list(l.values())
while True:
try:
del ans[ans.index(0)]
except:
break
return ans
def color_names(a):
x = list(a)
l = [x[i] for i in range(len(x))]
d = {'black': 'k', 'gray': 'lightgrey', 'brown': 'saddlebrown', 'green': 'g', 'lightblue': 'aqua', 'blue': 'b', 'yellow': 'y', 'orange': 'orange', 'red': 'r'}
for i in range(len(x)):
l[i] = d[x[i]]
return l
l = main("")#あなたのユーザーネーム
# Pie chart, where the slices will be ordered and plotted counter-clockwise:
labels = types(l)
sizes = colors(l)
colorlist = color_names(types(l))
fig1, ax1 = plt.subplots()
ax1.pie(sizes, labels=labels, colors = colorlist,autopct='%1.1f%%',
shadow=True, startangle=90)
ax1.axis('equal') # Equal aspect ratio ensures that pie is drawn as a circle.
plt.show()
出来上がるグラフの例
chokudai様
LayCurse様
これだと、Unratedなど(黒)が多くなってしまう、と言う弱点がある。
それが気になる方は、main.pyの73行目を
73行目変更
l = [l[i] for i in range(len(l)) if int(l[i]) > 0]
に変えれば良い。
参考文献
Discussion