生成AIの新展開!?―学術研究支援用ボットを作ってみた。その(2)

前回記事の続きです。生成 AI が、いつの間にか新しい局面を迎えているように思います。問い合わせをするための文字数制限(正確に言えばトークンの制限)が大幅に増え、問い合わせの際に、前提知識として学術論文数十本、あるいは新書10冊くらいを読み込ませてから回答させることができるようになっています。これまでは「生成 AI が持つ知識」を問い合せる形になっていましたが、これによって、「こちらが持つ知識や情報を生成 AI に考えさせる」ことができるようになりつつあります。この流れがさらに進めば、今まではできなさそうだった有用性を発揮することができるようになるかもしれない、ということで、とりあえず今試せることをちょこちょことやってみています。

で、前回記事をみた人から、J-STAGEからPDFをダウンロードする方法についてのリクエストがありましたので、ちょこっと書いてみます。

生成AIに読み込ませる信頼できる情報源としての学術論文ですが、現在はJ-STAGEでたくさんのオープンアクセス論文が公開されています。これを雑誌単位でまるっと利用できれば、その学会が扱っている分野に関する比較的専門性の高い生成AIのRAGが構築できそうな感じです。なお、国際ジャーナルでやればもっと楽だ、とか、その方がよいのではないか、という話もあるのですが、J-STAGEに載っている学術雑誌には固有の良さがありますので、これはこれで重要なことです。

J-STAGEはAPIでのデータ公開を行っています。雑誌一つをまとめてまるっとダウンロードしたい時は、これを使うのが便利です。

というわけで、J-STAGEのAPIを使って、任意の雑誌の論文PDFをざっくりダウンロードするスクリプトを書いてみます。 J-STAGEに迷惑がかからないように、特に、利用規約はよく読んでからご利用ください。規約では大量ダウンロードは禁じられていますので、大量にならないように、サーバに大きな負荷がかかってしまわないように、よく気をつけてください。

import requests
from bs4 import BeautifulSoup
import urllib.parse
import os
import re
import sys
import time

def save_pdf(link, save_path):
        pdf_response = requests.get(link)
        content_disposition = pdf_response.headers.get('content-disposition')
        if content_disposition and 'filename=' in content_disposition:
                filename = content_disposition.split('filename=')[1]
                filename = filename.strip('"')  
        pdf_filename = filename
        pdf_save_path = os.path.join(save_path, pdf_filename)
        #print (pdf_save_path)
        if not os.path.isfile(pdf_save_path):
          with open(pdf_save_path, 'wb') as pdf_file:
            pdf_response = requests.get(link)
            pdf_file.write(pdf_response.content)
            print(f"Downloaded: {pdf_filename}")
        else:
            print ('skip:')
        


if len(sys.argv) > 2:
    save_directory = sys.argv[2]
    if not os.path.exists(save_directory):
        os.makedirs(save_directory)
else:
    print ("保存フォルダ名を2番目の引数に指定してください。")
    sys.exit()

journalurlapi = 'https://api.jstage.jst.go.jp/searchapi/do?service=2&cdjournal='+sys.argv[1]
response = requests.get(journalurlapi)
soup = BeautifulSoup(response.content, 'xml')

entries = soup.select("entry")
for entry in entries:
    eachvol = entry.find_all('volume')[0].get_text()
    volurl = 'https://api.jstage.jst.go.jp/searchapi/do?service=3&cdjournal=jpbs&vol='+eachvol
    eresponse = requests.get(volurl)
    eachsoup = BeautifulSoup(eresponse.content, 'xml')
    eentries = eachsoup.select('entry')
    for eentry in eentries:
        elink = eentry.select('link')[0].get('href')
        pdflink =  re.sub(r'_article/',r'_pdf/',elink)
        print (pdflink)
        save_pdf(pdflink, save_directory)
        time.sleep(1)

このスクリプトは、以下のように利用します。

$ python このスクリプト 雑誌のID 保存先フォルダ名

これで、PDFファイルは一通り入手できるはずです。そうしましたら、次は、OCRをかけるために、このPDFからJPG画像を全部取り出します。 こういうのは Pythonで一括処理するのが楽ですね。

from pdf2image import convert_from_path
import os
import glob
import re

pdfs = glob.glob("*.pdf")
for pdf in pdfs:
    pdfpath = 'jpgs/'+os.path.splitext(pdf)[0]
    if not os.path.isdir(pdfpath):
        os.mkdir(pdfpath)
    images = convert_from_path(pdf)
    for i, image in enumerate(images):
            image_path = f"{pdfpath}/p_{i+1}.jpg"
            image.save(image_path, "JPEG")
            print(f"Page {i+1} saved as {image_path}")

さあ、ここまでできたら、次はOCRですね。。。というのはまた次回に。