BeautifulSoupを使ってWikipedia上の記事からテキストを抽出してみました。
本記事の前半ではurllib
、後半ではRequests
を使ってWikipediaの記事を取ってきています。
環境
Wikipediaの記事から<p>で囲まれたテキストを抽出する
ライブラリ
必要なライブラリのインポート
import urllib.parse as parser
import urllib.request as request
from bs4 import BeautifulSoup
urllibを使ってWikipediaの記事をダウンロードします。
詳細はこちら。
Wikipediaの織田信長の記事をダウンロードしています。
link = "https://ja.wikipedia.org/wiki/"
with request.urlopen(link + parser.quote_plus("織田信長")) as response:
html = response.read().decode("utf-8")
htmlには織田信長の記事のHTML形式で書かれた文字列が入っています。
BeautifulSoup
BeautifulSoup関数を使ってHTMLで書かれた文字列を解析します。
BeautifulSoupには2つの引数を渡します。
soup = BeautifulSoup(html, "lxml")
soupはBeautifulSoupのオブジェクトとなっていて、いくつかの変数やメソッドが用意されています。
textを使うと、HTMLの形式で書かれていたものから全てのタグを取り除いて読みやすいテキストの形にしてくれます。
print(soup.text)
<p>で囲まれたテキストを取り出す
find_allメソッドを使えば指定したタグで囲まれた部分をリストの形で取り出すことができます。
p_tags = soup.find_all("p")
p_tagsには<p>と</p>で囲まれている部分が入っています。
例えばこんな感じです。
sample = p_tags[0]
print(sample)
"""
<p><b>織田 信長</b>(おだ のぶなが)は、<a href="/wiki/%E6%88%A6%E5%9B%BD%E6%99%82%E4%BB%A3_(%E6%97%A5%E6%9C%AC)" title="戦国時代 (日本)">戦国時代</a>から<a href="/wiki/%E5%AE%89%E5%9C%9F%E6%A1%83%E5%B1%B1%E6%99%82%E4%BB%A3" title="安土桃山時代">安土桃山時代</a>にかけての<a href="/wiki/%E6%AD%A6%E5%B0%86" title="武将">武将</a>・<a href="/wiki/%E6%88%A6%E5%9B%BD%E5%A4%A7%E5%90%8D" title="戦国大名">戦国大名</a>。<b><a href="/wiki/%E4%B8%89%E8%8B%B1%E5%82%91" title="三英傑">三英傑</a></b>の一人。
</p>
"""
textを使って本文だけを取り出します。
これでWikipediaからテキストを抽出することができました。
print(sample.text)
"""
織田 信長(おだ のぶなが)は、戦国時代から安土桃山時代にかけての武将・戦国大名。三英傑の一人。
"""
ちなみに、find_allメソッドを使うと、型は以下のようになっています。
p_tags = soup.find_all("p")
print(type(p_tags))
sample = p_tags[0]
print(type(sample))
print(type(sample.text))
Requestsを使ってみる
ここではrequests
を使ってWikipediaの記事をダウンロードし、Beautifulsoupを使って必要な情報を取り出してみます。
流れはこんな感じです。全体のソースコードは下に置いてあります。
- URLの用意。
requests.get(URL)
を使って指定したURLのページを取ってくる。
- htmlに変換。
- Beautifulsoupを使って必要な情報を取り出す。
以下のURLにダウンロードしたいWikipediaのタイトルを足します。
url = "https://ja.wikipedia.org/wiki/"
例えば、織田信長
の記事を取ってきたい場合は以下のようにします。
url = "https://ja.wikipedia.org/wiki/織田信長"
requests.get(URL)
で指定したURLのページを取ってきます。
import requests
url = "https://ja.wikipedia.org/wiki/織田信長"
response = requests.get(url)
htmlに変換します。
html = response.text
最後に前半部分でやったようにBeautifulsoupを使ってpタグで囲まれた部分を抽出します。
for p_tag in soup.find_all('p'):
text = "".join(p_tag.text.strip().split(" "))
import codecs
import re
import requests
from bs4 import BeautifulSoup
url = "https://ja.wikipedia.org/wiki/"
keyword_list = ["織田信長", "徳川家康", "豊臣秀吉",
"伊達政宗", "武田信玄", "上杉謙信",
"明智光秀", "島津義弘", "北条氏康",
"長宗我部元親", "毛利元就", "真田幸村",
"立花宗茂", "石田三成", "浅井長政"]
corpus = []
for keyword in keyword_list:
response = requests.get(url + keyword)
html = response.text
soup = BeautifulSoup(html, 'lxml')
for p_tag in soup.find_all('p'):
text = "".join(p_tag.text.strip().split(" "))
if len(text) == 0:
continue
text = re.sub(r"\[注釈[0-9]+\]", "", text)
text = re.sub(r"\[[0-9]+\]", "", text)
corpus.append(text)
print(*corpus, sep="\n", file=codecs.open("wiki.txt", "w", "utf-8"))
このコードでは複数の戦国大名の記事をダウンロードし、pタグで囲まれた部分を抽出しています。抽出したものを正規表現を使って前処理をしています。
最後に前処理したデータをprint()
を使ってファイルに書き込んでいます。
Q&A
BeautifulSoupにlxmlを渡すとエラーが出る場合
下のコードのところで
soup = BeautifulSoup(html, "lxml")
このようなエラーが出る場合あります。
Couldn't find a tree builder with the features you requested: lxml.
そんなときは以下のようにすると解決できました。
soup = BeautifulSoup(html, "html.parser")