Bo○kQから学生を守りたい

プログラミング

お久しぶりです,ぴのです.新年度が始まってから講義やら研究やらで忙しくなってきました.講義はオンラインで開講されるものがほとんどですが,研究室で受ける方が捗るし学食でメシを食えるので毎日足を運んでいます.

さて,久しぶりに講義を受けるとたまに登場するのが「Bo○kQ(旧:Bo○kRoll)」です.知らない人のために説明すると,大学などで講義スライドなどを閲覧することのできるwebビューアのことです.Bo○kQ自体はメモ機能や栞機能などがあって便利といえば便利なのですが(使ったことないけど),このビューアには「スライドをダウンロードできない」という学生にとって致命的な欠陥があります.なぜそんな欠陥があるかというと,「教材をダウンロードできない」という機能がBo○kQの目的の一つだからです(参考).

今回はそんなBo○kQからPDFを頂戴するプログラムを書いてみました.ちなみに水色の研究MoodleのBo○kRollは仕組みが全く違っているようでうまくいきません.

注意

そもそもBo○kQは「教材をダウンロードできない」ことが目的の一つであるアプリなのでそこから直接PDFを頂戴するという行為を行うのは一考の余地があります(参考).また,著作権法上の問題からもわりとグレーゾーンなので頂戴したPDFの取扱いには注意しましょう.何かあっても管理人は責任はとれないぞ.

実行環境

Python3で動作します.

事前準備

必要なライブラリは以下のコマンドでインストールできます.

pip install requests bs4 img2pdf tqdm

また,実行前に以下のようなsecrets.jsonファイルを作成して,bookq2pdf.pyと同じ階層に作成しておく必要があります.”id”にはSSO-KIDを,”passwd”にはパスワードを記述してください.

{
    "id":"0000000000",
    "passwd":"XXXXXXXXXXX"
}

ファイル構造はこんな感じ.

  • bookq
    • main.py
    • bookq2pdf.py
    • secrets.json
    • (output.pdf)

プログラム全体

import bookq2pdf

bookq = bookq2pdf.Bookq()
bookq.login()
bookq.get_pdf(book_url='https://bookq.s.kyushu-u.ac.jp/book/view?contents=...', page_num=10)
import re
import time
import json

from tqdm import tqdm
import requests
from bs4 import BeautifulSoup
import img2pdf

class Bookq():
    URL = 'https://bookq.s.kyushu-u.ac.jp'
    def __init__(self):
        self._session = None
        self._imgs = []

    def login(self, secrets_file='secrets.json'):
        with open(secrets_file, 'r') as f:
            secrets = json.load(f)
        self._session = requests.session()
        login = self._session.get(f'{Bookq.URL}/login')
        soup = BeautifulSoup(login.text, 'html.parser')
        csrf = soup.select_one('input[name=_csrf]').get('value')
        login = self._session.post(f'{Bookq.URL}/login', data={'userid': secrets['id'], 'password': secrets['passwd'],'_csrf': csrf})

    def _bookq2jpg(self, book_id, page_num, sleep_time):
        for page in tqdm(range(1, page_num+1)):
            r = self._session.get(f'{Bookq.URL}/contents/unzipped/{book_id}_2/OPS/images/out_{page}.jpg', stream=True)
            if r.status_code == 200:
                self._imgs.append(r.content)
                time.sleep(sleep_time)
            else:
                break
        return

    def _jpg2pdf(self, file_name):
        with open(file_name,'wb') as f:
            f.write(img2pdf.convert(self._imgs))
        self._imgs.clear()

    def get_pdf(self, book_url, page_num, file_name='output.pdf', sleep_time=1):
        book_id = re.findall(r'contents=.+', book_url)[0].replace('contents=', '')
        try:
            self._bookq2jpg(book_id, page_num, sleep_time=sleep_time)
            self._jpg2pdf(file_name)
        except Exception as e:
            print(f'\n{e}')
        else:
            print(f'\n\"{file_name}\" is generated.')

使い方

  1. main.py内の関数に適切な引数を設定する.
    Bookqインスタンスの持つメソッドの詳細については次の項を参照してください.
  2. python3 main.pyを実行する.

メソッド

login()

login(
    secrets_file='secrets.json'
)

BookQへログインを行うメソッド.

Args
secrets_fileIDとパスワードを保存しているJSONファイルへのパス

get_pdf()

get_pdf(
    book_url, page_num, file_name='output.pdf', sleep_time=1
)

スライドをPDF形式で取得するメソッド.

Args
book_urlスライドが表示されているビューワーのURL
page_num取得するスライドの枚数を指定(システムエラー回避のため)
file_name出力するPDFの名前
sleep_timeスライド取得毎に入るスリープの間隔(デフォルトは1秒)

おわりに

管理人のゴールデンウィークは全くゴールデンじゃないらしいぞ

コメント

タイトルとURLをコピーしました