前回はゆっくり(SofTalk)に辞書登録しつつ読み上げさせることに成功しました
今回は、勉強のために公式ドキュメントや関連する記事を読みつつ、前回のコードを改善していきます
図書カードからURL取得まで
改善したコード
import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin
def aozoraurl(base_url):
page = requests.get(base_url)
soup = BeautifulSoup(page.text, 'lxml')
xhtml_relative_url = soup.select('table.download a[href*=".html"]')[0].get('href')
zipdl_relative_url = soup.select('table.download a[href*=".zip"]')[0].get('href')
xhtml_url = urljoin(base_url, xhtml_relative_url)
zipdl_url = urljoin(base_url, zipdl_relative_url)
return xhtml_url, zipdl_url
if __name__ == '__main__':
print(aozoraurl("https://www.aozora.gr.jp/cards/000879/card85.html"))
Beautiful Soup 4
Beautiful Soup はHTMLやXMLファイルからデータを取得するPythonのライブラリです。
Beautiful Soup 4.2.0 Doc. 日本語訳より
BeautifulSoup
コンストラクタにHTMLドキュメントを渡すことで、その構造を解析します
from bs4 import BeautifulSoup
soup = BeautifulSoup(page.content, 'lxml')
'lxml'
はパーサ(構文解析器)を指定しています
HTMLパーサはPython標準(Batteries included)の html,parser
, 高速な lxml
, 非常に寛大な html5lib
から選択できます
公式ドキュメントでは lxml
が推奨されているようです
If you can, I recommend you install and use lxml for speed.
Beautiful Soup 4.9.0 documentation より
Requests
Requestsは、人が使いやすいように設計されていて、Pythonで書かれている Apache2 Licensed ベースのHTTPライブラリです。
Requests: 人間のためのHTTP より
requests.get()
にURLを渡すことで、Response
オブジェクトが返されます
Response
の中身を取得するのには、.text
と .content
が使えます
import requests
r = request.get(URL)
r.content # バイナリデータを取得
r.text # テキストデータを取得
……バイナリとテキストの違いがわからないのですが、ここ1によるとHTMLやXMLには.text
、画像やPDFには.content
だそうです
2種類のURL (XHTML / zip)取得
要素取得の方法は色々ありますが、CSSセレクターが一番汎用性があると思います。
If you want to search for tags that match two or more CSS classes, you should use a CSS selector:
css_soup.select("p.strikeout.body")
# [<p class="body strikeout"></p>]
青空文庫図書カードのページからそれぞれのURLを取り出します
soup.select
の返り値はlistであることに注意しましょう
xhtml_url = soup.select('table.download a[href*=".html"]')[0].get('href')
zip_url = soup.select('table.download a[href*=".zip"]')[0].get('href')
urljoin
青空文庫図書カードのページから、それぞれのページへのリンクは相対リンクで記載されています
urljoin
を用いて元のURLと合成し、絶対リンクに戻します
urllib.parse.urljoin(base, url, allow_fragments=True)
"基底 URL"(base)と別のURL(url)を組み合わせて、完全な URL ("絶対 URL") を構成します。
urllib.parse --- URL を解析して構成要素にする より
>>> from urllib.parse import urljoin
>>> urljoin('http://www.cwi.nl/%7Eguido/Python.html', 'FAQ.html')
'http://www.cwi.nl/%7Eguido/FAQ.html'
return a, b
複数の返り値(今回はURL2つ)を返したいときは、このように書くのが最も簡潔なようです
Pythonでは、単純にカンマ区切りでreturnするだけで文字列だろうが数値だろうがまとめて返せる。
Pythonの関数で複数の戻り値を返す方法 | note.nkmk.me より
この場合返り値はタプルになります。
XHTMLページからのルビ抽出まで
改善したコード
from bs4 import BeautifulSoup
import requests
import jaconv
def aozoraruby(xhtml_url):
page = requests.get(xhtml_url)
soup = BeautifulSoup(page.content, 'lxml')
_ruby = soup.select("ruby")
_rubylist = [i.get_text().replace(")", "").split("(") for i in _ruby]
for index, item in enumerate(_rubylist):
_rubylist[index][1] = jaconv.kata2hira(item[1])
return _rubylist
if __name__ == '__main__':
print(aozoraruby("https://www.aozora.gr.jp/cards/000119/files/624_14544.html"))
ルビの抽出
青空文庫XHTML本文からrubyタグ以下の文字を抽出します
.select("ruby")
が一番簡単だと思います
とりあえず取得した内容を確認します
.get_text()
で文字列部分を抽出できますが、リストには適用できないのでfor文で回します
_ruby = soup.select("ruby")
for i in _ruby:
print(i.get_text())
# 重(かさ)
# 死骸(しがい)
# 麻利耶(マリヤ)
# ︙
漢字(ルビ)
の形で出力されます
ルビのリスト作成
取得したルビをリストにします。
単純な ["漢字(ルビ)", "漢字(ルビ)", ...]
のリストでは使いづらいので、[["漢字", "よみがな"], ["漢字", "よみがな"], ...]
の二次元配列を作成します
for文でリストを作成する際、これまではfor文の前で空リストを作成してそこに要素を追加していました
しかし、リスト内包表記という方法を使えば一文で作成できるようです 2 3
x = [i.get_text().replace(")", "").split("(") for i in _ruby]
# [['重', 'かさ'], ['死骸', 'しがい'], ['麻利耶', 'マリヤ'],...]
カタカタをひらがなに
SofTalkに辞書登録するために、読み仮名がカタカナのものをひらがなにします
こちらのQiita記事によると、今回の用法ではjaconvが適しているようです
jaconv (Japanese Converter) はひらがな・カタカナ・全角・半角の文字種変換を高速に行います。 Pythonのみで実装されているので、Cコンパイラが使えない環境でも利用できます。
jaconv/README_JP.rst at master · ikegami-yukino/jaconv · GitHub より
for index, item in enumerate(_rubylist):
_rubylist[index][1] = jaconv.kata2hira(item[1])
# [['重', 'かさ'], ['死骸', 'しがい'], ['麻利耶', 'まりや'],...]
-
What is the difference between 'content' and 'text'
https://stackoverflow.com/questions/17011357/what-is-the-difference-between-content-and-text ↩ -
内包表記を使ってリストの作成を簡潔に書く - Qiita
https://qiita.com/tag1216/items/040e482f9844805bce7f ↩ -
リスト内包表記の使い方 | note.nkmk.me
https://note.nkmk.me/python-list-comprehension/ ↩