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

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

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

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

Beautiful Soup

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

Python

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

HTML

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

Q&A

解決済

1回答

2893閲覧

【Python】【HTML】スクレイピング:競馬サイトnetkeibaの出馬表からオッズと人気データをスクレイピングする方法

takataka_11

総合スコア2

スクレイピング

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

Beautiful Soup

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

Python

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

HTML

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

0グッド

1クリップ

投稿2020/05/30 05:21

編集2020/05/30 05:48
コード ```### 前提・実現したいこと netkeibaの出馬表ページから単勝オッズと人気をスクレイピングしたい 参考ページ:https://race.netkeiba.com/race/shutuba.html?race_id=202005021211 ページソースの一部______________________________ ```HTML <td class="Barei">牡3</td> #馬齢 <td class="Txt_C">57.0</td> #斤量 <td class="Txt_R Popular"><span id="odds-1_03" style="font-weight : bold">---.-</span></td> #単勝オッズ <td class="Popular Popular_Ninki Txt_C">  <span id="ninki-1_03">**</span> #人気 </td>

________________________________________
python3.7 beautifulsoupを使ってスクレイピングをしています
ページソースのタグとclassを頼りにしてtextを取得する形でスクレイピングを試みているのですが、ページソースの単勝オッズ、人気のtextが、ページにでている数値と異なっており正しくスクレイピングできません

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

ページソースのtextにオッズ・人気データが直接書き込まれていないためスクレイピングができない

該当のソースコード(一部)#タグとclassを頼りにtextを引き抜いています

python

1soup = BeautifulSoup(r_text,"html.parser") 2HorseLists = soup.find_all("tr",class_="HorseList") 3 4for HorseList in HorseLists: 5 X = HorseList.find("td","Jockey").get_text() 6 Jockey.append(X.strip()) 7 X = HorseList.find("td",class_="Txt_C").get_text() 8 Waku.append(X.strip()) 9 X = HorseList.find_all("td",class_="Txt_C")[1].get_text() #find_allの(0から数えて)1番目だけ抽出 10 Umaban.append(X.strip()) 11 X = HorseList.find_all("td",class_="Txt_C")[2].get_text() #find_allの2番目だけ抽出 12 Kinryo.append(X.strip()) 13 X = HorseList.find("td",class_ ="Trainer").get_text() 14 Trainer.append(X.strip()) 15 X = HorseList.find("td",class_ ="Txt_R Popular").get_text() 16 odds.append(X.strip())

試したこと

このページソースの単勝オッズと人気の値はおそらく別のサイト?かどこかから値を引っ張て来ているのだろうとは思うのですが、HTMLに関する知識が乏しく、ページソース全体を見渡してみてもどういった構造になっているのかが理解できていない状況です

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

python3.7 windows10

スクレイピングするサイトのソース一部抜粋

HTML

1<!DOCTYPE html> 2<html> 3<head> 4<meta charset="EUC-JP"> 5 6_______________________________________________________________ 7<tr class="HorseList" id="tr_9"> 8<td class="Waku1 Txt_C"><span>1</span></td> 9<td class="Umaban1 Txt_C">1</td> 10<td class="CheckMark Horse_Select"> 11 12<select class="makeMeFancy_9" name="9" id="mark_9" style="display: none;"> 13<option data-html-text="--" value="1_0">--</option><option data-html-text="◎" value="1_1">◎</option><option data-html-text="◯" value="1_2">◯</option><option data-html-text="▲" value="1_3">▲</option><option data-html-text="△" value="1_4">△</option><option data-html-text="☆" value="1_5">☆</option><option data-html-text="&amp;#10003" value="1_98">&amp;#10003</option><option data-html-text="消" value="1_99">消</option> 14</select> 15</td> 16<td class="HorseInfo"> 17<div> 18<div> 19 <span class="HorseName"><a href="https://db.netkeiba.com/horse/2017104753" target="_blank" title="サトノインプレッサ">サトノインプレッサ<img id="myhorse_2017104753" class="disp_none Favorite" src="https://cdn.netkeiba.com/img.racev3/common/img/icon/icon_horse.png?2019073001" alt="" width="18"></a></span> 20</div> 21</div> 22</td> 23<td class="Barei">牡3</td> 24<td class="Txt_C">57.0</td> 25<td class="Jockey"> 26<a href="https://db.netkeiba.com/jockey/01163/" target="_blank" title="坂井">坂井</a> 27 28 29</td> 30<td class="Trainer"><span class="Label2">栗東</span><a href="https://db.netkeiba.com/trainer/01075/" target="_blank" title="矢作">矢作</a></td> 31<td class="Weight"> 32 33</td> 34<td class="Txt_R Popular"><span id="odds-1_01" style="font-weight : bold">---.-</span></td> 35<td class="Popular Popular_Ninki Txt_C"> 36<span id="ninki-1_01">**</span> 37</td> 38<td class="FavRegist Txt_C"> 39<a href="../popup/horse_bookmark.html?ketto_num=2017104753&race_id=202005021211" title="お気に入り馬登録" class="popup_link_04 cboxElement cboxElement_Nologin"> 40<img src="https://cdn.netkeiba.com/img.racev3/common/img/icon/prof_icon_favhorse_comp_01.png?2019073001" class="horsebookmark myhorse1_2017104753" onmouseover="this.src='https://cdn.netkeiba.com/img.racev3/common/img/icon/prof_icon_favhorse_comp_01.png?2019073001'" onmouseout="this.src='https://cdn.netkeiba.com/img.racev3/common/img/icon/prof_icon_favhorse_comp_01.png?2019073001'"> 41<img id="myhorse1_2017104753" src="https://cdn.netkeiba.com/img.racev3/common/img/icon/prof_icon_favhorse_comp_02.png?2019073001" class="disp_none horsebookmark myhorse_2017104753" onmouseover="this.src='https://cdn.netkeiba.com/img.racev3/common/img/icon/prof_icon_favhorse_comp_02.png?2019073001'" onmouseout="this.src='https://cdn.netkeiba.com/img.racev3/common/img/icon/prof_icon_favhorse_comp_02.png?2019073001'"> 42</a> </td> 43<td class="FavMemo"><div><a href="../popup/horse_bookmark.html?ketto_num=2017104753&race_id=202005021211" id="Bamei_2017104753" title="" class="popup_link_04 cboxElement"></a></div></td> 44</tr> 45_________________________________________________________________ 46 47<div style="display:none;" id="free_odds_limit_overlay"></div> 48<script type="text/javascript"> 49$(function(){ 50//tablesorterの不具合のため、馬番がNULLの場合に馬名のソートの振る舞いを変更する 51$("tbody .HorseInfo").each( function() { 52var rowIndex = $(this).parent().index(); 53if ($("tbody [class^=Umaban]").eq(rowIndex).text() == "") { 54$(this).attr("data-sort-value", rowIndex+1); 55} 56}); 57// オッズ更新click 58$(".OddsUpdataBtn").on({"click": 59function(){ 60$(".OddsUpdataBtn").removeClass("OddsUpdataClick"); 61$(".OddsUpdataBtn").addClass("OddsUpdataClick"); 62} 63}); 64}); 65</script> 66<script> 67"use strict" 68$(function(){ 69/* Area created in the intern Start */ 70const nullCheak = function(date){ return !date[0] ? true : false }; 71var firstTime = true; 72const table_sorte = function(t_header_flg){ 73$('.Shutuba_Table th').unbind(); 74$.tablesorter.destroy( $('.Shutuba_Table'), true, function(table) {}); 75$('.Shutuba_Table').tablesorter({ 76headers: { 770: { sorter: "false" }, 781: { sorter: t_header_flg[1] }, 792: { sorter: "false" }, 803: { sorter: "text" }, 814: { sorter: "false" }, 825: { sorter: t_header_flg[5] }, 836: { sorter: "false" }, 847: { sorter: "false" }, 858: { sorter: t_header_flg[8] }, 869: { sorter: "false" }, 8710: { sorter: t_header_flg[10] }, 8811: { sorter: "false" }, 8912: { sorter: "false" }, 9013: { sorter: "false" }, 91}, 92//tablesorterの不具合のため、馬番がNULLの場合に馬名のソートの振る舞いを変更する 93textExtraction: function(node) { 94var attr = $(node).attr('data-sort-value'); 95if (typeof attr !== 'undefined' && attr !== false) { 96return attr; 97} 98return $(node).text(); 99} 100}); 101}; 102// $(window).load(function(){ 103var tableSorteAction = function() { 104const Umaban = $('td.Umaban'); 105const weight = $('td.Weight small'); 106const t_header_icons = $('.sort_icon'); 107// sort flag [0:枠,1:印,2:名,3:オッズ,4:体重] 108var t_sorts_flg = [true,true,true,true,true,true,true,true, true, true, true, false ]; 109// sort Icon generation 110const icon = $('<i></i>',{ 111'class' : 'fas fa-sort', 112}); 113t_header_icons.append(icon); 114// Empty check in frame order 115if($('td').hasClass('Umaban')){ 116t_header_icons[0].remove(); 117t_sorts_flg[1] = false; 118} 119// Empty check of horse weight 120if(!weight.length){ 121t_header_icons[3].remove(); 122// t_sorts_flg[3] = false; 123t_sorts_flg[8] = false; 124} 125table_sorte(t_sorts_flg); 126$('.sort_icon').css("display", "block"); 127$('.sort_icon').show(); 128}; 129/* Area created in the intern End */ 130$.oddsUpdate({ 131apiUrl:'https://race.netkeiba.com/api/api_get_jra_odds.html', 132raceId:'202005021211', 133isPremium:0, 134displayDiffTime:false, 135PremiumLinkReturnUrl : 'http%3A%2F%2Frace.netkeiba.com%2Frace%2Fshutuba.html%3Frace_id%3D202005021211', 136PremiumLinkReturnRf : 'shutuba', 137isBrackets : false, 138compress:true, 139callbackApiComplete:function(_this,_odds_status,_data){ 140// オッズ見出し 141if(_odds_status=='yoso'){ 142$('#odds_title').html('予想<br />オッズ'); 143} else if(_odds_status=='result'){ 144$('#odds_title').html('オッズ'); 145} else if(_odds_status=='middle') { 146$('#premium_guide').show(); 147$('#odds_title').html('オッズ'); 148} else { 149$('#odds_title').html('オッズ'); 150} 151// マイオッズ遷移先 152var action = 'https://race.netkeiba.com'; 153var action_form_pid = '../odds/myodds'; 154if(_odds_status=='yoso'){ 155action = ''; 156action_form_pid = '../odds/index'; 157} 158$('#shutuba_form').attr('action',action_form_pid+".html"); 159// オッズ着色 160$('[id^="odds-1_"]').each(function(){ 161var data_key = $(this).prop('id').replace('odds-','').split('_'); 162var type = data_key[0]; 163var no = data_key[1]; 164if (_data) { 165if(!$.isEmptyObject(_data['odds'][type])){ 166var ary_row = _data['odds'][type]; 167var row = ary_row[no]; 168if (row) { 169$(this).text(row[0]); 170if(type==1){ 171$(this).parent().parent().find(".Popular_Ninki") 172.removeClass("BgYellow") 173.removeClass("BgBlue02") 174.removeClass("BgOrange"); 175if (row[2] == 1) { 176$(this).parent().parent().find(".Popular_Ninki").addClass("BgYellow") 177} else if (row[2] ==2) { 178$(this).parent().parent().find(".Popular_Ninki").addClass("BgBlue02") 179} else if (row[2] ==3) { 180$(this).parent().parent().find(".Popular_Ninki").addClass("BgOrange") 181} 182} 183} 184} 185} 186$(this).parent().removeClass('Odds_Ninki'); 187$(this).removeClass('Odds_Ninki'); 188if($(this).text()<10){ 189$(this).parent().removeClass('Odds_Ninki'); 190$(this).addClass('Odds_Ninki'); 191} 192}); 193var tmDeleteUpdateOddsClass = setTimeout(function(){ 194clearTimeout(tmDeleteUpdateOddsClass); 195$(".Shutuba_Table tr .UpdateOdds").removeClass("UpdateOdds"); 196}, 700); 197if (firstTime) { 198firstTime = false; 199tableSorteAction(); 200} else { 201$(".Shutuba_Table").trigger('update', [true]) 202} 203}, 204}); 205}); 206</script>

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

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

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

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

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

guest

回答1

0

ベストアンサー

該当サイトを見たところ、「オッズ」と「人気」の列はjavascriptで貼り付けられているようなので、requestsなどで入手したhtmlをBeautifulSoupでパースしても抽出出来ないと思います。
javascriptを別に実行して解析するか、seleniumなどブラウザベースのモジュールを使わないと難しいでしょう。

投稿2020/05/30 06:49

x98000

総合スコア1096

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

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

takataka_11

2020/05/31 00:08

ありがとうございます seleniumの使い方を勉強します!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問