XML(Extensible Markup Language)は、データの構造化方法として人気のあるマークアップ言語である。
データ転送(シリアル化されたオブジェクトを表す)や設定ファイルで使用されています。
JSONの人気が高まっているにもかかわらず、Android開発のマニフェストファイル、Java/Mavenのビルドツール、Web上のSOAP APIなどでXMLを見かけることがあります。
したがって、XMLの解析は開発者がやらなければならない一般的なタスクです。
Pythonでは、2つのライブラリを活用することで、XMLを読み、パースすることができます。
BeautifulSoupとLXMLです。
このガイドでは、XMLの読み方について説明します。
このガイドでは、BeautifulSoupとLXMLを使ってXMLファイルからデータを抽出・パースし、Pandasを使って結果を保存する方法を見ていきます。
LXMLとBeautifulSoupのセットアップ
まず、両ライブラリをインストールする必要があります。
ワークスペースに新しいフォルダを作成し、仮想環境を構築して、ライブラリをインストールします。
$ mkdir xml_parsing_tutorial
$ cd xml_parsing_tutorial
$ python3 -m venv env # Create a virtual environment for this project
$ . env/bin/activate # Activate the virtual environment
$ pip install lxml beautifulsoup4 # Install both Python packages
これで、すべてのセットアップが完了しましたので、パースを行ってみましょう。
lxml と BeautifulSoup による XML のパース
パースは常に基礎となるファイルとそれが使用する構造に依存するので、すべてのファイルに対する単一の銀の弾丸はありません。
BeautifulSoupはそれらを自動的に解析しますが、基礎となる要素はタスクに依存します。
したがって、実践的なアプローチでパージングを学ぶことが最善です。
<?xml version="1.0" encoding="UTF-8"?
<teachers
<teacher
<nameSam Davies</name
<age35</age
<subjectMaths</subject
</teacher
<teacher
<nameCassie Stone</name
<age24</age
<subjectScience</subject
</teacher
<teacher
<nameDerek Brandon</name
<age32</age
<subjectHistory</subject
</teacher
</teachers
タグはXML文書のルートを示し、
タグは
の子またはサブ要素で、一人の人に関する情報を持ちます。
name, <age
, <subject
は <teacher
タグの子であり、<teachers
タグの孫にあたります。
上のサンプル文書の最初の行、<?xml version="1.0" encoding="UTF-8"?
は、XML prolog と呼ばれるものです。
XML文書の中にXMLプロローグを含めることは完全に任意ですが、XMLファイルの先頭には必ずこの行が含まれます。
となります。
上のXMLプロローグは、使用するXMLのバージョンと文字エンコーディングの種類を示します。
この場合、XML文書内の文字は、UTF-8でエンコードされています。
XMLファイルの構造を理解したところで、それを解析してみましょう。
作業ディレクトリに teachers.py
という新しいファイルを作成し、BeautifulSoup ライブラリをインポートしてください。
from bs4 import BeautifulSoup
注意: お気づきかもしれませんが、lxml
をインポートしていません! BeautifulSoupをインポートすることで、LXMLは自動的に統合されるので、別途インポートする必要はありませんが、BeautifulSoupの一部としてインストールされているわけではありません。
では、作成したXMLファイルの内容を読み込んで、soup
という変数に格納し、パージングを始めてみましょう。
with open('teachers.xml', 'r') as f:
file = f.read()
# 'xml' is the parser used. For html files, which BeautifulSoup is typically used for, it would be 'html.parser'.
soup = BeautifulSoup(file, 'xml')
変数 soup
には XML ファイルをパースした内容が格納されています。
この変数とそれに付随するメソッドを使って、PythonのコードでXMLの情報を取得することができます。
例えば、XMLドキュメントから教師の名前だけを表示したいとします。
数行のコードでその情報を得ることができます。
names = soup.find_all('name')
for name in names:
print(name.text)
python teachers.py` を実行すると、次のようになります。
Sam Davis
Cassie Stone
Derek Brandon
find_all()メソッドは、引数として渡されたタグにマッチするすべてのリストを返します。
上のコードに示すように、soup.find_all(‘name’)は XML ファイルに含まれるすべての
タグを返します。
そして、これらのタグを繰り返し処理し、タグの値を含むtext` プロパティを表示します。
パースされたデータをテーブルに表示する
もう一歩進めて、XMLファイルの内容をすべてパースして表形式で表示することにしましょう。
teachers.py` ファイルを次のように書き換えてみましょう。
from bs4 import BeautifulSoup
# Opens and reads the xml file we saved earlier
with open('teachers.xml', 'r') as f:
file = f.read()
# Initializing soup variable
soup = BeautifulSoup(file, 'xml')
# Storing <name tags and elements in names variable
names = soup.find_all('name')
# Storing <age tags and elements in 'ages' variable
ages = soup.find_all('age')
# Storing <subject tags and elements in 'subjects' variable
subjects = soup.find_all('subject')
# Displaying data in tabular format
print('-'.center(35, '-'))
print('|' + 'Name'.center(15) + '|' + ' Age ' + '|' + 'Subject'.center(11) + '|')
for i in range(0, len(names)):
print('-'.center(35, '-'))
print(
f'|{names[i].text.center(15)}|{ages[i].text.center(5)}|{subjects[i].text.center(11)}|')
print('-'.center(35, '-'))
上のコードの出力は次のようになります。
-----------------------------------
| Name | Age | Subject |
-----------------------------------
| Sam Davies | 35 | Maths |
-----------------------------------
| Cassie Stone | 24 | Science |
-----------------------------------
| Derek Brandon | 32 | History |
-----------------------------------
おめでとうございます。
おめでとうございます! BeautifulSoupとLXMLを使って、最初のXMLファイルをパースしましたね。
さて、理論やプロセスに慣れてきたところで、もっと実戦的な例を試してみましょう。
ここでは、汎用的なデータ構造にデータを格納する前段階として、データを表としてフォーマットしました。
つまり、今度のミニプロジェクトでは、Pandasの DataFrame
にデータを格納することにします。
もしあなたがまだDataFrameについてよく知らないのであれば、Python with Pandasを読んでください。
DataFrameについてまだよく知らない方は、Python with Pandas: Guide to DataFrameを参照してください。
をご覧ください。
RSSフィードのパースとCSVへのデータ格納
ここでは、The New York Times NewsのRSSフィードをパースし、そのデータをCSVファイルに格納します。
RSSとは、Really Simple Syndicationの略です。
RSSフィードとは、ウェブサイトの更新情報をまとめたファイルのことで、XMLで記述されています。
ここでは、The New York TimesのRSSフィードは、同ウェブサイトで毎日更新されるニュースの要約を含んでいます。
この要約には、ニュースリリースへのリンク、記事画像へのリンク、ニュース項目の説明などが含まれています。
RSSフィードは、ウェブサイトの所有者による素敵なトークンとして、人々がウェブサイトをスクレイピングせずにデータを取得できるようにするためにも使用されています。
以下は、The New York TimesのRSSフィードのスナップショットです。
このリンクから、さまざまな大陸、国、地域、トピック、その他の基準のNew York Times RSSフィードにアクセスすることができます。
データの解析を始める前に、その構造を見て理解することが重要です。
各ニュース記事に関する RSS フィードから抽出したいデータは、次のとおりです。
- グローバル一意識別子 (GUID)
- タイトル
- 発行日
- 説明
さて、構造に慣れ、明確な目標を持ったところで、プログラムを開始しましょう! データを取得し、簡単にCSVファイルに変換するために、requests
ライブラリとpandas
ライブラリが必要です。
まだ requests
を扱ったことがない方は、 Python のリクエストモジュールへのガイド を読んでください。
を読んでください。
requestsを使うと、Web サイトに HTTP リクエストを送り、そのレスポンスを解析することができる。
今回の例では、RSSフィード(XML)を取得し、BeautifulSoupがそれをパースできるようにするために使用できます。
pandasを使用すると、パースされたデータをテーブルでフォーマットし、最終的にテーブルの内容をCSVファイルに格納することができるようになります。
同じ作業ディレクトリに、 requests
と pandas
をインストールします (仮想環境はまだ有効である必要があります)。
$ pip install requests pandas
新しいファイル nyt_rss_feed.py
で、ライブラリをインポートします。
import requests
from bs4 import BeautifulSoup
import pandas as pd
そして、The New York TimesのサーバーにHTTPリクエストをして、RSSフィードを取得し、その内容を取得しましょう。
url = 'https://rss.nytimes.com/services/xml/rss/nyt/US.xml'
xml_data = requests.get(url).content
上記のコードで、HTTP リクエストからレスポンスを取得し、その内容を xml_data
変数に格納することができました。
requestsライブラリはデータを
bytes` として返す。
では、BeautifulSoupの助けを借りて、PandasでXMLデータをパースしてテーブルに格納する以下の関数を作成します。
def parse_xml(xml_data):
# Initializing soup variable
soup = BeautifulSoup(xml_data, 'xml')
# Creating column for table
df = pd.DataFrame(columns=['guid', 'title', 'pubDate', 'description'])
# Iterating through item tag and extracting elements
all_items = soup.find_all('item')
items_length = len(all_items)
for index, item in enumerate(all_items):
guid = item.find('guid').text
title = item.find('title').text
pub_date = item.find('pubDate').text
description = item.find('description').text
# Adding extracted elements to rows in table
row = {
'guid': guid,
'title': title,
'pubDate': pub_date,
'description': description
}
df = df.append(row, ignore_index=True)
print(f'Appending row %s of %s' % (index+1, items_length))
return df
上記の関数は、BeautifulSoupを使ってHTTPリクエストからXMLデータをパースし、その内容をsoup
変数に格納します。
パースしたいデータの行と列を持つ Pandas DataFrame は df
変数を通して参照されます。
次に、XML ファイルを繰り返し処理し、<item
を含むすべてのタグを探します。
タグを繰り返し処理することで、その子タグを抽出することができます。
guid, <title
, <pubdate
, そして <description
です。
find()` メソッドを使用して、1つのオブジェクトだけを取得していることに注意してください。
各子タグの値をPandasのテーブルに追加していきます。
さて、関数の後のファイルの最後に、関数を呼び出してCSVファイルを作成するために、次の2行のコードを追加します。
df = parse_xml(xml_data)
df.to_csv('news.csv')
python nyt_rss_feed.py` を実行し、現在の作業ディレクトリに新しい CSV ファイルを作成します。
Appending row 1 of 24
Appending row 2 of 24
...
Appending row 24 of 24
CSV ファイルの中身は以下のようになります。
データのダウンロードは、インターネットの接続状況やRSSフィードの種類によって、多少時間がかかる場合があります。
また、データの解析には、CPUやメモリなどのリソースが必要です。
今回使用したフィードはかなり小さいので、すぐに処理できるはずです。
すぐに結果が表示されない場合は、しばらくお待ちください。
おめでとうございます!The New York Times NewsのRSSフィードを解析してCSVファイルに変換できました。
結論
このガイドでは、BeautifulSoup と LXML をセットアップして XML ファイルをパースする方法について学びました。
まず、教師データのある単純な XML ファイルを解析して練習し、次に、The New York Times の RSS フィードを解析して、そのデータを CSV ファイルに変換してみました。
これらのテクニックを使用して、遭遇する可能性のある他の XML を解析し、必要なさまざまな形式に変換することができます。
。