はじめに
さてさて、Advent Calendarもひとしきり盛り上がり、個人的にもVIPとか株AIとかバズったし楽しめた1ヶ月でした。全然バズらなかったけど、本当は社員2vecが一番気に入ってるんだけどね。仕事も収まったので、一人ハイボールを飲みながら次のネタを考えつつ、記事を書いています。
いつもは機械学習とかコンピュータビジョンを中心に活動しているけど、たまにはこういったプログラミングを始めたときの純粋なノリで、好きなものを作るのは良いものだ。
・
・
・
そんな綺麗にはAdvent Calendarを終わらせない、最後に禍根を残すスタイルで行ってみようと思います。
Advent Calenarでは「いいね」の順位が付いており、やはり上位の企業は嬉しいものだし目立つもの。でも、皆思わない?
「ていうか、自分でいいね押し合ってない?」
本日は、そんな「いいね」押し合いをしている会社を探しに行ってみようと思います。悪ノリの記事なので、気分を害された方は、この辺でページを閉じることをオススメします。
やってみよう!
会社情報の抽出
Qiita APIで取ってくることは出来ないようなので、スクレイピングで取ってきます。アドベントカレンダーに参加している企業は下記のように取ってこれるみたい。
# アドベントカレンダーに参加している会社リストの取得
ret = requests.get('https://qiita.com/advent-calendar/2019/categories/company')
soup = bs4.BeautifulSoup(ret.text, "html.parser")
companies = soup.find_all("a", class_="ac-Item_name")
companies = [{'name': c.text.strip(), 'href': c['href']} for c in companies]
次に企業内でQiita向けに書いた記事リストを取ってきます。外部向けに記事を書いている場合はユーザIDのみを保存します。
ret = requests.get('https://qiita.com' + company['href'])
soup = bs4.BeautifulSoup(ret.text, "html.parser")
contents = soup.find_all("div", class_="adventCalendarItem")
data = []
for content in contents:
d = {}
author = content.find("a", class_='adventCalendarItem_author')
user_name = author['href'][1:]
d['user'] = user_name
entry = content.find("div", class_="adventCalendarItem_entry")
if entry is not None:
item = entry.find('a')
if item is not None and 'https://qiita.com' in item['href']:
d['href'] = item['href']
d['title'] = item.text.strip()
data.append(d)
target_list.append({'name': company['name'], 'items': data})
いいねの抽出
Qiita APIを使って「いいね」をしているユーザを取ってこよう。最初に記事の総いいね数を取ってきて、その上でページを指定して「いいね」をしているユーザIDを抽出します。TOKENは右上にある自分のアイコンをクリック、設定➝アプリケーション➝個人用アクセストークンで発行できます。
def get_likes(content_id, token):
headers = {'Authorization': f'Bearer {token}'}
per_page = 100
ret = requests.get(f'https://qiita.com/api/v2/items/{content_id}', headers=headers)
if ret.status_code != 200:
print(f'https://qiita.com/api/v2/items/{content_id}')
raise requests.ConnectionError("Expected status code 200, but got {}".format(ret.status_code))
likes_count = json.loads(ret.content.decode('utf-8'))['likes_count']
nb_pages = math.ceil(likes_count / per_page)
#time.sleep(3)
likes = []
for p in range(nb_pages):
params = {'page': 1 + p, 'per_page': per_page}
ret = requests.get(f'https://qiita.com/api/v2/items/{content_id}/likes', params=params, headers=headers)
if ret.status_code != 200:
raise requests.ConnectionError("Expected status code 200, but got {}".format(ret.status_code))
likes.extend(json.loads(ret.content.decode('utf-8')))
#time.sleep(3)
return likes
ここで、問題発生。Qiita APIはなんと1時間に1000回しか呼び出せないらしい。なのでスクレイピングで取ってくることにする。URLを入力して、各ページから「いいね」をしているユーザを取ってきます。
def get_likes_direct(url):
page = 1
likes = []
while True:
ret = requests.get(f'{url}/likers?page={page}')
soup = bs4.BeautifulSoup(ret.text, "html.parser")
users = soup.find_all("li", class_="GridList__user")
local_likes = []
if users is not None:
local_likes = [u.find('h4', class_='UserInfo__name').find('a')['href'][1:] for u in users]
if len(local_likes) == 0:
break
local_likes = [{'user': {'id': ll}} for ll in local_likes]
likes.extend(local_likes)
page += 1
return likes
順位の計算
さて、ここが一番悩んだ所ですが、悩んだ結果難しいこと考えずに、以下のようにしました。
- 組織内の記事に「いいね」をつけたユーザのうち、1/4以上の記事に「いいね」を付けた人を抽出
- 組織内のQiita記事数が5本を超えている場合のみを対象とする
例えば、組織の記事が8本あり、うち2本を超えて「いいね」を付けたら、一旦は組織内「いいね」とみなすことにしました。厳密には、その人が別組織でどの位「いいね」を付けてるかも見ないといけないんだけど、1/4の割合で記事に「いいね」を付けまくっている人は、早々いないので、まずはこの条件としました。
結果発表!
すみません、皆さん興味あるかと思いますが、流石に公表するのは良くないので、ここにコードを置いておくので実施してみて下さい。以下はとても重要な事だけど手を動かす者だけが結果を得られるのです。
なお、ABEJAは内部いいね順位は27位でした。それでは、良いお年を!