python による scraping

(2024-05-02)

ある web ページのある html 要素の、ある class に書かれている内容を読み込んでデータベースに保存する python です。

テーブル名は tbl、カラム名は col の一つだけとします。

python

ある web ページの p 要素の foo という class 名に書かれている内容を取得して、mysql に書き込みます。

import urllib.request
import mysql.connector
from bs4 import BeautifulSoup
class Examtxt():
def __init__( self ):
self.url = "https://hoge"
self.question_list = []
self.host = "localhost"
self.mysqldb = 'dbname'
self.username = 'root'
self.password = 'pass'
def extract_text( self ):
res = urllib.request.urlopen(self.url)
soup = BeautifulSoup(res, 'html.parser')
name = soup.find_all("p", class_="foo")
for t in name:
self.question_list.append(t.text)
def insertDB(self):
connection = mysql.connector.connect(
host=self.host,
user=self.username,
password=self.password,
database=self.mysqldb
)
cursor = connection.cursor()
insert_query = "INSERT INTO tbl (col) VALUES (%s)"
for item in self.question_list:
data = (item,)
print(data)
cursor.execute(insert_query, data)
connection.commit()
cursor.close()
connection.close()
if __name__ == '__main__':
extxt = Examtxt()
extxt.extract_text()
extxt.insertDB()

self.question_list に保存されるのはリストで、それを mysql に書きこむにはタプルにする必要があるようです。

リストとタプルと辞書

python には配列のようなものが 3 つあるのですが、時に混乱します。

1. リストは通常の配列で、内容の変更ができる。
2. タプルも配列だが、内容が変更できない。
3. 辞書は連想配列。

と、ざっくり考えていいようです。

正規表現を使っていろいろと

上のコードは、東京アカデミーに提示されている看護師国家試験問題をデータベース化するためのものですが、 オリジナルのサイトが素晴らしいので scraping する必要はそこまでないのですが、キーワードで検索するためにはやはりデータベース化する必要があります。

基本的には東京アカデミーのサイトで勉強すればいいと思いますが、補助的な意味で検索機能で調べたりするためにいろいろ操作します。

まず、行頭の半角スペースを削除します。

ev = re.sub( r'^ ', '', eq.text )

問題番号を抽出します。行頭にある 3 桁以下の数字です。

qn = re.match( r'^\d{,3}', ev )

次に問題文を抽出します。全体から、問題番号と全角スペースを削除します。

qv = re.sub( r'^\d{,3} ', '', ev )

文中にある 2 つ以上の半角スペースを削除します。

qv = re.sub( r'\s{2,}', '', qv )

問題文が複数の p タグに別れている場合があるので、そういう時は問題文を前の問題文に加えます。

if len(qn.group(0)) == 0:
self.question_list[-1][1] += '\r\n' + qv
else:
el = [qn.group(0), qv]
self.question_list.append( el )
previous_qv = qv

最終的には以下のようになりました。

def extract_text( self ):
res = urllib.request.urlopen(self.url)
soup = BeautifulSoup(res, 'html.parser')
allq = soup.find_all("p", class_="foo")
previous_qv = ''
for eq in allq:
ev = re.sub( r'^ ', '', eq.text )
qn = re.match( r'^\d{,3}', ev )
qv = re.sub( r'^\d{,3} ', '', ev )
qv = re.sub( r'\s{2,}', '', qv )
if len(qn.group(0)) == 0:
self.question_list[-1][1] += '\r\n' + qv
else:
el = [qn.group(0), qv]
self.question_list.append( el )
previous_qv = qv

こうすることによって、問題番号と問題文が記録されます。