はじめに
前回の記事(「初投稿のPVが爆増したのがtrocco®とQiita APIでよくわかった話」)では、Qiita APIを利用して、自分のアカウントのデータを取得する仕組みについて紹介しました。
その最後で、組織のデータを取るのは難しいという話に触れていたのですが、せっかくなので遊んでみるかということで、データの取得方法を考えてみました。
何が難しいのか
Qiita APIで記事データを取得するには、リクエストを投げる際にpage
パラメータを指定する必要があります。自分のデータの取得であれば、
-
api/v2/authenticated_user
で記事数を取得 - 取得した記事数をもとにpageの数値を計算して、
api/v2/authenticated_user/items
から記事データを取得
という流れで処理を行うことができます。
一方、組織のデータを取得しようとすると、APIで組織の記事数を取得できないため、別の工夫をして記事数を特定しなければなりません。記事数が上手く特定できないと、
- 指定した
page
に対象記事がないことで、エラーが発生する - 記事のある
page
を指定できていないことで、取得漏れが生じる
可能性があります。
増減の要因を整理する
対応方法を考えるにあたり、まずは記事数の増減要因を考えてみます。
-
- 増加要因
- 1-1. 新規記事の作成
- 1-2. 既存記事への組織連携の追加付与
-
- 減少要因
- 2-1. 既存記事への組織連携の解除
- 2-2. ユーザーアカウント削除(未検証ではあるのでおそらく)
なお、アカウント単位の組織連携と記事単位の組織連携は独立しているので、アカウントの組織連携を解除しても記事の連携には影響しません。(「Organizationの設定について」)
そこで対応を考えてみると、
- 1-1と1-2:
updated_at
が前回データ取得時よりも後になっているものから拾えそうです。(既存記事への組織連携への追加付与でupdated_at
は更新される気がする/未検証) - 2-1と2-2:前回データ取得にあったが、今回なくなったものを検知すればよさそうです。
しかし、これをやろうとするとなかなかややこしいですね・・・記事数を取得できるような仕組みがあると助かるのですが。
ちなみにこれは余談ですが、組織ページの記事投稿数と、記事検索での組織連携されている記事数にずれがあり、組織ページの数値をスクレイピングするという裏技も使えずでした。なんでずれているのだろう。
方針を整理する
下記のような流れで進めれば対応できそうです。
- 新たに更新された記事データを取得する
- 前日に取得していた記事データを取得し、上記と合算することで本日該当するであろう記事数を算出
- 記事数をもとに
page
を算出して本日分の記事データを取得 - 本日取得した記事からユーザーIDを特定してユーザーデータを取得
- (2の減少分の考慮はややこしいので諦めました/何かいいやり方があれば教えてください笑)
trocco®で実装してみる
内容はかなり前回と同じようなものが多いので、異なる部分を中心にご紹介します。
新たに更新された記事データを取得する
- APIのURLはhttps://qiita.com/api/v2/items
- カスタム変数で前日の日付を取得して、queryのパラメータに入れることで、前日以降に更新された記事を取得する
query=org:primenumber_inc updated:>=$yesterday$
前日に取得していた記事データを取得し、上記と合算することで本日該当するであろう記事数を算出
この部分はクエリで処理をしてしまいます。下記のクエリでできますね。
select
count(id) as items_count
from
(
select distinct id from `project-name.dataset_name.qiita_api_items_primenumber_inc`
where date(timestamp_add(transferred_at, interval 9 hour)) = date_sub(current_date('Asia/Tokyo'), interval 1 day)
union distinct
select id from `project-name.dataset_name.qiita_api_items_primenumber_inc_newly_updated`
)
記事数をもとにpage
を算出して本日分の記事データを取得
上記のクエリを踏まえて、前回も登場したBigQueryのクエリ結果でループ実行を利用します。
with sum_items as (
select
count(id) as items_count
from
(
select distinct id from `project-name.dataset_name.qiita_api_items_primenumber_inc`
where date(timestamp_add(transferred_at, interval 9 hour)) = date_sub(current_date('Asia/Tokyo'), interval 1 day)
union distinct
select id from `project-name.dataset_name.qiita_api_items_primenumber_inc_newly_updated`
)
)
select
page
from
unnest(generate_array(1, (select div(items_count - 1, 100) + 1 from sum_items))) page
本日取得した記事からユーザーIDを特定してユーザーデータを取得
- APIのURLはhttps://qiita.com/api/v2/users/$user_id$
- カスタム変数で
user_id
を作成しておいて、このIDをBigQueryのクエリ結果でループ実行する
select distinct
user_id
from
`project-name.dataset_name.qiita_api_items_primenumber_inc`
where
date(timestamp_add(transferred_at, interval 9 hour)) = current_date('Asia/Tokyo')
組織の成果を可視化してみる
これでデータが揃ったので、Looker Studioでグラフにしてみます。凝ったものを作る前にめげました。
そしてこれを作ってから気が付いたのですが、限定公開すると検索上は公開日が限定公開を設定した日になっていて、一方で記事上での公開日は一般公開日になっている・・・(すると、限定公開の記事も組織の公開記事数に含まれているということかもしれない)
※ちなみにクエリ結果でループ実行については、上記の記事も参考になるのでぜひご覧ください!
おわりに
これで一通り組織のデータが取得できるようになりました。
- 記事数
- Like数
- ストック数
- コメント数
を蓄積して活用することができます。PV数が取得できないのが難点ですが、記事投稿数やLike数がわかるだけでも少しは役立ちそうです。
おまけ:タグの加工(string_agg
が便利だった件)
タグの情報についても、そのままで取得するのはJSON形式になりますが、少し加工してあげるとフィルタ等で利用することができるようになります。データ転送時ではなく、BigQueryに取り込み後のSQLでも加工はできます。下記のようなものです。
tag_all as (
select
article_id,
transferred_at,
string_agg(json_value(t.name), ',') as tag_all
from
tmp_data -- ここのもとは省略
left join
unnest(json_query_array(parse_json(tags))) t
group by
article_id, transferred_at
),
この処理でこれが、
[
{"name":"QiitaAPI","versions":[]},
{"name":"BigQuery","versions":[]},
{"name":"trocco","versions":[]}
]
こうなります。
QiitaAPI,BigQuery,trocco
string_agg
とかどこで使うのかと考えていたら、案外便利そうに思えました。