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

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

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

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

Python

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

Q&A

解決済

1回答

2051閲覧

競馬のスクレイピング

rikuanpg9294

総合スコア15

スクレイピング

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

Python

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

0グッド

0クリップ

投稿2021/05/13 12:45

編集2021/05/13 23:23

予想する地方競馬の出馬表をスクレイピングを行った際以下のようなエラーが発生しました。
なぜ範囲外になるかが分かりません。
どのように書き換えれば上手くいくかご教示ください。よろしくお願いいたします。

python

1race_id_list = "202130051304" 2st = ShutubaTable.scrape(race_id_list, '2021/5/13')

python

1--------------------------------------------------------------------------- 2IndexError Traceback (most recent call last) 3<ipython-input-18-da19651b9347> in <module> 4 1 race_id_list = "202130051304" 5----> 2 st = ShutubaTable.scrape(race_id_list, '2021/5/13') 6 7<ipython-input-9-ff97b4e36758> in scrape(cls, race_id_list, date) 8 20 for text in texts: 9 21 if 'm' in text: 10---> 22 df['course_len'] = [int(re.findall(r'\d+', text)[0])] * len(df) 11 23 if text in ["曇", "晴", "雨", "小雨", "小雪", "雪"]: 12 24 df["weather"] = [text] * len(df) 13 14IndexError: list index out of range

python

1class ShutubaTable(DataProcessor): 2 def __init__(self, shutuba_tables): 3 super(ShutubaTable, self).__init__() 4 self.data = shutuba_tables 5 6 @classmethod 7 def scrape(cls, race_id_list, date): 8 data = pd.DataFrame() 9 for race_id in tqdm(race_id_list): 10 url = 'https://nar.netkeiba.com/race/shutuba.html?race_id=' + race_id #narに変更 11 df = pd.read_html(url)[0] 12 df = df.T.reset_index(level=0, drop=True).T 13 14 html = requests.get(url) 15 html.encoding = "EUC-JP" 16 soup = BeautifulSoup(html.text, "html.parser") 17 18 texts = soup.find('div', attrs={'class': 'RaceData01'}).text 19 texts = re.findall(r'\w+', texts) 20 for text in texts: 21 if 'm' in text: 22 df['course_len'] = [int(re.findall(r'\d+', text)[0])] * len(df) 23 if text in ["曇", "晴", "雨", "小雨", "小雪", "雪"]: 24 df["weather"] = [text] * len(df) 25 if text in ["良", "稍重", "重"]: 26 df["ground_state"] = [text] * len(df) 27 if '不' in text: 28 df["ground_state"] = ['不良'] * len(df) 29 # 2020/12/13追加 30 if '稍' in text: 31 df["ground_state"] = ['稍重'] * len(df) 32 if '芝' in text: 33 df['race_type'] = ['芝'] * len(df) 34 if '障' in text: 35 df['race_type'] = ['障害'] * len(df) 36 if 'ダ' in text: 37 df['race_type'] = ['ダート'] * len(df) 38 df['date'] = [date] * len(df) 39 40 # horse_id 41 horse_id_list = [] 42 horse_td_list = soup.find_all("td", attrs={'class': 'HorseInfo'}) 43 for td in horse_td_list: 44 horse_id = re.findall(r'\d+', td.find('a')['href'])[0] 45 horse_id_list.append(horse_id) 46 # jockey_id 47 jockey_id_list = [] 48 jockey_td_list = soup.find_all("td", attrs={'class': 'Jockey'}) 49 for td in jockey_td_list: 50 jockey_id = re.findall(r'\d+', td.find('a')['href'])[0] 51 jockey_id_list.append(jockey_id) 52 df['horse_id'] = horse_id_list 53 df['jockey_id'] = jockey_id_list 54 55 df.index = [race_id] * len(df) 56 data = data.append(df) 57 time.sleep(1) 58 return cls(data) 59

イメージ説明

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

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

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

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

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

guest

回答1

0

ベストアンサー

前提

該当のURLはクエリパラメータにrace_idが値付きで指定されていれば、
そのIDでレース情報を取得して表示します。

指定したIDが間違っていた場合、別にエラーなどが出るわけでなく、
データが空っぽなガワだけのレスポンスを返します。

問題点

python

1>>> race_id_list = ['2020010106{}'.format(str(i).zfill(2)) for i in range(1, 13, 1)] 2>>> race_id_list 3['202001010601', '202001010602', '202001010603', '202001010604', '202001010605', '202001010606', '202001010607', '202001010608', '202001010609', '202001010610', '202001010611', '202001010612']

質問文にあるコードをもとにrace_idを生成すると上記のようになりますが、ID=202001010601のレースは存在しません。
そのため、前述の通り「ガワだけ」のレスポンスになっています。(実例

そのため、正常なデータのみを前提にしている場合パースに失敗します。

※ちなみに、おそらくIDのフォーマット的にそもそも最初の生成から間違っている気がします

どうするべきか

  • 正しいIDを生成する
  • データが正しくない場合にスキップする

まずは、サイトのURL情報を見回って、IDがどういうルールで生成されているかを確認したほうがいいでしょう。
その上で、とりたいデータのIDを作る必要があります。

また、イレギュラーなケースがあれば正しいロジックの途中でも同じ現象が発生することがあります。
事前に、「レスポンスは正しくレース結果を含むか」を判断できる処理を用意したほうがいいでしょう。

投稿2021/05/13 15:54

attakei

総合スコア2740

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

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

rikuanpg9294

2021/05/13 23:29

ご指摘された問題点のところを変更し、1レース分を取り出したのですが同じエラーが出てしまいました。 "202130051304"のレースidを確認したところ、データは空ではありませんでした。 スクリーンショットの様に行うと、データは取り出されている様に見えるのですが、classで行うとエラーは改善されません。
attakei

2021/05/14 09:14 編集

race_id_list = "202130051304" だと文字列型なので、スクレイピング処理において 2, 0, 2, 1, 3, 0, 0, 5, 1, 3, 0 , 4 に分割してループされると思います。 真っ先に、ループ内でURLなどをprintするようにして「このプログラムがどこからデータを取るようにしているか」の把握をしたほうが良さそうです。 おそらく、race_id=2でアクセスしようとしてます その上で、元々の処理的にrace_id_list が持つべきなのはrace_idのリストなので、 ["202130051304"]としたほうが良いでしょう。
rikuanpg9294

2021/05/14 13:41

ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問