1.国立国会図書館APIについて
今回はpythonと検索用API(opensearch)を用いて書籍情報を取得します。
ISBNを用いて一致する書籍を探し、タイトル・著者名などの書籍情報を取得し、使いやすく整形して辞書型で返す関数型のプログラムを作成しました。
ISBNから探すのでおそらく一致する書籍は一意なものになる(?)と思われます。
以前にも似たような記事を書いていたのですが、やや処理が冗長だったのと取得可能な書籍情報の整理ができていなかったので、再度記事を書きなおしました。
以下のページなどを参考にしています。
2.プログラムコードとデータ取得の実例
国立国会図書館のAPIはレスポンスをXMLで返してくるので、これを辞書型にパースするため、xmltodictを利用しています。
辞書に変換されたXMLファイルは構造がやや入れ子になっているので、使う情報を整理しています。
XMLファイルの構造がやや複雑である点に注意してください
pprintは結果の確認のために使用しています。必要なデータのみを取得するように適宜変えてみてください。
一応isbnをもとに書籍情報を取得するので、isbnを取得する意味はないのですが、当然国立国会図書館のデータの中にはあるので、# 辞書型を整理の部分を見てもらえればどのようにISBNを取得しているかわかるという意味でisbn_dataとしておきました。
import requests
import xmltodict
import pprint
# ISBNを使って書誌情報を取得
def fetch_book_info(isbn):
# NDLサーチAPI(国立国会図書館の説明を参照)
base_url = "https://iss.ndl.go.jp/api/opensearch"
# APIリクエストのパラメータを設定
params = {
'isbn': isbn,
'format': 'xml'
}
# リクエストを取得
response = requests.get(base_url, params=params)
# XMLを辞書型に変換
book_info = xmltodict.parse(response.text)
# 入れ子になった辞書型を整理し、必要と思われる情報のみ取得
book_dict = {
"author": book_info['rss']['channel']['item']['author'], # 著者
"category": book_info['rss']['channel']['item']['category'], # カテゴリ
"creator": book_info['rss']['channel']['item']['dc:creator'], # 作者
"publication_year": book_info['rss']['channel']['item']['dc:date']['#text'], # 発行年
"description": book_info['rss']['channel']['item']['dc:description'], # 説明
"pages": book_info['rss']['channel']['item']['dc:extent'], # ページ数
"isbn_data": book_info['rss']['channel']['item']['dc:identifier'][0]['#text'], #ISBN
"publisher": book_info['rss']['channel']['item']['dc:publisher'], # 出版社
"call_number": book_info['rss']['channel']['item']['dc:subject'][1]['#text'], # 請求記号
"title": book_info['rss']['channel']['item']['dc:title'], #タイトル
"author_kana": book_info['rss']['channel']['item']['dcndl:creatorTranscription'], # 作者カナ表記
"price": book_info['rss']['channel']['item']['dcndl:price'], # 価格
"series_title": book_info['rss']['channel']['item']['dcndl:seriesTitle'], # シリーズ名
"series_title_kana": book_info['rss']['channel']['item']['dcndl:seriesTitleTranscription'], # シリーズ名カナ表記
"title_kana": book_info['rss']['channel']['item']['dcndl:titleTranscription'] #タイトルカナ表記
}
""" 変数に代入する場合の例
author = book_info['rss']['channel']['item']['author'] # 著者
category = book_info['rss']['channel']['item']['category'] # カテゴリ
creator = book_info['rss']['channel']['item']['dc:creator'] # 作者
publication_year = book_info['rss']['channel']['item']['dc:date']['#text'] # 発行年
description = book_info['rss']['channel']['item']['dc:description'] # 説明
pages = book_info['rss']['channel']['item']['dc:extent'] # ページ数
isbn_data = book_info['rss']['channel']['item']['dc:identifier'][0]['#text'] #ISBN
publisher = book_info['rss']['channel']['item']['dc:publisher'] # 出版社
call_number = book_info['rss']['channel']['item']['dc:subject'][1]['#text'] # 請求記号
title = book_info['rss']['channel']['item']['dc:title'] #タイトル
author_kana = book_info['rss']['channel']['item']['dcndl:creatorTranscription'] # 作者カナ表記
price = book_info['rss']['channel']['item']['dcndl:price'] # 価格
series_title = book_info['rss']['channel']['item']['dcndl:seriesTitle'] # シリーズ名
series_title_kana = book_info['rss']['channel']['item']['dcndl:seriesTitleTranscription'] # シリーズ名カナ表記
title_kana = book_info['rss']['channel']['item']['dcndl:titleTranscription'] #タイトルカナ表記
"""
return book_dict
# ISBNを指定して情報を取得
isbn = '9784043898039'
d = fetch_book_info(isbn)
# 結果を整形して表示
pprint.pprint(d)
""" 結果
{'author': '有川, 浩, 1972-,有川浩 [著]',
'author_kana': 'アリカワ, ヒロ, 1972-',
'call_number': '913.6',
'category': ['図書', '紙'],
'creator': '有川, 浩, 1972-',
'description': ['メディアワークス2007年刊の加筆、訂正', '2010'],
'isbn_data': '978-4-04-389803-9',
'pages': '444p',
'price': '667円',
'publication_year': '2010',
'publisher': ['角川書店', '角川グループパブリッシング (発売)'],
'series_title': '角川文庫 ; 16082',
'series_title_kana': 'カドカワ ブンコ ; 16082',
'title': '塩の街',
'title_kana': 'シオ ノ マチ'}
"""
3.留意点
ここまでくればjsonにしてみたり、isbnのリストをループさせて書籍情報を連続で取得したりできると思います。
なお、ループ処理を行う場合は下記の留意事項を遵守する必要があります。
多重アクセスの禁止は明確に示されているので、単一のリクエストを適切な時間間隔ごとにリクエストするのが望ましいでしょう。
後ほど気づいたことですが、プログラムのテストであってもリクエストを送ることには何ら変わらないので、リクエスト結果をwith句などを使ってファイルに保存しておき、getリクエスト部分をコメントアウトすると親切かもしれません。
# リクエスト取得部分をコメントアウト
# response = requests.get(APIのURL, params=APIリクエスト用パラメータ)
# with open('response_data.txt', 'w', encoding='utf-8') as file:
# file.write(response.text) # テキストデータを保存
# 保存済みのテキストファイルを読み込む
with open('response_data.txt', 'r', encoding='utf-8') as file:
response = file.read()
# XMLを辞書型に変換
book_info = xmltodict.parse(response) # 保存時にテキストとして保存したので.textをはずす
4.課題点
この生成された辞書型のファイル(というよりもそもそものXMLファイル)がなかなかくせもので、['dc:identifier'][0]のように辞書のなかに配列が混じっています。
しかも、['item'][0]のようにどの要素のなかに入っているかは本によってさまざまなので困ります。
今後はこのへんの部分をうまくサーチしてうまくデータを整頓できるようなプログラムの改造を行っていきたいと思います。
"isbn_data": book_info['rss']['channel']['item']['dc:identifier'][0]['#text'], #ISBN
# 実行結果の例
{'rss': {'@version': '2.0',
'@xmlns:dc': 'http://purl.org/dc/elements/1.1/',
'@xmlns:dcmitype': 'http://purl.org/dc/dcmitype/',
'@xmlns:dcndl': 'http://ndl.go.jp/dcndl/terms/',
'@xmlns:dcterms': 'http://purl.org/dc/terms/',
'@xmlns:openSearch': 'http://a9.com/-/spec/opensearchrss/1.0/',
'@xmlns:rdf': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
'@xmlns:rdfs': 'http://www.w3.org/2000/01/rdf-schema#',
'@xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
'channel': {'description': 'Search results for isbn=9784043898039 '
'format=xml',
'item': {'author': '有川, 浩, 1972-,有川浩 [著]',
'category': ['図書', '紙'],
'dc:creator': '有川, 浩, 1972-',
'dc:date': {'#text': '2010',
'@xsi:type': 'dcterms:W3CDTF'},
'dc:description': ['メディアワークス2007年刊の加筆、訂正',
'2010'],
'dc:extent': '444p',
'dc:identifier': [{'#text': '978-4-04-389803-9',
'@xsi:type': 'dcndl:ISBN'},
{'#text': '000010905866',
'@xsi:type': 'dcndl:NDLBibID'},
{'#text': '21795827',
'@xsi:type': 'dcndl:JPNO'},
{'#text': '104998700',
'@xsi:type': 'dcndl:NSMARCNO'}],
'dc:publisher': ['角川書店', '角川グループパブリッシング (発売)'],
'dc:subject': [{'#text': 'KH67',
'@xsi:type': 'dcndl:NDLC'},
{'#text': '913.6',
'@xsi:type': 'dcndl:NDC9'}],
'dc:title': '塩の街',
'dcndl:creatorTranscription': 'アリカワ, ヒロ, 1972-',
'dcndl:price': '667円',
'dcndl:publicationPlace': 'JP',
'dcndl:seriesTitle': '角川文庫 ; 16082',
'dcndl:seriesTitleTranscription': 'カドカワ ブンコ ; '
'16082',
'dcndl:titleTranscription': 'シオ ノ マチ',
'dcterms:issued': '2010.1',
'description': '<p>角川書店,2010,978-4-04-389803-9<p><ul><li>タイトル:塩の街</li><li>タイトル(読み):シオ '
'ノ マチ</li><li>責任表示:有川浩 '
'[著]</li><li>シリーズ名:角川文庫 ; '
'16082</li><li>シリーズ名(読み):カドカワ ブンコ '
'; '
'16082</li><li>NDC(9):913.6</li></ul>',
'guid': {'#text': 'https://ndlsearch.ndl.go.jp/books/R100000002-I000010905866',
'@isPermaLink': 'true'},
'link': 'https://ndlsearch.ndl.go.jp/books/R100000002-I000010905866',
'pubDate': 'Tue, 9 Nov 2021 01:03:52 +0900',
'rdfs:seeAlso': [{'@rdf:resource': 'https://www.library.city.sapporo.jp/licsxp-opac/WOpacMsgNewListToTifTilDetailAction.do?tilcod=1008000245880'},
{'@rdf:resource': 'https://www.library.city.sapporo.jp/licsxp-opac/WOpacMsgNewListToTifTilDetailAction.do?tilcod=1008001179073'},
{'@rdf:resource': 'http://kensaku.lib.pref.tochigi.lg.jp/winj/opac/switch-detail-iccap.do?bibid=1101626332'},
{'@rdf:resource': 'https://www.lib.city.saitama.jp/bookdetail?num=2280410&ctg=1'},
{'@rdf:resource': 'https://www.lib.city.saitama.jp/bookdetail?num=2707391&ctg=1'},
{'@rdf:resource': 'https://www.library.city.chiba.jp/licsxp-opac/WOpacTifSchCmpdDispAction.do'},
{'@rdf:resource': 'https://opac.lib.city.yokohama.lg.jp/winj/opac/switch-detail-iccap.do?bibid=1110004412'},
{'@rdf:resource': 'https://www.library.city.kawasaki.jp/bookdetail?num=1938589&ctg=1'},
{'@rdf:resource': 'https://www.lib.sagamihara.kanagawa.jp/TOSHOW/asp/WwShousaiKen.aspx?FCode=1815838'},
{'@rdf:resource': 'https://www.library.pref.ishikawa.lg.jp/wo/opc_srh/srh_detail/1000001057582/'},
{'@rdf:resource': 'https://www.library-archives.pref.fukui.lg.jp/wo/opc_srh/srh_detail/1104898915/'},
{'@rdf:resource': 'https://www.library.pref.nagano.jp/licsxp-opac/WOpacMsgNewListToTifTilDetailAction.do?tilcod=1000000307777'},
{'@rdf:resource': 'https://www.toshokan.city.shizuoka.jp/licsxp-opac/WOpacMsgNewListToTifTilDetailAction.do?tilcod=1001101673266'},
{'@rdf:resource': 'https://www.library.city.nagoya.jp/licsxp-opac/WOpacMsgNewListToTifTilDetailAction.do?tilcod=1000910091766'},
{'@rdf:resource': 'https://www.library.city.nagoya.jp/licsxp-opac/WOpacMsgNewListToTifTilDetailAction.do?tilcod=1001710028790'},
{'@rdf:resource': 'https://web.oml.city.osaka.lg.jp/webopac_i_ja/0012007757'},
{'@rdf:resource': 'https://web.oml.city.osaka.lg.jp/webopac_i_ja/0014336116'},
{'@rdf:resource': 'https://www.lib-sakai.jp/licsxp-opac/WOpacMsgNewListToTifTilDetailAction.do?tilcod=1001000514569'},
{'@rdf:resource': 'https://www.lib-sakai.jp/licsxp-opac/WOpacMsgNewListToTifTilDetailAction.do?tilcod=1007000747377'},
{'@rdf:resource': 'http://www.lib.wakayama-c.ed.jp/winj/opac/switch-detail-iccap.do?bibid=1102121547'},
{'@rdf:resource': 'https://www2.library.pref.shimane.lg.jp/opac/switch-detail-iccap.do?bibid=1110066873'},
{'@rdf:resource': 'https://opac.libnet.pref.okayama.jp/licsxp-opac/WOpacMsgNewListToTifTilDetailAction.do?tilcod=1009812133453'},
{'@rdf:resource': 'http://www.library.city.hiroshima.jp/winj/opac/switch-detail-iccap.do?bibid=1103163814'},
{'@rdf:resource': 'https://www.library.pref.kagawa.lg.jp/winj/opac/switch-detail-iccap.do?bibid=1100336168'},
{'@rdf:resource': 'https://www.ehimetosyokan.jp/winj/opac/switch-detail-iccap.do?bibid=1101015440'},
{'@rdf:resource': 'https://opac.toshokan.city.fukuoka.lg.jp/licsxp-opac/WOpacTifSchCmpdDispAction.do'},
{'@rdf:resource': 'https://opac.miraionlibrary.jp/licsxp-opac/WOpacMsgNewListToTifTilDetailAction.do?tilcod=1000000832192'},
{'@rdf:resource': 'https://library.pref.oita.jp/winj/opac/switch-detail-iccap.do?bibid=1100493998'},
{'@rdf:resource': 'https://www.lib.pref.miyazaki.lg.jp/winj/opac/switch-detail-iccap.do?bibid=1101550275'},
{'@rdf:resource': 'https://www2.library.pref.kagoshima.jp/kento/opac/switch-detail-iccap.do?bibid=1110005350'},
{'@rdf:resource': 'https://ndlsearch.ndl.go.jp/books/R100000002-I000010905866'},
{'@rdf:resource': 'https://library.sapie.or.jp/cgi-bin/CN1MN1?S00101=J00DTL04&S00222=1762615'},
{'@rdf:resource': 'https://library.sapie.or.jp/cgi-bin/CN1MN1?S00101=J00DTL04&S00222=3788837'},
{'@rdf:resource': 'https://www.kanabun.or.jp/CARIN/CARINOPACLINK.HTM?ID=B00192023'},
{'@rdf:resource': 'https://ci.nii.ac.jp/ncid/BB0102421X'},
{'@rdf:resource': 'https://www.books.or.jp/book-details/04389803A00498100000'},
{'@rdf:resource': 'https://www.books.or.jp/book-details/9784043898039'}],
'title': '塩の街'},
5.最後に
何かの足しになれば幸いです。