📚

技術書の最新の書誌情報をメールで受け取る

2021/10/03に公開

プログラムを書く上で技術の進歩が続いており知識のアップデートは欠かせません。Pythonを使って、特定キーワードの最新書誌をメールで受け取り、書籍を探す手間をちょっと減らします。

https://github.com/rmc8/bibliography_alert

代替品がないか

いくつかありそうでした。

主にiOSアプリを中心にあげましたが、Android版もあったり、そもそもhontoのようにOSが関係ないものもあったり色々です。これらの機能で満足できれば、わざわざコードを読み書きする手間もなくなります。
ただ、アラートを拾ってくれる範囲が異なったり、有料だったり、広告付きだったり。アプリごとに特色や相性もあり、そもそもiOS系の端末もないよ!という方もいらっしゃると思います。
Pythonでいろいろ試してみたい方や、純粋に最新書誌を受け取る機能に興味がある方に読み進めることをオススメします。

やること

おおまか以下のことをやります。

  • 登録済みの書誌をデータベースから取得する
  • 設定したキーワードで最新の書誌を検索する
  • 国立国会図書館のAPIから最新の書誌情報を取得する
  • データベースの書誌情報をつかって、アラート済みの書籍を除外する
  • アラートする書籍がなければここでプログラムを終了する
  • 書籍用のコード(ISBN)を追加取得し、Amazonのリンクを生成する
  • 最新の書籍をHTML形式のテーブルにまとめる
  • Gmailでアラートを送る
  • アラート済みの書誌をデータベースに登録する

ライブラリ

  • 標準
    • time
    • typing
    • sqlite3
    • os
    • ssl
    • smtplib
    • email
    • datetime
  • 外部
    • pandas
    • bs4
    • lxml
    • requests
    • PyYAML
  • ローカル(ユーザー定義)
    • SQLite操作用のクラス
    • 国立国会図書館のAPIの操作をするクラス
    • YAMLのデータを取得する用のクラス
    • Gmailを操作する用のクラス

動作環境

  • Python3.8以降
  • 筆者はWindows10でのみ実行しました

とりあえず使いたい!

コードについては後述に。使う手順としては以下の通りです。

  • GitHubから一式をCloneする
  • requirements.txtを使いライブラリを導入する
  • 設定ファイルを編集する
  • main.pyを実行する

プログラムの導入

GitHubから直接Downloadいただいても大丈夫ですが、コマンドラインを使うとライブラリのインストールまで簡単にできます。

$ git clone https://github.com/rmc8/bibliography_alert.git
$ cd bibliography_alert
$ pip install -r requirements.txt

設定ファイルの編集

設定ファイルは./settings/config.ymlに入っています。以下のように入力してください。

settings:
  api:
    keywords:
      - Python     # - {Word} のように書くと
      - JavaScript # 検索するワードを複数設定できます
      - Go言語     # この場合はPython, JavaScript, Go言語がアラート対象です
    params:
      - title # API仕様に応じて変更できますが基本はそのままでOKです
      - description
  google:
    account:
      user: kirakira?@gmail.com # 手持ちのGoogleアカウント
      password: xyza1234bcde5678 # 後述にて
    gmail:
      to: kirakira?@gmail.com,pikapika!@gmail.com # 任意のアドレス(カンマ区切り)
      cc: kirakira?@gmail.com # 1つだけでもOK
      bcc: "" # 空文字はダブルクォーテーション2つか空欄
      subject: "[BibliographyAlert]書誌アラート" # メールの件名

Googleアカウントのパスワード

Googleのメール送信用サーバーの使用にあたって、通常のパスワードではアカウント認証ができません。以下のGoogle公式のドキュメントを参考にして、アプリパスワードを生成してください。生成したアプリパスワードを、google > account > passwordの値に設定してください。

https://support.google.com/accounts/answer/185833?hl=ja

実行

main.pyをコマンドラインかダブルクリックで実行します。

$ python main.py

Alert

alert

文字通りAlertなので、ちょっとでも危機感をもって(?)勉強するきっかけになると良いのかなと思います。ここまでいけば動作は大丈夫です。

コードの解説

要所をつまんで書きます。

データベースの操作

module: https://github.com/rmc8/bibliography_alert/blob/main/pkg/db.py

SQLiteクラスを使い操作します。このプログラム用にメソッド内に直接SQLのQueryを埋め込んで、何も考えず使えるようにしています。./db/bibliography.dbがリポジトリ内にありますが、テーブルはbibliographyのみです。このテーブルの構成は以下の通りです。

column type description
title TEXT 書籍の名前
author TEXT 著者の名前
keyword TEXT 検索ワード
isbn TEXT 書籍のISBN

このまま流用も難しい気もしますが、コードの使い方は以下の通りです。

from pandas import DataFrame

from pkg.db import SQLite

sqlite_db = SQLite(path="./db/bibliography.db") # テーブルのデータを全取得
try:
	db_df: DataFrame = sqlite_db.get_table()
	...
	records: list = [
		["Sapphire言語入門", "杉本なにがし" , "Sapphire", "ISBN1"]
		["Effective Amethyst", "森本なんとか", "Amethyst", "ISBN2"]
	]
	sqlite_db.insert_many(records=records)
finally:
	sqlite_db.close()

スクレイピング

module: https://github.com/rmc8/bibliography_alert/blob/main/pkg/ndl.py

国立国会図書館で公開されているAPI(仕様書)にしたがっています。検索用のAPIでキーワードや日付でフィルターをしつつ、最新の書誌情報を取得します。

"https://iss.ndl.go.jp/api/sru?operation=searchRetrieve&query={param}%3d%22{keyword}%22%20AND%20from%3d%22{dt:%Y-%m}"

初期値の場合、{param}にはtitledescriptionが代入されます。{keyword}にキーワードを代入して、書籍名や書籍の説明文に特定のキーワードが含まれる書籍を取得します。また最新の書籍に絞り込むため、プログラムの実行日-90日をした結果を{dt:%Y-%m}に代入して、年月で最新書誌に絞り込みます。

そののちに、取得した書籍名をOpenSearch APIに流し込み、対応するISBNを取得します。

それぞれのAPIでResponseはXMLです。BeautifulSoupとlxml-xmlを使えば、HTMLと同様にデータの抽出ができます。

ISBN13をISBN10に変換する

Amazonの商品ページのURLはISBN10が採用されています。そのため、13桁のISBNを10桁形式に変換します。

https://ninoseki.hatenadiary.org/entry/20090525/1243236925
変換には↑を参考にしました。最初の3桁と最後の1桁以外を取り出して、(桁番号*その桁の数値)の総和を算出します。11 - (算出した総和 / 11)のあまりを求めます。求めた値が10であればX11であれば0、それ以外はその値をチェックデジットとして、最初に取り出した9桁の番号の末尾にチェックデジットを追加します。

def _check_digit(cd_sum: int) -> str:
    cd_num: int = 11 - (cd_sum % 11)
    if cd_num == 10:
        return "X"
    elif cd_num == 11:
        return "0"
    return str(cd_num)


def isbn13to10(isbn13: str) -> str:
    isbn_base = isbn13[3:12]
    cd_sum: int = sum([int(n) * (10 - i) for i, n in enumerate(isbn_base)])
    cd: str = _check_digit(cd_sum)
    return f"{isbn_base}{cd}"

Gmailで送信する

module: https://github.com/rmc8/bibliography_alert/blob/main/pkg/gmail.py

世の中にGmailで便利に送信できるライブラリがある気もしつつ、Gmail以外での流用もほんのり考慮してモジュールを書きました。大まかに使い方は以下の通りです。

from pkg.gmail import Gmail

gm = (
	from_="piyopiyo$@gmail.com",
	to="pikapika!@gmail.com,kirakira?@gmail.com",
	cc="",
	bcc="",
	subject="TEST_MAIL",
	body="Pythonで自動送信のテスト",
)
try:
	gm.login(
		user="piyopiyo$@gmail.com",
		password="xyza1234bcde5678", # アプリパスワード
	)
	gm.send()
finally:
	gm.close()

Gmailクラスを呼び出す際に、SMTPのhostやポート番号を変更できるので、適切なクラス名に変えるなどして他の値を設定すると、Gmail以外でも活用できるかもです。

その他、add_attachmentメソッドでファイルパスを指定すると、ファイルの添付もできます。

gm.add_attachment(r"C\:attachment\kirakira.png")

細かい変換はクラスの中に隠しているので、気軽にメール送信用にご活用いただけると良いのかなと思っています。

まとめ

技術は絶えず進歩しています。一方で、急激に進歩している風でもないように思われます。無理なく少しずつ本やドキュメントを読み、新しいコードを書きましょう!
読むべき本を探す点などで本ページが貢献できましたら幸いです。

Discussion