ユーニックス総合研究所

  • home
  • archives
  • bs4-csv

BeautifulSoup4でタグをCSVに変換する

  • 作成日: 2021-04-15
  • 更新日: 2023-12-24
  • カテゴリ: BeautifulSoup4

BeautifulSoup4で得たタグをCSVに変換する

PythonにはHTML/XMLパーサーとしてBeautifulSoup4という外部ライブラリがあります。
これを使うと簡単にHTML/XMLなどのドキュメントをパースすることが可能です。

今回は、このBeautifulSoup4を使って得たタグのリストをCSVファイルに書き込んでみたいと思います。
具体的には↓を見ていきます。

  • CSVとは?
  • 単一のulをCSVに変換する
  • 複数のulをCSVに変換する
  • テーブルをCSVに変換する

CSVとは?

CSV(シーエスブイ)とは「Comma Separated Values」の略です。
これは直訳すると、「カンマで区切られた複数の値」という意味になります。
たとえば↓のようなものがCSVフォーマットの文字列です。

one,two,three  
cat,dog,bird  

値がカンマ(,)で区切られて並べられています。
この時一行を「行」または「レコード」といい、これが1つの塊のデータとして扱われます。
行(レコード)が複数並んでいる状態はつまり複数のデータがある状態です。

たとえば学校の名簿を考えてみたいと思います。
名簿には学年や名前、出席番号などが書かれています。
この時生徒1人分のデータがレコードになります。

つまり↓ということです。

1,田中太郎,101  
1,山田花子,102  
1,原人北京,103  
...  

HTMLなどののデータをこのようなCSVに変換したいというのは割とよくあることです。
スクレイピングなどでデータを取得して、そのHTMLのデータから目的のデータを抽出して、それをファイルにCSVで保存するという具合にです。

リスト内包表記について

この記事でよく使われるリスト内包表記の解説です。
知ってる方は飛ばしてください。

リスト内包表記とは↓のようなフォーマットの表記です。

結果 = [ 要素 for 要素 in リスト ]  

↑のようにするとリスト内の要素が新しく出来たリストに保存され、結果として返ってきます。
具体的にコードにすると↓のようなコードになります。

lis = [1, 2, 3]  
res = [el for el in lis]  
print(res)  

↑のコードを実行すると↓のような結果になります。

[1, 2, 3]  

リスト内包表記ではforの左側にある要素に対して加工などを行うことができます。
たとえば要素を10で割るという加工を行うと↓のようなコードになります。

lis = [1, 2, 3]  
res = [el / 10 for el in lis]  
print(res)  

↑のコードを実行すると↓のような結果になります。

[0.1, 0.2, 0.3]  

リスト内包表記は普通のfor文と比べてコードが短くなるという特徴があります。

単一のulをCSVに変換する

それでは単一のulタグをレコードに変換してCSVファイルに保存してみます。
例としては↓のようになります。

from bs4 import BeautifulSoup  
import csv  

# 元になるHTML  
code = '''<ul>  
<li>one</li>  
<li>two</li>  
<li>three</li>  
</ul>  
'''  
soup = BeautifulSoup(code, 'html.parser')  # パースする  
row = [li.text for li in soup.find_all('li')]  # liタグのテキストをリストにする  

with open('out.csv', 'w') as fout:  # 書き込み用ファイルを開き  
    writer = csv.writer(fout)  # ライターを作成し  
    writer.writerow(row)  # レコードを一行書き込む  

codeをBeautifulSoupでパースしてsoupという結果を得ます。
このsoupのメソッドfind_all()を呼び出してliタグのリストを得ます。
それをリスト内包表記で回してli.textをリストの要素に格納していきます。
これでrowというliタグのテキストが格納されたレコードができました。

あとはout.csvというファイルを開いて、そのファイルオブジェクトをcsv.writer()に渡します。
(今回はCSVファイルの保存にcsvモジュールを使います)
writerを作ったらwriterow()メソッドに先ほどのrowを渡して書き込みます。
これであとはwriterが良い感じのフォーマットにしてくれます。

書き込んだout.csvファイルの中身は↓のようになっています。

one,two,three  

ul内のデータがCSVとして保存できてますね。

複数のulをCSVに変換する

複数のulタグをCSVに変換するには↓のようにします。

from bs4 import BeautifulSoup  
import csv  

# 元になるHTML  
code = '''<ul>  
<li>one</li>  
<li>two</li>  
<li>three</li>  
</ul>  
<ul>  
<li>cat</li>  
<li>dog</li>  
<li>bird</li>  
</ul>  
'''  
soup = BeautifulSoup(code, 'html.parser')  # パースする  
mat = []  # 行列  

for ul in soup.find_all('ul'):  # ulタグを取り出す  
    row = [li.text for li in ul.find_all('li')]  # liを取り出してtextを保存する  
    mat.append(row)  # 行を追加  

with open('out.csv', 'w') as fout:  # 書き込み用ファイルを開き  
    writer = csv.writer(fout)  # ライターを作成し  

    for row in mat:  
        writer.writerow(row)  # レコードを一行書き込む  

soupを作ってfind_all()ulタグを取り出してfor文で回します。
そしてそのulタグからfind_all()を呼び出してliタグを取り出します。
そのliタグはリスト内包表記で回してtextをリストの要素に保存します。
その結果をrowとして、出来あがったらmatに追加します。
ちなみにmatmatrix(行列)の略です。

matが出来上がったらout.csvファイルを書き込みモードで開きます。
そのファイルオブジェクトをcsv.writer()に渡してwriterを作ります。
matfor文で回して行(row)を取り出し、writerwriterow()メソッドに渡して行(レコード)をファイルに書き込みます。

書き込まれたout.csvを見ると↓のようになっています。

one,two,three  
cat,dog,bird  

テーブルをCSVに変換する

テーブルをCSVに変換したい場合は↓のようにします。

from bs4 import BeautifulSoup  
import csv  

# 元になるHTML  
code = '''<table>  
<tr>  
    <td>one</td>  
    <td>two</td>  
    <td>three</td>  
</tr>  
<tr>  
    <td>cat</td>  
    <td>dog</td>  
    <td>bird</td>  
</tr>  
</table>  
'''  
soup = BeautifulSoup(code, 'html.parser')  # パースする  
mat = []  # 行列  

# テーブルをパースする  
table = soup.find('table')  
for tr in table.find_all('tr'):  # trタグを取る  
    row = [td.text for td in tr.find_all('td')]  # tdのtextを保存する  
    mat.append(row)  # 行を追加  

with open('out.csv', 'w') as fout:  # 書き込み用ファイルを開き  
    writer = csv.writer(fout)  # ライターを作成し  

    for row in mat:  
        writer.writerow(row)  # レコードを一行書き込む  

基本的には複数のulタグのパースと同じです。
まずsoup.find()tableタグを取ります。
そしてtableタグのfind_all()trタグを取ってきてfor文で回します。
trタグのfind_all()tdタグを取ってきて、リスト内包表記でtdtextをリストの要素に保存します。
その結果をrowとして、matに保存します。

matが出来上がったらout.csvを書き込みモードで開き、writer.writerow()で行を書き込みます。

おわりに

今回はBeautifulSoup4で取得したデータをCSVに変換してみました。
CSVはスクレイピングなどでもよく使われるデータフォーマットです。
Pythonではモジュールを使えば簡単に変換することができます。

🦝 < カンマで区切ってあげる

🐭 < けっこうです