Qiita APIとPythonを用いてQiitaのデータを取得してみる
Qiita APIとPythonを用いてQiitaのデータを取得してみる
Qiita APIを使用すると、Qiitaサイトにあるデータを取得できます。PythonでQiita APIをたたき、データを取得してみます。
APIを調べる
Qiita API v2公式サイト
Qiita APIの詳細はすべてこちらに書かれています。
使えそうなAPIを探す
今回は、記事についているタグをキーに記事一覧を取得してみます。
「タグ」や「投稿」あたりを見てみて、タグをキーに記事を取得できそうなAPIを探します。
以下のAPIが使えそうでした。
GET /api/v2/tags/:tag_id/items
指定されたタグが付けられた記事一覧を、タグを付けた日時の降順で返します。
お試しでAPIを呼んでみる
APIの呼び出し(パラメータなし)
まずは、Pythonで上記のAPIをパラメータなしでたたき、データを取得してみます。
requestsモジュールのインストール
pip install requests
APIをたたいてみます。
import requests res = requests.get('https://qiita.com/api/v2/tags/python/items') print(res.text)
[{"rendered_body":"\u003cp\u003ePythonでOAuth認証を突破して、アクセストークンを取得するスクリプトを書きました。 \u003cbr\u003e\n解説などはあとで書き加えたいと思います。\u003c/p\u003e\n\n\u003cp\u003e\u003ca href=\"https://qiita.com/kai_kou/items/d03abd6012f32071c1aa\" class=\"autolink\" id=\"reference- ...
JSONが返ってきており、中身に記事の中身らしきものが含まれているのが見えます。JSONのフォーマットもAPIリファレンスに書かれたフォーマットになっています。
APIの呼び出し自体はうまくいってそうですね。
APIの呼び出し(URLクエリ)
もう少し条件を付けてみます。APIリファレンスのサンプルに書かれている、pageとper_pageのオプションをURLのクエリにつけて呼び出してみます。
import requests res = requests.get('https://qiita.com/api/v2/tags/python/items?page=1&per_page=10') print(res.text)
これも問題なく取得できました。
APIの呼び出し(JSONクエリ)
パラメータが多いとパラメータを変えながら渡すのが大変なため、あらかじめクエリをJSONで作り、それを渡します。
import requests import json p = { "page": "1", "per_page": "5", } res = requests.get('https://qiita.com/api/v2/tags/python/items', params=p) print(res.text)
同じデータが返ってきたのが確認できました。
なお、この書き方であればエンコードなども自動でやってくれるそうです。
JSONモジュールで読み込む
上記のデータを、JSONを処理するモジュールに読み込ませてみます。
import requests import json res = requests.get('https://qiita.com/api/v2/tags/python/items?page=1&per_page=5') jsondata = json.loads(res.text) print(len(jsondata))
5
JSONモジュールで読みこめて、lenで5個あることが確認できました。
APIドキュメントを見ると、JSONに"id"および"title"という項目があるのが分かるので、その部分を取り出してみます。
for item in json: print(item['id']) print(item['title'])
16e88f7a85f82d7afac8 OAuth認証してアクセストークンを取得する 715aba6db368f53b3a2e VBAユーザがPython・Rを使ってみた:行列 2b5523eede2e0c088f92 [Blender] Modeling tips まとめ Mesh Modeling編 55daf41e925a969aa5b5 Docker-compose + Django + MySQL + Nginx + uwsgi を使った環境の初期設定 c350f64b7abb396973ed 【pytorch-lightning入門】torchvision.transformsの使い方と自前datasetの自由な作り方?
idとtitleが取り出せました。JSONの中身も問題ないようです。
認証
API呼び出しの制限
API呼び出しは、未認証ユーザであれば1時間に60回までリクエストの制限があります。認証することで、1時間に1000回まで呼び出せるようになるため、認証をしておきます。
アクセストークンの発行
APIドキュメントの「認証許可」の項目を見ると、ユーザ管理画面からアクセストークンを発行できるようなので、ユーザ管理画面に行きます。
https://qiita.com/settings/applications
Qiitaにログイン後、「個人用アクセストークン」のところに「新しくトークンを発行する」のリンクから発行できます。
説明は分かりやすいように文章を記載、スコープはひとまず「read_qiita」だけでよいです。
発行ボタンでトークンが発行されます。なくさないようにメモっておきましょう。
認証してみる
APIドキュメントの「認証認可」内、「アクセストークン」の部分に、トークンをヘッダに含めればいいと記載あり。コードに追加してみます。
import requests import json token = "=====paste=your=token=here=====" headers = { "Authorization": "Bearer " + token } params = { "page": "1", "per_page": "5", } res = requests.get('https://qiita.com/api/v2/tags/python/items', params=params, headers=headers) print(res.text)
先ほどのコードと同じ結果が返ってきました。問題なく認証されて呼び出せました。
記事を取得する
先ほどの処理で記事一覧が取得できたので、そのidを使って記事本文を取得してみます。
使用するAPI
APIリファレンスの「投稿」あたりを見てみると、以下が使えそうでした。
GET /api/v2/items/:item_id
記事を取得します。
呼び出し
先ほどの認証処理のあとに、記事取得APIを記事数回呼び出し、各記事の情報を取得します。
APIリファレンスによると、戻りJSON内に"tags"の項目があり、その中にタグがリストで返ってくるようなので、それをjsonモジュールで解析して画面に出してみます。
import requests import json token = "=====paste=your=token=here=====" headers = { "Authorization": "Bearer " + token } params = { "page": "1", "per_page": "5", } res = requests.get('https://qiita.com/api/v2/tags/python/items', params=params, headers=headers) jsondata = json.loads(res.text) for item in jsondata: print(item['id']) # 記事IDを出力 res = requests.get('https://qiita.com/api/v2/items/' + item['id'], headers=headers) json_content = json.loads(res.text) for tag in json_content['tags']: print(tag['name']) #記事のタグを出力
a3b1dfbc580608dd4e10 Python 再帰関数 580d000d1eda58bfa8b4 Python gspread slackbot 16e88f7a85f82d7afac8 Python OAuth HTTPS 715aba6db368f53b3a2e Python R VBA 配列 行列 2b5523eede2e0c088f92 Python Blender
記事ごとのタグ一覧がすべて出力されました。
タグの数を数えてみる
データは取得できたので、あとは好きに加工すればよいです。
今回は、タグの数を数えてみます。tag_cnt変数でタグをカウントしていきます。
import requests import json token = "=====paste=your=token=here=====" headers = { "Authorization": "Bearer " + token } params = { "page": "1", "per_page": "5", } # 「python」タグがついた記事一覧を取得 res = requests.get('https://qiita.com/api/v2/tags/python/items', params=params, headers=headers) jsondata = json.loads(res.text) tag_cnt = {} for item in jsondata: # 各記事を取得 res = requests.get('https://qiita.com/api/v2/items/' + item['id'], headers=headers) json_content = json.loads(res.text) # 記事の各タグについて for tag in json_content['tags']: # カウント処理 if tag['name'] in tag_cnt: tag_cnt[tag['name']] += 1 else: tag_cnt[tag['name']] = 1 # カウントした値を出力 for key, value in tag_cnt.items(): print(key, value)
Python 5 再帰関数 1 gspread 1 slackbot 1 OAuth 1 HTTPS 1 R 1 VBA 1 配列 1 行列 1 Blender 1
Pythonで検索しているのでPythonが一番多く5個、Pythonタグとともについているタグがどういったものかが分かりました。
900記事を取得する
上記では、ページ当たりの記事数を5個とし、その1ページ目だけを取得しました。このカウントを増やし、900記事分を取得してみます。
最初のAPI(GET /api/v2/tags/:tag_id/items)の説明によると、同時に取得できる記事一覧の数は100個までなので、100個の記事を9回取得します。
1回の処理でAPI呼び出しが101回行われるため、9回繰り返すと合計909回のAPI呼び出しとなり、API呼び出し制限1000回を下回ります。
import requests import json token = "=====paste=your=token=here=====" headers = { "Authorization": "Bearer " + token } tag_cnt = {} for i in range(9): params = { "page": str(i + 1), "per_page": "100", } # 「python」タグがついた記事一覧を取得 res = requests.get('https://qiita.com/api/v2/tags/python/items', params=params, headers=headers) jsondata = json.loads(res.text) for item in jsondata: # 各記事を取得 res = requests.get('https://qiita.com/api/v2/items/' + item['id'], headers=headers) json_content = json.loads(res.text) # 記事の各タグについて for tag in json_content['tags']: # カウント処理 if tag['name'] in tag_cnt: tag_cnt[tag['name']] += 1 else: tag_cnt[tag['name']] = 1 # カウントした値を出力 for key, value in tag_cnt.items(): print(key, value)
Python 900 AWS 23 lambda 25 Slack 7 ServerlessFramework 4 Python3 110 gspread 3 slackbot 3 Twitter 7 tweepy 3 自然言語処理 13 NLP 2 WordNet 1 環境構築 11 Anaconda 14 ・・・
取得に数分かかりましたが、無事取得できました。
CSV出力する
取得して集計したデータをCSVに出力してみます。
with open("output.csv", "w", encoding='utf-8') as f: for key, value in tag_cnt.items(): f.write('"' + key + '", ' + str(value) + "\n")