Qiitaの人気記事を徹底解析！タグといいね数の相関を探る

**よく読まれているQiitaのトピックって何…**


このようなことを思ったそこのあなたのために、人気の記事をQiita APIを使いながら徹底解析していこうと思います。

# はじめに

この記事は、株式会社スピードリンクジャパン Advent Calendar 2024 の7日目の記事です。


https://qiita.com/advent-calendar/2024/slj


# 環境
- mac
- python

pythonの環境構築に関してはこちらが参考になります。

https://prog-8.com/docs/python-env
# 手始めに
現在どれだけの記事が投稿されているのか取得してみましょう。
ファイルを作成し、以下のコードを入れます。
```python:qiita.py
import requests

url = 'https://qiita.com/api/v2/items'
params = {
    'page'     : 1,
    'per_page' : 100
}
headers = {
    'content-type'  : 'application/json',
    'charset'       : 'utf-8',
    'Authorization': 'Bearer 発行したアクセストークン' # ここはなくても動きます
}

# 記事のトータル数取得
r = requests.get(url, params=params,  headers=headers)
if r.status_code == 200:
    total_count = r.headers.get('Total-Count')  # ヘッダーから Total-Count を取得
    print(f"Total-Count: {total_count}")
else:
    print(f"Error: {r.status_code}, {r.text}")
```
ターミナルでpythonを実行します。
```terminal
% python qiita.py
Total-Count: 1008368
```


#### 2024.12.05現在の記事のトータルの投稿数は1008368件だそうです。
さらに分析を進めていきます。

# どんなタグの記事が多いのか
次はどんなタグの記事が多いのか取得してみたいと思います。
100万記事も取得したら時間がかかりそうなので、試しに20ページ分取得することにしました。
また、上位10件をグラフ化しました。
<details><summary>サンプルコード</summary>

```python:qiita.py
import requests
import matplotlib.pyplot as plt
from collections import Counter
import time

# Qiita API設定
ACCESS_TOKEN = "発行したアクセストークン"
HEADERS = {
    "Authorization": f"Bearer {ACCESS_TOKEN}"
}

BASE_URL = "https://qiita.com/api/v2/items"
NUM_PAGES_TO_FETCH = 20  # 取得するページ数
PER_PAGE = 100  # 1ページあたりの記事数

# タグを収集
def fetch_tags(num_pages=NUM_PAGES_TO_FETCH, per_page=PER_PAGE):
    tags = []
    for page in range(1, num_pages + 1):
        params = {"page": page, "per_page": per_page}
        response = requests.get(BASE_URL, headers=HEADERS, params=params)
        if response.status_code == 200:
            items = response.json()
            for item in items:
                # 記事に付与されているタグを取得
                tags.extend(tag["name"] for tag in item["tags"])
            print(f"Fetched page {page} with {len(items)} articles.")
        else:
            print(f"Error fetching page {page}: {response.status_code}")
            break
        time.sleep(1)  # レートリミット対策
    return tags

# 分布の描画
def plot_tag_distribution(tag_counts, top_n=10):
    # 上位N件を表示
    most_common_tags = tag_counts.most_common(top_n)
    tags = [tag for tag, count in most_common_tags]
    counts = [count for tag, count in most_common_tags]

    # 棒グラフを作成
    plt.figure(figsize=(10, 6))
    plt.bar(tags, counts, color="skyblue")
    plt.xlabel("Tags (Categories)")
    plt.ylabel("Number of Articles")
    plt.title(f"Top {top_n} Tags by Number of Articles")
    plt.xticks(rotation=45, ha="right")
    plt.grid(axis="y", linestyle="--", alpha=0.7)
    plt.tight_layout()
    plt.show()

# メイン処理
if __name__ == "__main__":
    print("Fetching tags from articles...")
    tags = fetch_tags()

    print(f"Total tags fetched: {len(tags)}")
    tag_counts = Counter(tags)

    print("Plotting tag distribution...")
    plot_tag_distribution(tag_counts)
```
</details>


ターミナルでpythonを実行します。
```terminal
% python qiita.py
```

![Figure_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524128/a3eafaf0-5c2d-8f37-9ba6-9b2c6005a3cd.png)

2番目に多いものは文字化けしてしまって見えずでした…
以下が週間ランキングでした。
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524128/d911606c-dca9-f0d9-0341-0c0b6e379296.png">

#### アドベントカレンダーに関するタグが多くなってきているようです。

# いいね数とタグの相関関係
今度はどんなタグにいいねが多いのかを分析してみたいと思います。
30ページ分を取得し、上位20件のグラフを出してみます。
先ほどの反省を生かし、日本語が表示できるようにします。
<details><summary>サンプルコード</summary>

```python:qiita.py
import requests
import matplotlib.pyplot as plt
from collections import Counter
import time
from matplotlib import font_manager

# Qiita API設定
ACCESS_TOKEN = "発行したアクセストークン"
HEADERS = {
    "Authorization": f"Bearer {ACCESS_TOKEN}"
}

BASE_URL = "https://qiita.com/api/v2/items"
NUM_PAGES_TO_FETCH = 30  # 取得するページ数
PER_PAGE = 100  # 1ページあたりの記事数

# 日本語フォントの設定 (Macの場合)
font_path = '/Library/Fonts/Arial Unicode.ttf'  # Macの日本語フォント
# Windowsの場合は次の行を使います
# font_path = 'C:/Windows/Fonts/msゴシック.ttc'  # Windowsの日本語フォント

prop = font_manager.FontProperties(fname=font_path)

# 日本語フォントを設定
plt.rcParams['font.family'] = prop.get_name()

# 記事とタグ、いいね数を収集
def fetch_article_data(num_pages=NUM_PAGES_TO_FETCH, per_page=PER_PAGE):
    articles_data = []
    for page in range(1, num_pages + 1):
        params = {"page": page, "per_page": per_page}
        response = requests.get(BASE_URL, headers=HEADERS, params=params)
        if response.status_code == 200:
            items = response.json()
            for item in items:
                # 記事のいいね数とタグを取得
                likes_count = item["likes_count"]
                tags = [tag["name"] for tag in item["tags"]]
                articles_data.append((likes_count, tags))
            print(f"Fetched page {page} with {len(items)} articles.")
        else:
            print(f"Error fetching page {page}: {response.status_code}")
            break
        time.sleep(1)  # レートリミット対策
    return articles_data

# タグごとのいいね数の平均を計算
def calculate_avg_likes_by_tag(articles_data):
    tag_likes = Counter()
    tag_count = Counter()

    for likes_count, tags in articles_data:
        for tag in tags:
            tag_likes[tag] += likes_count
            tag_count[tag] += 1

    avg_likes_by_tag = {tag: tag_likes[tag] / tag_count[tag] for tag in tag_likes}
    return avg_likes_by_tag

# 可視化（タグごとの平均いいね数）
def plot_avg_likes_by_tag(avg_likes_by_tag, top_n=20):
    # 上位N件を表示
    sorted_tags = sorted(avg_likes_by_tag.items(), key=lambda x: x[1], reverse=True)[:top_n]
    tags = [tag for tag, avg_likes in sorted_tags]
    avg_likes = [avg_likes for tag, avg_likes in sorted_tags]

    # 棒グラフを作成
    plt.figure(figsize=(10, 6))
    plt.bar(tags, avg_likes, color="skyblue")
    plt.xlabel("タグ名")  # 日本語
    plt.ylabel("平均いいね数")  # 日本語
    plt.title(f"上位{top_n}タグの平均いいね数")  # 日本語
    plt.xticks(rotation=45, ha="right")
    plt.grid(axis="y", linestyle="--", alpha=0.7)
    plt.tight_layout()
    plt.show()

# メイン処理
if __name__ == "__main__":
    print("Fetching article data...")
    articles_data = fetch_article_data()

    print(f"Total articles fetched: {len(articles_data)}")
    
    # タグごとのいいね数の平均を計算
    avg_likes_by_tag = calculate_avg_likes_by_tag(articles_data)

    print("Plotting average likes by tag...")
    plot_avg_likes_by_tag(avg_likes_by_tag)


```
</details>

ターミナルでpythonを実行します。
```terminal
% python qiita.py
```

![Figure_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524128/928ec00c-449d-4f83-5545-e2ff326ea6af.png)

限られた範囲の記事しか取得できていないのか偏りが見られました。

#### 今回取得したデータの中では「警察」、「事情聴取」のタグの平均いいね数が多かったです。


# 最後に
Qiitaの全情報の取得は難しかったため、一部の記事に絞って取得してみました。
python初心者がやったので、不備は多々あります。
python猛者の方々、もっと良いデータの取得方法などありましたらコメントで教えていただけるとありがたいです。
ここまで読んでいただきありがとうございます。

# 参考
https://qiita.com/dcm_chida/items/687654685dc434bdc9d4#fn-1

https://qiita.com/api/v2/docs