質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.32%

BeautifulSoupで特定div内の複数のタグの要素を取得する方法

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 11K+

horik

score 44

attakeiさん再び回答ありがとうございます。
だいぶスッキリとコードが書けるようになりました。

addressのdictのkeyの部分;
address.append({li.attrs.get('class')[0]: li.text})

はもっと綺麗に書く方法はないでしょうか?
liのclassを取得したいだけなのに
attrs.get('class')[0]
こういうのしか思い当たりませんでした。

これが最善であれば、このままベストアンサーにさせていただきます。

profile = []
soup = BeautifulSoup(html, "html.parser")

for div in soup.select(".profile"):
    name = div.h3.text
    hobby = []
    address = []
    for a in div.select('ul.hobby > li > a'):
        hobby.append(a.text)
    for li in div.select('ul.address > li'):
        address.append({li.attrs.get('class')[0]: li.text})
    profile.append({"name": name, "hobby": hobby, "address": address})

print(profile)
[
{'name': '山田太郎', 'hobby': ['サッカー', 'ドライブ'], 'address': [{'city': '東京都'}, {'ward': '新宿区'}, {'town': '西新宿'}]},
{'name': '鈴木花子', 'hobby': ['手芸', '料理', '旅行'], 'address': [{'city': '大阪市'}, {'ward': '中央区'}]}
]

attakeiさん回答ありがとうございます。
追加で質問させてください。

ul要素が複数あった場合、最初の要素は取れましたが、
二つ目以降の取り方がわかりませんでした。

下のコードで取れたデータ:
[{'name': '山田太郎', 'hobby': ['サッカー', 'ドライブ']},
{'name': '鈴木花子', 'hobby': ['手芸', '料理', '旅行']}]

期待する出力は:
[{'name': '山田太郎', 'hobby': ['サッカー', 'ドライブ'], 'address': [{'city': "東京都"}, {'ward': "新宿区"}, {'town': "西新宿"}]},
{'name': '鈴木花子', 'hobby': ['手芸', '料理', '旅行'], 'address': [{'city': "大阪市',}, {'ward': '中央区'}]}]


html = """
<div class="profile">
    <h3>山田太郎</h3>
    <ul class="hobby">
        <li><a href="#">サッカー</a></li>
        <li><a href="#">ドライブ</a></li>
    </ul>
    <ul class="address">
        <li class="city">東京都</li>
        <li class="ward">新宿区</li>
        <li class="town">西新宿</li>
    </ul>
</div>
<div class="profile">
    <h3>鈴木花子</h3>
    <ul class="hobby">
        <li><a href="#">手芸</a></li>
        <li><a href="#">料理</a></li>
        <li><a href="#">旅行</a></li>
    </ul>
    <ul class="address">
        <li class="city">大阪市</li>
        <li class="ward">中央区</li>
    </ul>
</div>
"""
profile = []
soup = BeautifulSoup(html, "html.parser")
for div in soup.select(".profile"):
    name = div.h3.text
    hobby = []
    for a in div.ul.findChildren("a"):
        hobby.append(a.text)
    profile.append({"name": name, "hobby": hobby})
print(profile)

==============前回の質問==============
例えば下のようなHTMLがあっとして、二人のプロフィールを次のようなjson形式で保存したいと考えています。
{[name: "山田太郎", comment: "よろしくお願いします", age: 26, address: "東京都"], [name: "鈴木花子", comment: "よろしくお願いします", age: 20, address: "大阪府"]}

html = """
<div class="profile">
    <h3>山田太郎<h3>
    <p>よろしくおねがいします</p>
    <ul>
        <li>26歳</li>
        <li>東京都</li>
    </ul>
</div>
<div class="profile">
    <h3>鈴木花子<h3>
    <p>よろしくおねがいします</p>
    <ul>
        <li>20歳</li>
        <li>大阪府</li>
    </ul>
</div>
"""
soup = BeautifulSoup(html, "html.parser")

試したこと:
for name in soup.select(".profile > h3")
    print(name.text)
こうすると山田太郎と山田花子の名前を取れますが、
あとの年齢、都道府県を名前と紐付けた形で取得できません。

なにかいい方法はありませんでしょうか?

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • argius

    2016/05/27 12:41 編集

    って、既にattakeiさんが書いてましたね 余計なことをしてしまったすみません > 良く見たら<h3>の閉じタグが閉じられていませんね。</h3>でなくて<h3>になっています。

    キャンセル

  • argius

    2016/05/28 01:25

    おっと、回答したのは私ではないですよ。

    キャンセル

回答 3

+1

提示されていたhtmlだとh3タグが閉じられていないのですが、閉じられている想定で書いてみます。

この場合だと、名前があるh3タグのみで抽出すると面倒なので、ひとくくりになっている.profileクラスのdivタグを1セットにしてループさせた方がいいかと思います。

for profile in soup.select('.profile'):
    # 名前
    print(profile.h3.text)
    # コメント
    print(profile.p.text)
    # 年齢
    print(profile.ul.findChildren()[0].text)
    # 住所
    print(profile.ul.findChildren()[1].text)

HTMLの構造が上記の内容なら、これで各タグの中身のテキストはprint出力できます。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

※2番目に追加された方の質問に対する回答です。

大まかに書くと、selectで抽出可能です

自分も普段からそこまで深く使っているわけではないですが、「BeaufulSoupで抽出した要素は、さらにselectなどのメソッドが使用可能」という感じでいてもらえればいいかと。

soup = BeautifulSoup(html, "html.parser") 
profile = [] 
for div in soup.select(".profile"): 
    name = div.h3.text 
    hobby = [] 
    for a in div.select('ul.hobby > li > a'): 
        hobby.append(a.text) 
    address = [] 
    for li in div.select("ul.address > li"): 
        address.append(li.text) 
    profile.append({"name": name, "hobby": hobby, "address": address}) 

print(profile)

こんな感じでしょうか

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

checkベストアンサー

0

※あまり、一つの質問記事に次々と質問が足されていくのは良くないかな、と思いながら勉強がてら調べてみました

ドキュメントを読む限りだと、タグ要素にひもづいている属性は辞書として取り出せるみたいですね。

li.attrs.get('class')[0]
li['class'][0]

これで取れるみたいです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/05/31 10:45

    ありがとうございます。
    以後気をつけます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.32%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る