<aside>

> Duolingo非公式API

</aside>

| Duolingo 非公式APIの存在

公式にはアナウンスされていないけれど、API処理ができるようです。

requestsを投げると返ってきます。

| 認証に必要なデータの取得(手作業)

API使用には認証が必要です。jwt_token という値を取得します。

image.png

image.png

image.png

<aside>

> 色々な処理の実装(python)

</aside>

| UserIDを取得する処理

Username から UserID取得します。

認証(jwt_token)は不要です。

import requests

username = **"USERNAME"**

def get_duolingo_id(username: str):
    url = f"<https://www.duolingo.com/2017-06-30/users?username={username}>"
    headers = {
        "User-Agent": "Mozilla/5.0"
    }

    resp = requests.get(url, headers=headers)
    resp.raise_for_status()
    data = resp.json()
    
    if "users" in data and len(data["users"]) > 0:
        user_id = data["users"][0].get("id")
        return user_id
    else:
        return None

user_id = get_duolingo_id(username)
if user_id:
    print(f"Username: {username} → User ID: {user_id}")
else:
    print("ユーザーが見つかりませんでした")

実行結果例

image.png

| 相互フォローになっていないユーザーを一覧表示する処理

import requests
import time

user_id = **"USERID"**
jwt_token = **"JWT TOKEN"**

headers = {
    "Authorization": f"Bearer {jwt_token}",
    "User-Agent": "Mozilla/5.0",
}

# followers
followers_url = f"<https://www.duolingo.com/2017-06-30/friends/users/{user_id}/followers>"
followers_params = {"pageSize": 500, "viewerId": user_id, "_": str(int(time.time() * 1000))}
followers_data = requests.get(followers_url, headers=headers, params=followers_params).json()

# following
following_url = f"<https://www.duolingo.com/2017-06-30/friends/users/{user_id}/following>"
following_params = {"pageSize": 500, "viewerId": user_id, "_": str(int(time.time() * 1000))}
following_data = requests.get(following_url, headers=headers, params=following_params).json()

followers_list = {tmp_userlist["username"] for tmp_userlist in followers_data["followers"].get("users", [])}
following_list = {tmp_userlist["username"] for tmp_userlist in following_data["following"].get("users", [])}

# 相互フォローしていない人
not_following_back = following_list - followers_list

print("フォローしているがフォローされていないアカウント:")
for tmp_userlist in sorted(not_following_back):
    print('<https://www.duolingo.com/profile/>' + tmp_userlist)

実行結果例

image.png

これでプロフィールのURLを開いてどんどんフォロー解除できますね。

| ユーザの連続日数(streak)を取得

userIDを指定してstreakを取得します。

認証(jwt_token)は不要です。

import requests

user_id = **"USERID"**

url = f"<https://www.duolingo.com/2017-06-30/users?username={user_id}>"
headers = {
    "User-Agent": "Mozilla/5.0",
    "Accept": "application/json"
}

res = requests.get(url, headers=headers)
res.raise_for_status()

data = res.json()
user_data = data["users"][0]
streak = user_data["streak"]

print(user_id, "の streak:", streak, "日")

実行結果例

image.png

こざえもん、635日がんばっている。えらい。

| フォローしているユーザの連続日数(streak)を一覧取得

ちょっと処理時間かかるけど、ずらっと表示されます。

import requests
import time

user_id = **"USERID"**
jwt_token = **"JWT TOKEN"**

headers = {
    "Authorization": f"Bearer {jwt_token}",
    "User-Agent": "Mozilla/5.0",
}

def streak_check(user_id):
    url = f"<https://www.duolingo.com/2017-06-30/users?username={user_id}>"
    headers = {
        "User-Agent": "Mozilla/5.0",
        "Accept": "application/json"
    }

    res = requests.get(url, headers=headers)
    res.raise_for_status()

    data = res.json()
    user_data = data["users"][0]
    return user_data["streak"]

# following
following_url = f"<https://www.duolingo.com/2017-06-30/friends/users/{user_id}/following>"
following_params = {"pageSize": 500, "viewerId": user_id, "_": str(int(time.time() * 1000))}
following_data = requests.get(following_url, headers=headers, params=following_params).json()

following_list = {tmp_userlist["username"] for tmp_userlist in following_data["following"].get("users", [])}

print("各ユーザのStreak: ※0daysは先頭に★")
for tmpUserID in sorted(following_list):
    streak = streak_check(tmpUserID)
    if streak == 0:
        print('★https://www.duolingo.com/profile/' + tmpUserID + ": " + str(streak) + "days")
    else:
        print('<https://www.duolingo.com/profile/>' + tmpUserID + ": " + str(streak) + "days")

実行結果例

image.png

streak 0days のお友達は、すまないけどフォロー解除させてもらいます。

| 500人以上のフォローユーザを取得する

pageSizeが500を超えると、duolingoからエラーが返ってくる..という情報があります。(まだ試していませんが)

なので、500名以上のデータを取得する場合は工夫が必要と思われます。

requestのパラメータにpageを追加して、ループ処理でpage数をインクリメントしていけば、全データ取得できるはずです。

*ここの処理は考え中です。
というか、まだ友達500も居ないので、困った頃に記載します。*

以上

<aside>

最近の更新

2025/9/23

2025/9/22

2025/8/23

2025/7/5

<aside>

ICON.png

Hello world


NAME : こざえもん

SNS : X(@koz_sec)

JOB : IT Security

Certifications