はじめに
D言語でのQiita API
の使用例を示したいと思います。
Qiita API
や他のAPI
を利用する際にも必要になる、libcurl
やJSON
処理の参考になればと思います。
今回使った Qiita API
GET /api/v2/items
を使用しました。
Qiita API v2ドキュメントより、抜粋します。
GET /api/v2/items
記事の一覧を作成日時の降順で返します。
page
ページ番号 (1から100まで)
Example: 1
Type: string
Pattern: /^[0-9]+$/
per_page
1ページあたりに含まれる要素数 (1から100まで)
Example: 20
Type: string
Pattern: /^[0-9]+$/
query
検索クエリ
Example: "qiita user:Qiita"
Type: string
API
から得られるJSON
の戻り値は、以下のイメージです。
[
{
"rendered_body":"",
"body":"",
"coediting":"",
"comments_count":"",
"created_at":"",
"group":"",
"id":"",
"likes_count":"",
"private":"",
"reactions_count":"",
"tags":[{"name":"", "versions":[]}]
"title":"",
"updated_at":"",
"url":"",
"user":
{
"description":""
"facebook_id":""
"followees_count":
"followers_count":
"github_login_name":""
"id":""
"items_count":
"linkedin_id":""
"location":""
"name":""
"organization":""
"permanent_id":""
"profile_image_url":""
"team_only":
"twitter_screen_name":""
"website_url":""
},
"page_views_count":""
}
]
事前準備(JSON処理の補足説明)
JSON
形式をパターン分けて、実装例を書いてみました。
これらのパターンを組み合わせれば、いろんなJSON
形式を処理できます。
import std.json;
import std.stdio;
void main()
{
string s = `{ "name" : "black", "value" : 0 }`;
JSONValue j = parseJSON(s);
writeln(s);
writeln(j["name"].type); // string
writeln(j["name"]); // "black"
writeln(j["value"].type); // integer
writeln(j["value"]); // 0
writeln();
s = `{ "key1" : { "key2" : "value" } }`;
j = parseJSON(s);
writeln(s);
writeln(j["key1"].type); // object
writeln(j["key1"]["key2"]); // "value"
writeln();
s = `[ { "key" : "value1" }, { "key" : "value2" } ]`;
j = parseJSON(s);
writeln(s);
writeln(j.type); // array
JSONValue[] jarr = j.array();
foreach ( jv ; jarr ){
writeln(jv["key"]); // "value1" "value2"
}
writeln();
s = `
{
"royalblue" : "#4169e1",
"darkgreen" : "#006400",
"deeppink" : "#ff1493"
}`;
j = parseJSON(s);
writeln(s);
writeln(j.type); // object
foreach ( string key, value; j ){
writefln("%-9s : %s", key, value); // not sorted
}
}
D:\Dev>dmd -m64 json1.d
D:\Dev>json1
{ "name" : "black", "value" : 0 }
string
"black"
integer
0
{ "key1" : { "key2" : "value" } }
object
"value"
[ { "key" : "value1" }, { "key" : "value2" } ]
array
"value1"
"value2"
{
"royalblue" : "#4169e1",
"darkgreen" : "#006400",
"deeppink" : "#ff1493"
}
object
darkgreen : "#006400"
royalblue : "#4169e1"
deeppink : "#ff1493"
1つ目のパターンは、項目名("name"や"value")を指定して、値("black"や0)を得る、基本パターンです。
parseJSON
を使うことで、JSON
の解析結果がJSONValue
に格納されます。
.type
を使えば、値の型を得ることができます。
実装例では、string
、integer
、object
、array
が得られています。
2つ目のパターンは、階層構造(.type
がobject
)になっている場合に値を得る例です。
j["key1"]["key2"]
という風に項目を指定することができます。
3つ目のパターンは、配列構造(.type
がarray
)になっている場合に値を得る例です。
実装例では、JSONValue[] jarr = j.array()
を使って、ループで値を得ています。
4つめのパターンは、仮に項目名がわからなくても、ループ処理foreach ( string key, value; j )
で項目名、値を得られることを示しています。
ソースコード
import std.conv;
import std.json;
import std.net.curl;
import std.stdio;
import std.uri;
void main()
{
listQiitaItems(getQiitaItems("tag:dlang", 5));
listQiitaItems(getQiitaItems("tag:D言語", 5));
}
JSONValue[] getQiitaItems(string option, int maxpage)
{
writeln(option);
if ( option != "" ){
option = "query=" ~ option.encodeComponent ~ "&";
}
string sUrl = "https://qiita.com/api/v2/items?" ~ option ~ "per_page=100&page=";
writeln(sUrl);
auto http = HTTP();
JSONValue[] jarr;
for ( int i = 1; i <= maxpage; i++ ){
JSONValue[] j = parseJSON(cast(string)get(sUrl ~ i.to!string, http)).array;
if ( j.length == 0 ){
break;
}
jarr ~= j;
}
return ( jarr );
}
void listQiitaItems(JSONValue[] jarr)
{
foreach ( i, j; jarr ){
writefln("No.%3d", i + 1);
writefln("title : %s", j["title"]);
writefln("user-id: %s", j["user"]["id"]);
write( "tags : ");
foreach ( j1; j["tags"].array ){
writef("%s ", j1["name"]);
}
writeln();
writefln("LGTM : %s", j["likes_count"]);
writefln("comment: %s", j["comments_count"]);
writeln();
}
}
getQiitaItems
getQiitaItems
関数で、libcurl
を使用しています。
libcurl get関数
QiitaAPIでの利用制限を考慮して、maxpage
を5
に指定しています。
利用制限
認証している状態ではユーザごとに1時間に1000回まで、認証していない状態ではIPアドレスごとに1時間に60回までリクエストを受け付けます。
検索結果はAPI
の呼び出し1回ごとに最大100件です。100件を超える場合を想定してループ処理になっています。
実行結果
D:\Dev>dmd -m64 qiitaapi.d
D:\Dev>qiitaapi > res.txt
tag:dlang
https://qiita.com/api/v2/items?query=tag%3Adlang&per_page=100&page=
No. 1
title : "Window10にWSL2+Ubuntuを導入し、GDC、DMD、LDCを使ってみた"
user-id: "devmynote"
tags : "dlang" "D言語" "Windows10" "WSL2"
LGTM : 1
comment: 0
No. 2
title : "D言語で迷路を再現(ドルアーガの塔)"
user-id: "devmynote"
tags : "dlang" "D言語" "クロージャ" "乱数" "迷路"
LGTM : 1
comment: 0
No. 3
title : "dub v1.23.0のx86_omfについて"
user-id: "mono_shoo"
tags : "dlang"
LGTM : 5
comment: 0
・・・ 省略 ・・・
No.399
title : "template for getting a field name of class or struct"
user-id: "repeatedly"
tags : "Dlanguage" "dlang"
LGTM : 1
comment: 0
tag:D言語
https://qiita.com/api/v2/items?query=tag%3AD%E8%A8%80%E8%AA%9E&per_page=100&page=
No. 1
title : "Window10にWSL2+Ubuntuを導入し、GDC、DMD、LDCを使ってみた"
user-id: "devmynote"
tags : "dlang" "D言語" "Windows10" "WSL2"
LGTM : 1
comment: 0
・・・ 省略 ・・・
No. 99
title : "D言語のビルドツール DUB"
user-id: "kazoo04"
tags : "D言語"
LGTM : 20
comment: 0
この記事を投稿する前の実行結果となります。
この記事がtag:dlang
で400番目の、tag:D言語
で100番目の記事になる予定です。
キリ番ゲットしちゃいました。
参考情報
Qiita API v2ドキュメント
std.net.curl 使用例
std.json 使用例