Monthly Hacker's Blog

毎月のテーマに沿ったプログラミング記事を中心に書きます。

Yahooスポーツナビから競馬データをスクレイピングする

やること

Yahooスポーツナビ 競馬
keiba.yahoo.co.jp

から、競走馬の出走レースの記録をスクレイピングします。

使用したライブラリ

使用したライブラリは
・Beautiful Soup(以下bs)
・urllib
・selenium
です。

また、今回はPython3で行いました。

取得対象について

競走馬検索を行うと以下のように競走馬一覧のページが表示されます。

f:id:Duramente:20160713002815p:plain

このページから各競走馬の詳細ページへ飛び、詳細情報を見ることができます。
以下の画像はアイアムナチュラルという馬の出走レースの記録です。

f:id:Duramente:20160713002654p:plain

この出走レースの記録をスクレイピングします。

取得の流れ

  1. bsとurllibを用いて各競走馬の詳細ページのURLを取得
  2. seleniumを用いて詳細ページのHTMLを取得
  3. bsを用いてHTMLから必要情報を取得

今回seleniumを用いたのは、詳細ページの取得したい部分がJavaScriptで生成されているため、bsではうまく取得できなかったからです。

結果

f:id:Duramente:20160713002328p:plain

ソースコード

# -*- coding: utf-8 -*-
# python3

import urllib.request
import urllib.parse
from bs4 import BeautifulSoup
# selenium import
from selenium import webdriver
from selenium.webdriver.common.keys import Keys


# 各馬の詳細情報ページのURLを取得し、リストに格納

start_url = 'http://keiba.yahoo.co.jp'

url_1 = 'http://keiba.yahoo.co.jp/directory/horsesearch/?status=1&p='
url_2 = '&sidx=&dir=1'
url_3 = '?d=1'

horse_url_list = []

last_page = 400

for p in range(1,last_page):

	time.sleep(1)
	target_url = url_1 + str(p) + url_2
	htmlfp = urllib.request.urlopen(target_url)
	html = htmlfp.read()
	soup = BeautifulSoup(html)

	# tag_select
	table = soup.find("table", {"class": "dataLs mgnBS"})

	trs = table.findAll("tr")[1: -1]
	
	for tr in trs:
		horse_url = tr.find("a")["href"]
		horse_url_list.append(horse_url)



# 先ほど取得した各馬の詳細ページから必要な情報を取得し、リストに格納

data_list = []

driver = webdriver.Chrome('./chromedriver')

for t_url in horse_url_list:

	time.sleep(1)
	target_url = start_url + str(t_url) + url_3
	driver.get(target_url)
	html = driver.page_source


	soup = BeautifulSoup(html)

	# 馬の名前を取得
	horse_name = soup.find("h1", {"class": "fntB"}).text
	# idが"resultLs"であるtableタグを取得(このtableタグに欲しい情報がある)
	table = soup.find("table", {"id": "resultLs"})

	# try,exceptで書いているのは、出走レース情報がない馬が存在するため
	try:
		# tableタグからtrタグをすべて取得
		trs = table.findAll("tr")
		for i, tr in enumerate(trs):
			# 1レースの情報を格納するリスト、先頭は馬の名前
			data = [horse_name]

			# 最初の行と最後の行はヘッダーなので飛ばす
			if i != 1 and i != len(trs):
				# trタグからtdタグをすべて取得
				tds = tr.findAll("td")
				for td in tds:
					# dataに出走レースの情報を加えていく
					d = td.text
					data.append(d)

	except:
		continue
	# 1行のすべての情報をdataにappendしたらdata_listにappend
	data_list.append(data)

for d in data_list:
	print d

スクレイピングは以下の部分で行なっています。

soup = BeautifulSoup(html)

# 馬の名前を取得
horse_name = soup.find("h1", {"class": "fntB"}).text
# idが"resultLs"であるtableタグを取得(このtableタグに欲しい情報がある)
table = soup.find("table", {"id": "resultLs"})

# try,exceptで書いているのは、出走レース情報がない馬が存在するため
try:
	# tableタグからtrタグをすべて取得
	trs = table.findAll("tr")
	for i, tr in enumerate(trs):
		# 1レースの情報を格納するリスト、先頭は馬の名前
		data = [horse_name]

		# 最初の行と最後の行はヘッダーなので飛ばす
		if i != 1 and i != len(trs):
			# trタグからtdタグをすべて取得
			tds = tr.findAll("td")
			for td in tds:
				# dataに出走レースの情報を加えていく
				d = td.text
				data.append(d)

except:
	continue
# 1行のすべての情報をdataにappendしたらdata_listにappend
data_list.append(data)