MENU
  • ホーム
  • プログラミング
  • ワードプレス
    • プラグインプラグイン関連記事
    • 賢威賢威のカスタマイズ
    • CSSCSSの関連記事
  • サイト情報
    • プライバシーポリシー
  • ツール
    • メルエディター
    • フリマスパイダー – 疾風
    • フリマスパイダー
    • -ポイ活くんα-
  • お問い合わせ
あらゆるモノにHackする、探究者の読み物。
Let's Hack Tech
  • ホーム
  • プログラミング
  • ワードプレス
    • プラグインプラグイン関連記事
    • 賢威賢威のカスタマイズ
    • CSSCSSの関連記事
  • サイト情報
    • プライバシーポリシー
  • ツール
    • メルエディター
    • フリマスパイダー – 疾風
    • フリマスパイダー
    • -ポイ活くんα-
  • お問い合わせ
Let's Hack Tech
  • ホーム
  • プログラミング
  • ワードプレス
    • プラグインプラグイン関連記事
    • 賢威賢威のカスタマイズ
    • CSSCSSの関連記事
  • サイト情報
    • プライバシーポリシー
  • ツール
    • メルエディター
    • フリマスパイダー – 疾風
    • フリマスパイダー
    • -ポイ活くんα-
  • お問い合わせ
  1. ホーム
  2. プログラミング
  3. 言語別
  4. Python
  5. BeautifulSoupでXMLをパース(解析)加工する – Python

BeautifulSoupでXMLをパース(解析)加工する – Python

2019 9/15
Python
2019-04-132019-09-15
BeautifulSoupでXMLをパース(解析)加工する - Python
目次

XMLとは?

XMLとは、文書やデータの意味や構造を記述するためのマークアップ言語の一つ。 マークアップ言語とは、「タグ」と呼ばれる特定の文字列で地の文に情報の意味や構造、装飾などを埋め込んでいく言語のことで、XMLはユーザが独自のタグを指定できることから、マークアップ言語を作成するためのメタ言語とも言われる。

https://www.graffe.jp/blog/2911/

一帯何に使うマークアップなのか?という方もいらっしゃるかもしれませんが、よくあるのはAPIでのレスポンスです。

割とよく見る馴染み深いレスポンス形式といえば「JSON」という方も少なくないと思います。

最近ではJSONに押され気味ながらも、まだまだXMLも健在です。

PythonでのXML解析にBeautifulSoupを使ってみる

BeautifulSoupはHTMLのパースというイメージがあるかと思いますが、実はXMLの解析にも使えます。

サンプルはAmazonMWSへのアクセス時にレスポンスとして帰ってくるXMLを使います。

<?xml version="1.0"?>
<GetProductCategoriesForASINResponse xmlns="http://mws.amazonservices.com/schema/Products/2011-10-01">
  <GetProductCategoriesForASINResult>
    <Self>
      <ProductCategoryId>2509478051</ProductCategoryId>
      <ProductCategoryName>FOSSIL(フォッシル)</ProductCategoryName>
      <Parent>
        <ProductCategoryId>2509471051</ProductCategoryId>
        <ProductCategoryName>F</ProductCategoryName>
        <Parent>
          <ProductCategoryId>2509395051</ProductCategoryId>
          <ProductCategoryName>Brand Stores</ProductCategoryName>
          <Parent>
            <ProductCategoryId>333346011</ProductCategoryId>
            <ProductCategoryName>COOP</ProductCategoryName>
            <Parent>
              <ProductCategoryId>333334011</ProductCategoryId>
              <ProductCategoryName>Stores</ProductCategoryName>
              <Parent>
                <ProductCategoryId>324025011</ProductCategoryId>
                <ProductCategoryName>腕時計</ProductCategoryName>
              </Parent>
            </Parent>
          </Parent>
        </Parent>
      </Parent>
    </Self>
    <Self>
      <ProductCategoryId>333009011</ProductCategoryId>
      <ProductCategoryName>メンズ腕時計</ProductCategoryName>
      <Parent>
        <ProductCategoryId>331952011</ProductCategoryId>
        <ProductCategoryName>カテゴリー別</ProductCategoryName>
        <Parent>
          <ProductCategoryId>324025011</ProductCategoryId>
          <ProductCategoryName>腕時計</ProductCategoryName>
        </Parent>
      </Parent>
    </Self>
    <Self>
      <ProductCategoryId>2131417051</ProductCategoryId>
      <ProductCategoryName>メンズ</ProductCategoryName>
      <Parent>
        <ProductCategoryId>361245011</ProductCategoryId>
        <ProductCategoryName>カテゴリー別</ProductCategoryName>
        <Parent>
          <ProductCategoryId>352484011</ProductCategoryId>
          <ProductCategoryName>服&ファッション小物</ProductCategoryName>
        </Parent>
      </Parent>
    </Self>
  </GetProductCategoriesForASINResult>
  <ResponseMetadata>
    <RequestId>*******-****-****-****-**********</RequestId>
  </ResponseMetadata>
</GetProductCategoriesForASINResponse>

MWS-GetProductCategoriesForASINで取得したXMLです。

どういったソースなのかというと、商品が属するカテゴリノードを示したXMLです。Amazonでは一商品一カテゴリという分類ではなく、複数のカテゴリ分類に属している可能性があり、上記は一商品分のソースで、3つのカテゴリ分類に属しています。

BeautifulSoupにXMLを渡す

まずは解析準備です。

MWSアクセスのコードは省略します。res.contentがXMLの文字列本体だと思ってください。

BeautifulSoupオブジェクトの作成

import requests
from bs4 import BeautifulSoup as bs4

res = requests.post(MWS)
#詳しくは省略、上のXMLが返ってくるものと思ってください

soup = bs4(res.content,'lxml-xml')
Let's Hack Tech
【Python】BeautifulSoupの使い方・基本メソッド一覧|スクレイピング | Let's Hack Tech Pythonを使ったWebスクレイピングの比較的メジャーなライブラリBeautifulSoupのメソッドを一挙紹介します。 このページを読めばBeautifulSoupのほとんどの動作、メソッドを...

上記記事でHTMLをパースした時とsoupオブジェクトの作り方が若干違うのがわかるかと思いますが、bs4のパーサに’lxml-xml’を指定してます。

僕は基本的に’lxml’パーサを使いますが、それのXML版です。

’lxml’のままでもパースできなくはないですが、キャメルバックになったタグが使えなくなったり、色々弊害が出てきたりするので、こちらをオススメします。

BeautifulSoupでXMLをパースする

基本的にHTMLのパースと要領は同じですが、復習を兼ねて、逆引きリファレンス的にまとめてみます。

上記コードの続きからです。

XMLのタグ名で検索し、最初に見つかる要素へアクセス

soup.Self
soup.find('Self')
#どちらも同じ

上記はどちらも同じ挙動で、「最初の<Self>タグ」にアクセスします。

Outは以下の通り。

Out[1]: 
<Self>
<ProductCategoryId>2509478051</ProductCategoryId>
<ProductCategoryName>FOSSIL(フォッシル)</ProductCategoryName>
<Parent>
<ProductCategoryId>2509471051</ProductCategoryId>
<ProductCategoryName>F</ProductCategoryName>
<Parent>
<ProductCategoryId>2509395051</ProductCategoryId>
<ProductCategoryName>Brand Stores</ProductCategoryName>
<Parent>
<ProductCategoryId>333346011</ProductCategoryId>
<ProductCategoryName>COOP</ProductCategoryName>
<Parent>
<ProductCategoryId>333334011</ProductCategoryId>
<ProductCategoryName>Stores</ProductCategoryName>
<Parent>
<ProductCategoryId>324025011</ProductCategoryId>
<ProductCategoryName>腕時計</ProductCategoryName>
</Parent>
</Parent>
</Parent>
</Parent>
</Parent>
</Self>

XMLのタグ名で検索し、一致した全ての要素のリストを返す

soup('Self')
soup.find_all('Self')
#どちらも同じ

上記はどちらも同じ挙動で、「全ての<Self>タグ」にアクセスし、リスト形式で返却します。

Outは以下の通り。

Out[2]:
[<Self>
 <ProductCategoryId>2509478051</ProductCategoryId>
 <ProductCategoryName>FOSSIL(フォッシル)</ProductCategoryName>
 <Parent>
 <ProductCategoryId>2509471051</ProductCategoryId>
 <ProductCategoryName>F</ProductCategoryName>
 <Parent>
 <ProductCategoryId>2509395051</ProductCategoryId>
 <ProductCategoryName>Brand Stores</ProductCategoryName>
 <Parent>
 <ProductCategoryId>333346011</ProductCategoryId>
 <ProductCategoryName>COOP</ProductCategoryName>
 <Parent>
 <ProductCategoryId>333334011</ProductCategoryId>
 <ProductCategoryName>Stores</ProductCategoryName>
 <Parent>
 <ProductCategoryId>324025011</ProductCategoryId>
 <ProductCategoryName>腕時計</ProductCategoryName>
 </Parent>
 </Parent>
 </Parent>
 </Parent>
 </Parent>
 </Self>, <Self>
 <ProductCategoryId>333009011</ProductCategoryId>
 <ProductCategoryName>メンズ腕時計</ProductCategoryName>
 <Parent>
 <ProductCategoryId>331952011</ProductCategoryId>
 <ProductCategoryName>カテゴリー別</ProductCategoryName>
 <Parent>
 <ProductCategoryId>324025011</ProductCategoryId>
 <ProductCategoryName>腕時計</ProductCategoryName>
 </Parent>
 </Parent>
 </Self>, <Self>
 <ProductCategoryId>2131417051</ProductCategoryId>
 <ProductCategoryName>メンズ</ProductCategoryName>
 <Parent>
 <ProductCategoryId>361245011</ProductCategoryId>
 <ProductCategoryName>カテゴリー別</ProductCategoryName>
 <Parent>
 <ProductCategoryId>352484011</ProductCategoryId>
 <ProductCategoryName>服&ファッション小物</ProductCategoryName>
 </Parent>
 </Parent>
 </Self>]

リスト形式ですので、返却されたオブジェクトを操作する場合はリストと同じようにインデックスアクセスして操作します。

例えば最後の<Self>タグにアクセスしたい場合は以下のように。

Self = soup('Self')
Self[-1]

Out[3]: 
<Self>
<ProductCategoryId>2131417051</ProductCategoryId>
<ProductCategoryName>メンズ</ProductCategoryName>
<Parent>
<ProductCategoryId>361245011</ProductCategoryId>
<ProductCategoryName>カテゴリー別</ProductCategoryName>
<Parent>
<ProductCategoryId>352484011</ProductCategoryId>
<ProductCategoryName>服&ファッション小物</ProductCategoryName>
</Parent>
</Parent>
</Self>

[-1]は最後の要素、[-2]なら最後から二番目の要素を返します。

子要素をリスト形式で返却

要素直下の各子要素をリスト形式で返却するメソッドもあります。

soup.GetProductCategoriesForASINResult.contents
#直下子要素をリスト形式で返却

上記コードはsoup(‘Self’)とした時と全く同じ結果が返ってきます。

XMLのテキストで検索する

soup.find(text='メンズ')
Out[4]: 'メンズ'

テキストがわかっている時そのテキストを持つ要素にアクセスしたい場合は上記の通り。

ただ、そのテキスト本体にアクセスしてしまうので、基本的にこれだけでは何してるのか一切意味が分かりません(笑)

普通は、ここから更に、別の要素に展開させて行く使い方をします。

#テキスト一致の親要素(タグ)
soup.find(text='メンズ').parent
Out[5]: <ProductCategoryName>メンズ</ProductCategoryName>
#テキスト一致の親要素(タグ)の「タグ名」
soup.find(text='メンズ').parent.name
Out[6]: 'ProductCategoryName'
#テキスト一致の親要素(タグ)から更に直前の兄弟要素
soup.find(text='腕時計').parent.previous_sibling
Out[7]: <ProductCategoryId>324025011</ProductCategoryId>
#テキスト一致の親要素(タグ)から更に直後の兄弟要素
soup.find(text='352484011').parent.next_sibling
Out[8]: <ProductCategoryName>服&ファッション小物</ProductCategoryName>

実践的にBeautifulSoupでXMLを加工してみる

大体使い方もわかったところで、少し実践的に加工してみます。

ProductCategoryIdと、ProductCategoryNameのテキストを一組2要素のタプルとして、階層順にリストとして保存。更に3つの各カテゴリ属性全てを同様に加工し別リストとして保存してみます。

複雑そうに見えますが、慣れればこの加工、2行で出来ます。

Self = soup('Self ')
item_nodes = [[(tag.text,tag.next_sibling.text) for tag in item('ProductCategoryId')] for item in Self]

1行目は各カテゴリ分類をリスト形式で「Self」という変数に保存。

2行目のリスト内包表記は 「Self」に格納された各要素にアクセス。
各要素は「item」要素に格納されます。

「item(‘ProductCategoryId’)」としてProductCategoryIdのタグ全てを取得していますが、そのままではタグごと取得してしまい、テキストを抜き出すことが出来ないため、更にリスト内包表記を使ってタグ内のtextにアクセスします。

ProductCategoryNameは必ずProductCategoryIdと一対の兄弟要素となっているため、Idタグにさえアクセスできれば「.next_sibling」で取得可能になります。

item_nodesに結果が保存されています。

item_nodes
Out[9]: 
[[('2509478051', 'FOSSIL(フォッシル)'),
  ('2509471051', 'F'),
  ('2509395051', 'BrandStores'),
  ('333346011', 'COOP'),
  ('333334011', 'Stores'),
  ('324025011', '腕時計')],
 [('333009011', 'メンズ腕時計'), ('331952011', 'カテゴリー別'), ('324025011', '腕時計')],
 [('2131417051', 'メンズ'), ('361245011', 'カテゴリー別'), ('352484011', '服&ファッション小物')]]

BeautifulSoupによるXMLパース(解析) – 総括

HTMLのパースと感覚はほとんど一緒ですね。

‘lxml-xml’を使うと、要素へのアトリビュートアクセスの時にキャメルバックのタグもそのままアクセスできますが、’lxml’だと小文字でしかアクセスできなかったりと、細かい違いはところどころに存在します。

今回はパース(解析)の方法を紹介しましたが、実はBeautifulSoupはXMLの作成もできたりします。

こちらの記事ではYahooAPIを題材にBeautifulSoupでゼロから作成したXMLドキュメントでリクエストを行う方法を紹介していますので、ぜひ参考にしてみてください。

Let's Hack Tech
Re:ゼロから始めるBeatufulSoupによるXMLドキュメント作成【Python】 | Let's Hack Tech WebAPIなんかを使っていると、リクエストをするためにXML文字列をリクエストボディに含める要求方法なんかに出くわします。 Yahooショッピングの注文API関係なんかがそのタ...
10日でおぼえるXML入門教室 第2版
created by Rinker
¥631 (2025/05/09 19:46:50時点 Amazon調べ-詳細)
  • Amazon
  • 楽天市場
  • Yahooショッピング
Python
BeautifulSoup Python XML スクレイピング
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする コメントをキャンセル

email confirm*

post date*

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)

シンプル美と機能性を両立させた、国内最高峰のWordPressテーマ『SWELL』
人気記事
  • IQテストいくつか受けてみました
    ネット上で信憑性がありそうなIQテスト、5種類まとめて受けた結果…
  • hayate
    メルカリの商品を世界最速で購入するためだけのアラートツール
  • 【Python】BeautifulSoupの使い方・基本メソッド一覧|スクレイピング
  • Pythonファイルのexe化
    【悲報】PyInstallerさん、300MBのexeファイルを吐き出すようになる
  • Amazon Echo アレクサのコマンドまとめ
    AmazonEchoの使い方とできる事、アレクサへの指示コマンド一覧
最近の投稿
  • 正規表現処理の濁点でハマった話2024-12-12
  • 保護中: 疾風v2更新履歴2024-05-31
  • 【自営・経営者向け・税金も】クレジットカードガチ勢による最強クレカ解説2023-10-23
  • PyQt5 QListWidget の item削除でtextBoxのフォーカスが奪われる2023-03-05
  • WordPressからのメールが届かない時の調査と解決法2023-02-27
目次
目次