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

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

新規登録して質問してみよう
ただいま回答率
85.35%
スクレイピング

スクレイピングとは、公開されているWebサイトからページ内の情報を抽出する技術です。

Beautiful Soup

Beautiful Soupは、Pythonのライブラリの一つ。スクレイピングに特化しています。HTMLデータの構文の解析を行うために、HTMLタグ/CSSのセレクタで抽出する部分を指定することが可能です。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

Q&A

解決済

2回答

12656閲覧

Beautiful Soup 取得したい階層にたどり着けない(見つからない)

metrobaroque

総合スコア1

スクレイピング

スクレイピングとは、公開されているWebサイトからページ内の情報を抽出する技術です。

Beautiful Soup

Beautiful Soupは、Pythonのライブラリの一つ。スクレイピングに特化しています。HTMLデータの構文の解析を行うために、HTMLタグ/CSSのセレクタで抽出する部分を指定することが可能です。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

0グッド

1クリップ

投稿2020/04/25 17:23

前提・実現したいこと

pythonのBeautiful Soupを用いてスクレイピングを行っております。
用いているサイトはこちら(netkeibaへのリンク)で、実現したいことは、レース表を取得することです。
Chromeのデベロッパーツールを用いてレース表の場所を探し出し、find_all()で適宜条件を指定すれば取得できるはずだと思い実行してみたのですが、なぜかうまくいきません。
取得したいレース表と、該当する階層の画像を以下に添付します。
レース表
デベロッパーツール

発生している問題・エラーメッセージ

ホームページ上で確認できる階層にたどり着けない(見つけられない)。
find_all()で検索をしても[]が返ってくる。

取得したい場所は

<dl class="RaceList_DataList">...</dl>

なのですが、find_all()関数では、その場所を見つけることができませんでした。

該当のソースコード

python

1def func(x): 2 http = urllib3.PoolManager() 3 response = http.request('GET',x) 4 5 return BeautifulSoup(response.data, "html.parser") 6 7url = "https://race.netkeiba.com/top/race_list.html?kaisai_date=20200412" 8soup.find_all("dl", class_="RaceList_DataList") 9# 返り値 10# []

試したこと

他にもいくつかの方法で探してみましたが、手がかりは見つかりませんでした。

python

1soup.find_all("div", id="date_list") 2# [<div class="RaceList_Area" id="date_list"></div>]

python

1soup.find_all("div", id="race_list") 2""" 3[<div id="race_list"> 4 <div class="RaceList_Area" id="date_list"></div> 5 <div id="JraDigestPlaceHolder"></div> 6 <div class="Contents_Box Top_RaceDigest" id="JraDigest"></div> 7 <script type="text/javascript"> 8 〜〜省略〜〜 9 </script> 10 <div class="FileLoader"><img alt="" src="https://cdn.netkeiba.com/img.racev3/common/img/common/gif-load.gif?2019080101"/></div> 11 </div>] 12"""

また、selectorを使ってみましたが、同じ結果を返しました。

python

1soup.select('#RaceTopRace > div > dl:nth-child(1)') 2# []

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

こちらのnetkeiba.comさんのページですが
HTMLをJavScriptで色々と処理をしています
urllibをそのまま使ってしまうとJavaScriptで色々と処理をする前の
HTMLを取得してしまいます
※この色々な処理のことをブラウザレンダリングと呼んだりします
※詳細はググってください

引用されているリンクを開き「ページのソースを表示する」を押して
RaceList_DataListを検索していただければ、検索結果が0/0になると思います
なぜならレンダリング前のソースが表示されているからです
urllibで取得しているHTMLというのはそれと同じものです

response = http.request('GET',x)を実行した時には
レンダリングされていない生のHTMLを取得しているため
そもそも<dl class="RaceList_DataList">...</dl>が存在しない
という感じになっています

他の回答者様が仰っている
「CSSが複雑だからBeautifulSoupで要素が見つからない」 のではなくて
「そもそも取得したHTMLにRaceList_DataList要素が無い」
=> 当然 BeautifulSoupでは要素が見つからないということです
その他のタグも同様にそもそもHTMLにタグが無いので見つからないです

よってただ生のHTMLではなくてレンダリング後のHTMLを取得する必要があります
Pythonではいくつか方法はありますがseleniumを使う方法がすごくおすすめです

私の環境(Ubuntu18.04 Python3.6.9)で実行できることを確認しています
※ Windowsをお使いの場合は環境変数の設定等が必要かもしれません

環境

my_env

1# パッケージのバージョンです 2$ pip freeze | grep -e selenium -e beautifulsoup4 -e chromedriver-binary 3beautifulsoup4==4.8.2 4chromedriver-binary==83.0.4103.14.0 5selenium==3.141.0

コード

python

1""" 2Scraping with Selenium 3 4$ pip install selenium 5$ pip install beautifulsoup4 6$ pip install chromedriver-binary 7""" 8 9from selenium import webdriver 10from bs4 import BeautifulSoup as bs 11import time 12 13 14def scraping(url): 15 16 # ============================================ 17 # さっそくおまじないです 18 # 説明量が膨大になるため割愛します 19 options = webdriver.ChromeOptions() 20 21 # headless モードを有効にします 22 # これを付けないと実際にWebブラウザ(Chrome)が立ち上がるのでびっくりします 23 options.add_argument('--headless') 24 25 # ブラウザを起動する 26 driver = webdriver.Chrome(options=options) 27 28 # url から get します 29 driver.get(url) 30 31 # いったん落ち着かせます 32 time.sleep(2) 33 34 # レンダリング後のHTMLを取得できます 35 html = driver.page_source 36 37 # もし文字化けしたら、こちらでいけると思います(たぶん) 38 # html = driver.page_source.encode('euc_jp') 39 40 41 # ============================================ 42 # ここからはいつものBeautifulsoupです 43 # 取得したhtmlは完全版なのでご自由にタグなりリンクなりを抜いてください 44 45 soup = bs(html, 'lxml') 46 47 filter_tag = '.RaceList_DataList' 48 for elem in soup.select(filter_tag): 49 print('***' * 8) 50 print(elem) 51 52 53if __name__ == "__main__": 54 url = 'https://race.netkeiba.com/top/race_list.html?kaisai_date=20200412' 55 scraping(url) 56 57 58 59"""出力結果 60 61$ py scraping_with_selenium.py 62 63************************ 64<dl class="RaceList_DataList"> 65<dt class="RaceList_DataHeader"> 66<p class="RaceList_DataTitle"><small>3回</small> 中山 <small>6日目</small></p> 67<div class="RaceList_DataDesc"> 68<span class="Weather">天気:<span class="Icon_Weather Weather02"></span></span> 69<span class="Shiba">芝:稍</span> 70<span class="Da">ダ:稍</span> 71</div> <!-- /.RaceList_DataDesc --> 72<a class="LinkHaraimodoshiichiran" href="../top/payback_list.html?kaisai_id=2020060306&amp;kaisai_date=20200412&amp;rf=race_list">払戻一覧</a> 73</dt> 74<dd class="RaceList_Data"> 75<ul> 76<li class="RaceList_DataItem hasMovieLink"> 77 78...(中略)... 79 80 81************************ 82<dl class="RaceList_DataList"> 83<dt class="RaceList_DataHeader"> 84<p class="RaceList_DataTitle"><small>2回</small> 阪神 <small>6日目</small></p> 85<div class="RaceList_DataDesc"> 86<span class="Weather">天気:<span class="Icon_Weather Weather03"></span></span> 87<span class="Shiba">芝:重</span> 88<span class="Da">ダ:重</span> 89</div> <!-- /.RaceList_DataDesc --> 90<a class="LinkHaraimodoshiichiran" href="../top/payback_list.html?kaisai_id=2020090206&amp;kaisai_date=20200412&amp;rf=race_list">払戻一覧</a> 91</dt> 92<dd class="RaceList_Data"> 93<ul> 94 95... 96 97"""

お時間がありましたらレンダリング前と後のHTMLを見比べてみてはいかがでしょうか
サイトの構造が全然違って見えるはずです

他の方法ですとPhntomJSを使う、requests_htmlを使う、
そもそもJavaScriptを使うなど方法は色々とあるようですが
seleniumはとても使い勝手が良いので試してみてくだしあ

投稿2020/04/25 22:23

dullcodes

総合スコア10

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

metrobaroque

2020/04/26 04:07

ご回答いただきありがとうございました。 おっしゃる通り、レンダリングについて理解しないまま取り組んでおりました。 いただいたソースコードもとても役に立ちました。ありがとうございます。 最後にBeautifulSoupで整形するところ、自分の環境では bs(html, "html.parser") とすることで欲しい形になったことを報告させていただきます。
dullcodes

2020/04/26 11:07 編集

soup = bs(html, 'lxml') について lxmlはpythonの外部ライブラリであり、pip install が必要なことを すっかり忘れており説明を記入しておりませんでした 大変申し訳ありません スクレイピングのほうが上手くいったという事で一安心です これからも頑張ってください!
guest

0

BeautifulSoupは、CSS(Webページのスタイル)が複雑だと、要素を見つけられないことがあるようです。
https://gammasoft.jp/blog/how-to-download-web-page-created-javascript/
ここにも書いているように、Seleniumを使うことをお勧めします。Seleniumでは、
BeautifulSoupは、HTMLを読み込むのに対して、
SeleniumはWebDriverでWebページから直接要素を探し出すので、より詳細に調べることが可能です。いちいちWebページが動くので動作が多少遅くなりますが、質問にあるような状況では問題ないかと思います。
また、Seleniumをバックグラウンドで動かすこともできるみたいです。(自分用の備忘録)
https://watlab-blog.com/2019/08/18/selenium-chrome-background/

手前味噌ですが、私も競馬サイトのスクレイピングを実装したことがあり、BeautifulSoupでやろうとしてできなかったので、Seleniumにしました。Seleniumの方がよさそうです!

投稿2020/04/25 17:53

Matsui_hero

総合スコア346

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

metrobaroque

2020/04/26 04:08

早速のご回答ありがとうございました。 そもそもSeleniumを用いないと探し出すことすら不可能なんですね。 いただいたリンクも拝見させていただきます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問