QiitaAPIを使って自分の記事の整理をしてリスト化する。

# はじめに
PythonでQiitaAPIを使って、記事の整理をしてみた。QiitaAPIは下記。

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

# 目次
+ [QiitaAPIの概要](#qiitaapiの概要)
+ [QiitaAPIでデータ取得する例](#qiitaapiでデータ取得する例)

# QiitaAPIの概要
+ Qiita APIはHTTPのメソッドでアクセスする。対応しているメソッドはGET、POST、PUT、PATCH、DELETEの5種類。APIでやり取りするデータのフォーマットはJSON。今回はデータ収集のためにAPIを使うので、GETメソッドを使う。

HTTPメソッド|内容
---|---
GET|データの要求。
POST|データの送信。
PUT|データの更新。
PATCH|データの部分更新。
DELETE|データの削除。

+ GETメソッドの場合はアクセストークンがなくても、1時間60回まではリクエストを受け付けてくれる。上限を超えるアクセス、または、POST、PUT、PATCH、DELETEのメソッドを使う場合は、アクセストークンを取得する必要がある。また、GETメソッドでも本人しか見れないViews数はアクセストークンがないと取得できなかった。アクセストークンはQiitaの **[設定]→[アプリケーション]→[個人用アクセストークン]** で取得できる。
　
+ GETメソッドでパラメータを指定する場合はURIクエリで指定する。URIクエリは```?```の区切り文字から始まる。指定するパラメータが複数ある場合```&```でつなげる。Google検索するときにURLに```?```や```&```の文字が出てくるが、それがURIクエリ。例えばkey1にval1、key2にval2を指定したい場合は```?key1=val1&key2=val2```となる。URIクエリで、```page```(ページ数)と```per_page```(ページあたりの要素数)を指定して、GETメソッドで取得するデータ数を指定する。```?page=5&per_page=20```とすれば、ページあたり20のデータの5ページ目を取得する。
　
+ GETメソッドのAPIは何種類かあるが今回は下記4点を使う。

　API|内容
 ---|---
 GET /api/v2/users/:user_id|```:user_id```にユーザIDの文字列を指定するとそのユーザIDに合致した「ユーザ情報」を取得できる。
 GET /api/v2/users/:user_id/items|```:user_id```にユーザIDの文字列を指定するとそのユーザIDに合致する「記事」のデータを取得できる。
 GET /api/v2/items/:item_id/likes|```:item_id```に記事のIDを指定すると、合致する記事の「いいね」のデータを取得できる。
 GET /api/v2/items/:item_id/stocks|```:item_id```にt記事のIDを指定すると、合致する記事の「ストック」のデータを取得できる。

+ GETの例。下記のとすれば「ユーザIDが[qiita]で、1ページ(ページあたり5個)分を取得する。」となり、JSON形式でデータがレスポンスされることを確認できる。
> https://qiita.com/api/v2/users/qiita/items?page=1&per_page=5

+ GET(***/items)で取得したデータには下記のようなものがある。

データ|内容
---|---
user_id|ユーザのID
description|ユーザの自己紹介文
items_count|ユーザの記事数
followees_count|ユーザがフォローしているユーザ数
followers_count|ユーザがフォローされているユーザ数
id|記事のID
url|記事のURL
title|記事のタイトル
tags|記事のタグ一覧
stocks_count|記事のストック数
likes_count|記事のいいね数
created_at|記事の作成日時
updated_at|記事の最終更新日時
body|記事の本文
page_views_count|記事の閲覧数(アクセストークンで承認必要。)

+ 条件を絞りたい場合は、URIクエリに```query```を使うこともできる。queryは下記参照。
https://help.qiita.com/ja/articles/qiita-search-options



[戻る](#目次)

# QiitaAPIでデータ取得する例
下記例は```qiita_api()```という関数にしてみた。ユーザIDとトークンIDは自分のものを設定する。投稿した記事の各種情報と、各記事に対して「いいね」や「ストック」してくれたユーザのリストを出力する。自分の今まで投稿した記事の情報がリストとして返答される。投稿した記事数によっては、処理に時間がかかるので注意。

関数名|引数|戻り値
--|--|--
qiita_api(user, token)|user : ユーザID<br>token : トークンID|記事の情報をリストとして返す。

ポイントとしては
+ GETで返答するデータを100で1ページとして分割していること。数量が多いとGETしきれないため。
+ いいねとストックのユーザリストは別関数```user_list_check()```にしていること。
+ likes(いいね)とstockers(ストック)でGETしたときのパラメータが違うので注意。likes(いいね)は2階層になっている。

```python:
import requests
import json
import openpyxl as px
from datetime import datetime
import pprint

def qiita_api(user, token):
	Ret=[]
	
	#-------------------------------------------------------
	#いいね、ストックしてくれたユーザのリスト取得
	# items_id   : 記事のID
	# check_type : likes(いいね) stockers(ストック)
	# count      : いいね or ストックのユーザ数
	# token      : トークンID
	#-------------------------------------------------------
	def user_list_check(items_id, check_type, count, token):
		Ret = []
		user_list=[]
		for i in range((count+100-1)//100):
			qiita_res = requests.get(f'https://qiita.com/api/v2/items/{items_id}/{check_type}', params = {'page': f'{(i+1):d}', 'per_page':'100'}, headers= { 'Authorization': f'Bearer {token}'})
			# listに格納
			user_list.append(json.loads(qiita_res.text))
			
		# ユーザのリストごと処理
		for i in range(len(user_list)):
			if check_type == 'stockers':
				Ret = [u['id'] for u in user_list[i]]
			elif check_type == 'likes':
				Ret = [u['user']['id'] for u in user_list[i]]

		return Ret

	# userの記事数確認
	qiita_res   = requests.get(f'https://qiita.com/api/v2/users/{user}')
	items_count = json.loads(qiita_res.text)['items_count']

	# 記事を100ずつに分けて取得
	post_list=[]
	for i in range((items_count+100-1)//100):
		qiita_res = requests.get(f'https://qiita.com/api/v2/users/{user}/items', params = {'page': f'{(i+1):d}', 'per_page':'100'}, headers= { 'Authorization': f'Bearer {token}'})
		
		# post_listに格納
		post_list.append(json.loads(qiita_res.text))
	
	# 1記事ずつ処理
	for i in range(len(post_list)):
		for post  in post_list[i]:
			post_detail={}
			post_detail['ID']				= post['id']
			post_detail['タイトル']			= post['title']
			post_detail['URL']				= post['url']
			post_detail['作成日']			= datetime.fromisoformat(post['created_at']).strftime('%Y/%m/%d')
			post_detail['更新日']			= datetime.fromisoformat(post['updated_at']).strftime('%Y/%m/%d')
			post_detail['VIEW数']			= post['page_views_count']
			post_detail['Tag']				= [tag['name'] for tag in post['tags']]
			post_detail['いいね数']			= post['likes_count']
			post_detail['いいねユーザ']		= user_list_check(post['id'], 'likes', post['likes_count'], token)
			post_detail['ストック数']		= post['stocks_count']
			post_detail['ストックユーザ']	= user_list_check(post['id'], 'stockers', post['stocks_count'], token)
			
			Ret.append(post_detail)
		
	return Ret


user = input('ユーザ名:')
token = input('アクセストークン:')
pprint.pprint(qiita_api(user, token))
```

実行結果イメージ。XXXは伏字にしたところ。
```
[{'ID': '764440297cb9b1302b81',
  'Tag': ['Python', 'replace', 'pandas'],
  'URL': 'https://qiita.com/tapitapi/items/764440297cb9b1302b81',
  'VIEW数': XXX,
  'いいねユーザ': [],
  'いいね数': 0,
  'ストックユーザ': [],
  'ストック数': 0,
  'タイトル': 'Pandasの要素指定・置換',
  '作成日': '2024/10/14',
  '更新日': '2024/10/14'},
 {'ID': 'fdd86439840dfa96c312',
  'Tag': ['Python', 'pandas'],
  'URL': 'https://qiita.com/tapitapi/items/fdd86439840dfa96c312',
  'VIEW数': XXX,
  'いいねユーザ': ['XXX', 'XXX', 'XXX', 'XXX', 'XXX'],
  'いいね数': 5,
  'ストックユーザ': ['XXX',
              'XXX',
              'XXX',
              'XXX',
              'XXX',
              'XXX',
              'XXX',
              'XXX',
              'XXX',
              'XXX'],
  'ストック数': 10,
  'タイトル': 'Pandasでよく使う23選',
  '作成日': '2024/10/13',
  '更新日': '2024/10/13'},
  ・・・・
```

参考にした記事

https://qiita.com/koki_develop/items/57f86a1abc332ed2185d


以上