うならぼ

申し訳程度のアフィリエイトとか広告とか解析とかは/aboutを参照

国立国会図書館のAPIで書誌情報を検索してみた話

書名や著者名に対する読み仮名の情報を揃えたくなったので、国立国会図書館APIで検索してみた。

国立国会図書館API

APIのご利用について « 国立国会図書館サーチについて

いくつか種類があるが、今回使うのはSRUというプロトコル。検索用API3つの中では最も高機能で、前方一致や完全一致、ソート順の指定などもできる。検索対象のフィールドとしてはタイトル、著者、出版社、NDC分類、ISBN、出版年などが使える。

GETでXMLが落ちてくるので、例えば https://iss.ndl.go.jp/api/sru?operation=searchRetrieve&recordPacking=xml&recordSchema=dcndl&maximumRecords=1&query=title%3D%E3%81%86%E3%82%89%E3%82%89%E8%BF%B7%E8%B7%AF%E5%B8%96%201 をブラウザで開くと見れる。

クエリパラメータを簡単に解説するとこういう感じ。

  • operation=searchRetrieve コマンド的なもの
  • recordPacking=xml 検索結果をそのままXMLに埋め込む指定。デフォルトはtextで、XMLが文字列として入ってくる。
  • recordSchema=dcndl レコードのスキーマを色々選べる。デフォルトの dcdcndl よりもシンプルで、カナ情報とかは入っていない。
  • maximumRecords=1 いわゆるlimit
  • query=... 検索クエリを CQL (Contextual Query Language) で記述する。ここでは title=うらら迷路帖 1。後述。

そしてお目当てのカナ情報は <dcndl:transcription> タグに入っている。

なおここで取れるデータは別組織から提供を受けたものもあるため、メタデータのライセンスはデータプロバイダごとに異なる。国立国会図書館オンラインのデータだとCC-BY 4.0、とか。

CQLと戦う

queryパラメータに指定するクエリについてはAPIのドキュメントにも説明はあるものの、CQLを知っている前提の説明なのでこれだけだとよくわからない。特に前方一致に使う ^exact 等と並列に書かれていてさんざんはまった *1。なのでCQL自身については別途 https://www.loc.gov/standards/sru/cql/spec.htmlhttps://www.loc.gov/standards/sru/cql/contextSets/theCqlContextSet.html などを読むのがよさそう。

もしくは同様のAPIである 国立国会図書館東日本大震災アーカイブのAPIドキュメント を読むと、基本的な使い方や雰囲気は掴める。

とはいえ結局 field =|==|exact|all|any "term" [and/or ...] で、加えるとしたらソート条件ぐらいだろう。

  • ===
    • 半角スペースを含んでいてもフレーズ検索される
    • 全角スペースを含むとフレーズ検索ではなくなる
    • ^== だと無視される
  • exact での完全一致
    • 日本語扱いの英字?(NEW GAME! とか)は全角でも半角でもマッチするが、英語扱いの英字は半角でないとマッチしない
    • NEW GAME! で言うところのスペースや感嘆符は半角にしないとマッチしない
  • メタ文字 ^ での前方一致
    • 前述の「日本語扱いの英字」は全角英字にしないとヒットしない
      • title = "^NEW" AND creator = 得能正太郎 はよくて title = "^NEW" AND creator = 得能正太郎 はダメ
      • title exact "NEW GAME!"title = "NEW GAME!" は大丈夫
    • 空白を含むフレーズの前方一致ができない
      • title = "^foo bar" は検索結果が0件になる
      • title all "^foo bar" はできるが、これはfooとbarが連続している保証がない
        • つまり title = "^foo" and title = "foo bar" とするのが一番近いだろうか…
      • CQLの資料を見るに、 adj とか /string とか prox とかが使えればあるいはという気もするが、対応していない様子

取得結果を読み取る

JSなら例えばこんな感じで。

const title = "...";
const creator = "...";
const xml = await fetch("https://iss.ndl.go.jp/api/sru?operation=searchRetrieve&recordPacking=xml&recordSchema=dcndl&onlyBib=true&maximumRecords=1&query="+encodeURIComponent(`title = "${title}" and creator = "${creator}" and sortBy=issued_date/sort.ascending`)).then(x => x.text());
const doc = new DOMParser().parseFromString(xml, "application/xml");
const title_kana = doc.querySelector('title transcription')?.textContent;
const creator_kana = doc.querySelector('creator transcription')?.textContent;
console.log(`${title}(${title_kana}) - ${creator}(${creator_kana})`);

XMLはDOMParserを通せばDOMで触れるので、あとはquerySelectorでもなんでも。本当は名前空間を指定した方がいいのだろうけど、querySelectorでやるのも面倒だったので省略。

おまけ

ところでKindle芳文社創立70周年セールが話題ですね。いい機会なので、たまにはアソシエイトIDを活用してみましょう。

擬人化されていないやつは苦手です、ええもちろん。

*1:exactは=同様の演算子的なもの(relation)だが、 ^ は検索キーワードに使うメタ文字なので他のrelationと組み合わせて使わないといけない