ビジネスパーソン・ガジェット置場 empty lot for business

営業や仕事、それに伴う生活を便利に楽にするツール、ガジェットを作ります。既にあるツールも自分用にカスタマイズ。

図書館蔵書検索アプリ【python + カーリル】

図書館に行く前に読みたい本が取り扱われているか、または、貸し出し中になっていないかなどを調べることができるガジェットです。行きたいエリアの図書館情報も調べることができ、マップ表示します。また、調べたい項目は分かるけど、本のタイトルやどんな本があるか分からない場合は、キーワードで検索も可能です。

f:id:kslabo51:20220327203319j:plain

今回のガジェットはこういう声に対応
「図書館に調べ物に行かなければいけないんだけど、調べたい本が今から行く図書館にあるだろうか。。行ったはいいが本がなかったら無駄足だし。事前に貸し出し可能な本があるかを調べて図書館に行きたい」

f:id:kslabo51:20220327203409p:plain

このガジェットでできることはこちら

  • 行きたいエリアの図書館の情報が確認できます。
  • 図書館の情報は地図でも表示します。
  • キーワードで本を検索できます。
  • どの図書館がその本を取り扱っており、どの図書館が貸し出し中で、どの図書館が借りることができるか調べることができます。

注意点はこちら

本の検索でISBN番号というものを使用します。ガジェット内でキーワードで検索して入手できます。
また、どの図書館が取り扱っているかを調べる際にシステムIDというIDも使用します。こちらも、ガジェット内で図書館を検索して入手できます。

評価(自己)

役立ち度  ★★★★(良し)
効率化   ★★★★(良し)
ミス防止  ★★★(平均)
楽しさ   ★★★(平均)
操作性   ★★(悪し)

※在庫状況の検索でISBN番号やシステムIDというあまり聞き慣れない識別番号を使用します。ガジェット内で取得可能にしていますが、自動変換にはしていないため慣れる必要がありです。

実行環境

使用環境    streamlit
使用言語    python
使用ライブラリ pandas、BeautifulSoup、streamlit

コード

import requests
import pandas as pd
from bs4 import BeautifulSoup
import streamlit as st
from streamlit import caching
import json

st.title('蔵書検索アプリ')

st.sidebar.write('### 図書館検索')
pref = st.sidebar.text_input('都道府県を入力してください', value="")
city = st.sidebar.text_input('市区町村を入力してください', value="")
book_data = None

with open('secret.json', 'r') as f:
    api_key = json.load(f)

def library_search(api_key, pref, city):
    LIBRARY_URL = 'https://api.calil.jp/library'
    API_KEY = api_key['API_KEY']
    params = {
        'appkey': API_KEY,
        'pref': pref,
        'city': city
    }

    res = requests.get(LIBRARY_URL, params)
    soup = BeautifulSoup(res.text, 'lxml')

    df = pd.DataFrame()
    libralies = soup.find_all('formal')
    df['図書館名'] = [library.text for library in libralies]

    libids = soup.find_all('libid')
    df['図書館ID'] = [libid.text for libid in libids]

    addresses = soup.find_all('address')
    df['住所'] = [address.text for address in addresses]

    tels = soup.find_all('tel')
    df['電話番号'] = [tel.text for tel in tels]

    geocodes = soup.find_all('geocode')
    longs = []
    lats = []
    for geocode in geocodes:
        longs.append(float(geocode.text.split(',')[0]))
        lats.append(float(geocode.text.split(',')[1]))
    df['緯度'] = lats
    df['経度'] = longs

    urls = soup.find_all('url_pc')
    df['URL'] = [url.text for url in urls]

    systemids = soup.find_all('systemid')
    df['システムID'] = [systemid.text for systemid in systemids]
    df_map = df[['緯度', '経度']]
    df_map.columns = ['lat', 'lon']
    
    return df, df_map

if pref != "" and city != "":
    libdata = library_search(api_key, pref, city)[0]
    st.dataframe(libdata)
    map_data = library_search(api_key, pref, city)[1]
    st.map(map_data)
    
st.sidebar.write('### 本検索')
title = st.sidebar.text_input('探したい本のタイトルを入力してください', value="")

# 検索直後のページのみ情報取得
def book_search(title):
    OPEN_URL = f'https://api.calil.jp/openurl?rft.btitle={title}'
    res_title = requests.get(OPEN_URL)

    soup2 = BeautifulSoup(res_title.text, 'lxml')
    books = soup2.find_all('div', attrs={'class': 'book'})
    li = []
    for book in books:
        d = {}
        d['タイトル'] = book.find('a', attrs={'class': 'title'}).text
        d['ISBN'] = book.find('a', attrs={'class': 'title'})['href'].split('/')[2]
        li.append(d)
    book_data = pd.DataFrame(li)
    return book_data

if title != "":
    book_data = book_search(title)
    st.dataframe(book_data)
    
st.sidebar.write('### 蔵書有無検索')
isbn = st.sidebar.text_input('探したい本のISBNを入力してください', value="")
systemid = st.sidebar.text_input('探したいエリアのシステムIDを入力してください', value="")

def status_search(api_key, isbn, systemid):
    isbn = isbn
    systemid = systemid
    API_KEY = api_key['API_KEY']

    CHECK_URL = f'https://api.calil.jp/check?appkey={API_KEY}&isbn={isbn}&systemid={systemid}&format=json&callback=no'

    res = requests.get(CHECK_URL)
    info = res.json()
    return info

if isbn != "" and systemid != "":
    info = status_search(api_key, isbn, systemid)
    if book_data is not None:
        book_title = book_data[book_data['ISBN']==isbn]['タイトル'][0]
        st.write('#### ■ タイトル ■')
        st.write(f'{book_title}')
    try:
        st.write('#### ■ 貸し出し状況 ■')
        for key, value in info['books'][isbn][systemid]['libkey'].items():
            st.write(f'{key}が{value}です')
    except KeyError:
        print('情報が確認できません。後ほどお試しください')
    
    
    if info is not None:
        link = f'[カーリルで確認](https://calil.jp/book/{isbn})'
        st.markdown(link, unsafe_allow_html=True)
    
    st.sidebar.write('別の本を検索する場合は下記をクリック')
    if st.sidebar.button('再検索'):
        info = ""