yuhtaryouko
@yuhtaryouko (Yuta Kato)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

同じクラス名の要素を選択して抽出したい

こちらの質問の続きです
https://qiita.com/yuhtaryouko/questions/d3b7d5347cbadef0ee4d

seleniumを使って動的な要素を全部取得する+cssセレクタで欲しい要素を指定できるまではできました。

from selenium import webdriver
from bs4 import BeautifulSoup as bs

import chromedriver_binary
browser = webdriver.Chrome()
url = 'https://www.pokemon-card.com/products/'

html = browser.page_source.encode('utf-8')
soup = bs(html, 'html.parser')


#タイトル・発売日・金額をリストに入れていく
dates = []
names = []
prices = []

#タイトルの取得
titles = soup.select('#productsTab_expansionPack .Title' )
print(titles)

days = soup.select('#productsTab_expansionPack .Description-list .Description_body')
print(days)







ここで、商品の発売日だけを取得したいのですがDescription-list Description_bodyが複数箇所(3か所)で使われており、それらがすべて取得されてしまいます。これらを分けて取得するにはどうしたらよいでしょうか。

image.png

自分で試したこと

変数daysで取得できたリストの中の項目から1番目、4番目、7番目というように指定出来たらいいのかなと思いました。
:nth-of-type()というものも使えるのかと思いましたが、使い方がよくわからず…

どなたかご教授頂けないでしょうか。

0

3Answer

これで発売日だけ取ってこれました。

days = soup.select('#productsTab_expansionPack > ul > li > div > div > ul > li:nth-of-type(1) > span.Description_body')

image.png

chromeの開発者ツールで、取得したい要素を右クリックから「Copy selector」とすると、ほぼ取得したい形のCSSセレクタが取れるので便利ですよ。
今回だと1番上の商品の発売日のセレクタを取得すると以下のものがとってこれます。
あとはよしなに修正して取得すれば、すべての発売日のみを取得することができました。

#productsTab_expansionPack > ul > li:nth-child(1) > div > div > ul > li:nth-child(1) > span.Description_body
1Like

Comments

  1. @yuhtaryouko

    Questioner

    ありがとうございます!詳細はあまり理解できないですが、とにかくこれでできるということは確認できました!

    この意味が理解できるように精進していこうと思います。

(seleniumは長らく使っていないのですが)
変数daysに格納されているリストは上から順番に取得されたものになっていないでしょうか?
リストを眺めて発売日が入ってるインデックスの法則を探してみては?
例えば1, 4, 7番目を取り出したいとわかっているのならスライスで取り出せるかと。
スライスについてはこちらとかを→ https://qiita.com/yossyyossy/items/0c8dc2ed53466d970fe4

0Like

Comments

  1. @yuhtaryouko

    Questioner

    ありがとうございます。そうなんです!3個ずつ順番に来るので最初は1.4.7と取り出そうと考えました。スライスというのも使ってみようと思います。
  2. スライス自体はめちゃくちゃ便利なので是非是非覚えてみてください!
    (ちゃんとしたものならともかく、個人でサクッとやる分にはそのように法則見出して取り出す方が楽だと思いますよ)
days = soup.select("#productsTab_expansionPack .Description-list .Description_body")
print(days)

# ------------- 質問のコードここまで -------------
import re

# リスト
dates = []
prices = []

# 正規表現のパターン
pattern_year = "(\d+)年.*"
pattern_price = "(\d+)円.*"

# days を一つずつ見ていく
for day in days:
    # day.text が xxxx年~~なら
    if re.match(pattern_year, day.text):
        dates.append(day)
    # day.text が xxxx円~~なら
    elif re.match(pattern_price, day.text):
        prices.append(day)

としてもいいですが、"内容"も取りたいとなった場合に苦労します。
※内容に「2022年限定カード入り.....」なんて仮に書かれていた場合など。

不確定要素が多くあるものは避けたいので、
この場合は項目名が固定されている「発売日、希望小売価格、内容」を軸に取得します。

# タイトル・発売日・金額をリストに入れていく
dates = []
names = []
prices = []

# ------------- 質問のコードここまで -------------

# <li class="KSTabContents_item current" id="productsTab_expansionPack"> にある
# 複数の <div class="List_body"> を一つずつ見ていく
li_tag = soup.select_one("#productsTab_expansionPack")
div_tags = li_tag.select("div.List_body")
for div in div_tags:

    # タイトル: <div class="Title"> をテキストで取得
    name_text = div.select_one("div.Title").get_text(strip=True)

    # <div class="List_body"> にある
    # <ul class="Description Description-list"> の <li> を一つずつ見ていく
    li_tags = div.select("ul.Description.Description-list > li")
    for li in li_tags:

        # if文で <li> の中に"発売日"か"希望小売価格"が含まれているか
        # 含まれている場合は、<li> にある
        # <span class="Description_body"> をテキストで取得
        if "発売日" in li.text:
            date_text = li.select_one("span.Description_body").get_text(strip=True)
        elif "希望小売価格" in li.text:
            price_text = li.select_one("span.Description_body").get_text(strip=True)

    # 取得したテキストをリストに追加する
    dates.append(date_text)
    names.append(name_text)
    prices.append(price_text)

テキストではなく、htmlのままが良い場合は
.get_text(strip=True) を消してください

0Like

Comments

  1. @yuhtaryouko

    Questioner

    ありがとうございます。一つ一つ確認して場合分けするというようなイメージですかね。
    こういった確実なやり方も勉強になります!

Your answer might help someone💌