はじめに
TechCommit Advent Calendar 2021 3日目を担当しますRyotaです!
よろしくお願いいたします。
pythonで機械学習を勉強するため、書籍「Pythonによるスクレイピング&機械学習 開発テクニック 」に沿って学習していました。
自然言語処理の章で学習用のデータを収集するため、青空文庫から夏目漱石などの作家の作品を一括ダウンロードする必要がありました。
一括ダウンロードサイトとして「http://keison.sakura.ne.jp/」
からダウンロードするようにと書かれていましたが、現在はそのサイトは無い様子。
そこで、自分で青空文庫から夏目漱石の書籍をダウンロードして展開するスクリプトを作成しましたので、参考になればと思い記載させていただきます。
注意事項
青空文庫のUIが変わると、正常にスクレイピングができなくなります。
環境
windows 10
Python 3.10.1
bs4 0.0.1
beautifulsoup4 4.10.0
前提知識
- pythonの基本的知識
- html/CSSの基本的知識
まずはコード全部
ちょっと冗長な部分もありますが大目に見てください
import urllib.request as req
import urllib
import re
from bs4 import BeautifulSoup
import time
import os
import zipfile
#青空文庫 夏目漱石(person148)リストURL
url = "https://www.aozora.gr.jp/index_pages/person148.html#sakuhin_list_1"
card_nums =[]
save_folder = ".//作品//夏目漱石//"
if not os.path.isdir(save_folder):
os.makedirs(save_folder)
def get_card_num():
print(url)
try:
res = req.urlopen(url)
except urllib.error.HTTPError as e:
print('raise HTTPError')
print(e.reason)
except urllib.error.URLError as e:
print('raise URLError')
print(e.reason)
else:
print(res.status)
soup = BeautifulSoup(res, "html.parser")
first_ol_element = soup.find('ol')
for element in first_ol_element.find_all('li'):
sakuhin = element.text
#print(sakuhin)
title_name = re.search(r'(.*)(()',sakuhin)
#print(title_name.group(1))
card_num =re.search(r'作品ID:([\d:]+)',sakuhin)
#print(card_num.group(1))
card_nums.append(card_num.group(1))
get_card_num()
file_names = []
for card_num in card_nums:
print(card_num)
card_url = "https://www.aozora.gr.jp/cards/000148/card" + str(card_num) + ".html"
print(card_url)
try:
res = req.urlopen(card_url)
except urllib.error.HTTPError as e:
print('raise HTTPError')
print(e.reason)
continue
except urllib.error.URLError as e:
print('rase URLError')
print(e.reason)
continue
else:
print(res.status)
soup = BeautifulSoup(res, "html.parser")
download_table = soup.find('table', {'class':'download'})
#print(download_table)
download_path = download_table.select_one("tr:nth-of-type(2) td:nth-of-type(3)").get_text()
#print(download_path)
file_names.append(download_path)
time.sleep(1)
save_folder = ".//作品//夏目漱石//"
download_folder = save_folder + "zip//"
if not os.path.isdir(download_folder):
os.makedirs(download_folder)
for file_name in file_names:
print(file_name)
download_file_url = "https://www.aozora.gr.jp/cards/000148/files/" + file_name
local = download_folder + file_name
if not os.path.exists(local):
print("{0}のZIPファイルをダウンロード".format(file_name))
try:
download_data = urllib.request.urlopen(download_file_url).read()
except urllib.error.HTTPError as e:
print('raise HTTPError')
print(e.reason)
continue
except urllib.error.URLError as e:
print('rase URLError')
print(e.reason)
continue
else:
print(res.status)
res.close()
with open(local, mode="wb") as f:
f.write(download_data)
time.sleep(1)
else:
print("{0}のファイルはダウンロード済みです。".format(file_name))
zip_files = os.listdir(download_folder)
unzip_folder = save_folder + "unzip//"
if not os.path.isdir(unzip_folder):
os.makedirs(unzip_folder)
unzip_filenames = []
for zip_file in zip_files:
if ".zip" in zip_file:
print("{0}のファイルを解凍します。".format(zip_file))
zip_file_path = download_folder + zip_file
with zipfile.ZipFile(zip_file_path, 'r') as z:
for info in z.infolist():
info.filename = info.filename.encode('shift_jis').decode('utf-8')
z.extract(info, path=unzip_folder)
unzip_filenames.append(info.filename)
utf8_folder = save_folder + "utf8//"
if not os.path.isdir(utf8_folder):
os.makedirs(utf8_folder)
for unzip_filename in unzip_filenames:
if os.path.isfile(unzip_folder + unzip_filename):
if not os.path.isfile(utf8_folder + unzip_filename):
sr_file = open((unzip_folder + unzip_filename), 'r',encoding='shift_jis')
dt_file = open((utf8_folder + unzip_filename), 'w',encoding='utf-8')
for row in sr_file:
dt_file.write(row)
sr_file.close
dt_file.close
print("{0}ファイルの文字コードをUTF8に変換しました。".format(unzip_filename))
else:
print("{0}ファイルは既に文字コード変換されています。".format(unzip_filename))
else:
print("{0}ファイルが存在しません。".format(unzip_filename))
出力先
下記の場所に各ファイルが作成されます。
このコードを実行したディレクトリを基準としています。
- 作品
- 夏目漱石
- unzip (ダウンロード後、解凍したファイル(SJIS))
- utf8 (ダウンロード後、解凍し文字コードを変更したファイル(UTF8))
- zip (ダウンロードしたファイル)
- 夏目漱石
青空文庫の構成
青空文庫の構造は下記のようになっています。
- 作家別の作品一覧(作品名と作品ID)
- ex) 夏目漱石の作品一覧 https://www.aozora.gr.jp/index_pages/person148.html#sakuhin_list_1
- 作品ID
- 作品のページ
- 作品ダウンロードURL
作品ファイルはzipで圧縮されています。
文字コードはSJISになっています。
コードの構成
作品一覧ページから各作品ID(card_nums)を取得
#青空文庫 夏目漱石(person148)リストURL
url = "https://www.aozora.gr.jp/index_pages/person148.html#sakuhin_list_1"
def get_card_num():
print(url)
try:
res = req.urlopen(url)
except urllib.error.HTTPError as e:
print('raise HTTPError')
print(e.reason)
except urllib.error.URLError as e:
print('raise URLError')
print(e.reason)
else:
print(res.status)
soup = BeautifulSoup(res, "html.parser")
first_ol_element = soup.find('ol')
for element in first_ol_element.find_all('li'):
sakuhin = element.text
#print(sakuhin)
title_name = re.search(r'(.*)(()',sakuhin)
#print(title_name.group(1))
card_num =re.search(r'作品ID:([\d:]+)',sakuhin)
#print(card_num.group(1))
card_nums.append(card_num.group(1))
get_card_num()
作品ID(card_nums)をもとに作品ダウンロードリンク(file_names)を取得
for card_num in card_nums:
print(card_num)
card_url = "https://www.aozora.gr.jp/cards/000148/card" + str(card_num) + ".html"
print(card_url)
try:
res = req.urlopen(card_url)
except urllib.error.HTTPError as e:
print('raise HTTPError')
print(e.reason)
continue
except urllib.error.URLError as e:
print('rase URLError')
print(e.reason)
continue
else:
print(res.status)
soup = BeautifulSoup(res, "html.parser")
download_table = soup.find('table', {'class':'download'})
#print(download_table)
download_path = download_table.select_one("tr:nth-of-type(2) td:nth-of-type(3)").get_text()
#print(download_path)
file_names.append(download_path)
time.sleep(1)
作品ダウンロードリンク(file_names)から作品をダウンロード
for file_name in file_names:
print(file_name)
download_file_url = "https://www.aozora.gr.jp/cards/000148/files/" + file_name
local = download_folder + file_name
if not os.path.exists(local):
print("{0}のZIPファイルをダウンロード".format(file_name))
try:
download_data = urllib.request.urlopen(download_file_url).read()
except urllib.error.HTTPError as e:
print('raise HTTPError')
print(e.reason)
continue
except urllib.error.URLError as e:
print('rase URLError')
print(e.reason)
continue
else:
print(res.status)
res.close()
with open(local, mode="wb") as f:
f.write(download_data)
time.sleep(1)
else:
print("{0}のファイルはダウンロード済みです。".format(file_name))
ダウンロードしたzipファイルを解凍
for zip_file in zip_files:
if ".zip" in zip_file:
print("{0}のファイルを解凍します。".format(zip_file))
zip_file_path = download_folder + zip_file
with zipfile.ZipFile(zip_file_path, 'r') as z:
for info in z.infolist():
info.filename = info.filename.encode('shift_jis').decode('utf-8')
z.extract(info, path=unzip_folder)
unzip_filenames.append(info.filename)
解凍した作品ファイルの文字コードをUTF8に変換
for unzip_filename in unzip_filenames:
if os.path.isfile(unzip_folder + unzip_filename):
if not os.path.isfile(utf8_folder + unzip_filename):
sr_file = open((unzip_folder + unzip_filename), 'r',encoding='shift_jis')
dt_file = open((utf8_folder + unzip_filename), 'w',encoding='utf-8')
for row in sr_file:
dt_file.write(row)
sr_file.close
dt_file.close
print("{0}ファイルの文字コードをUTF8に変換しました。".format(unzip_filename))
else:
print("{0}ファイルは既に文字コード変換されています。".format(unzip_filename))
else:
print("{0}ファイルが存在しません。".format(unzip_filename))
最後まで見てくださりありがとうございました。