やらなきゃならないこと
ボートレース公式サイトからスタート展示情報のスクレイピングを行う。
開発環境
Windows10
Visual Studio Community 2019
C# .Net Core 3.1
注意
スクレイピングは取得先のサーバの過負荷にならないように注意して扱うこと。
また、スクレイピングに関する規定があるため、確認は行うこと。
.NetCoreでのスクレイピング
参考:https://www.casleyconsulting.co.jp/blog/engineer/183/
大まか流れ
- URLに対しての
Request
を作成 - URLに対して
Request
を投げResponse
を取得。 - 必要な内容をパターンで検出する。
Requestを生成
var req = (HttpWebRequest)System.Net.WebRequest.Create(string url)
でURLに対するリクエストを生成する。
Requestに対するResponseを取得
var resreq = (HttpWebResponse)req.GetResponse()
Responseを読み込むためにStreamを取得
var resSt = resreq.GetResponseStream()
Streamを使いHTMLを読み込む。
string htmlData = "";
using( var sr = new StreamReader(resSt, Encoding.UTF8)) )
{
htmlData = sr.ReadToEnd()
}
まとめると
static public string GetHtmlString(string url)
{
string rtn = "";
var webReq = (HttpWebRequest)WebRequest.Create(url);
using (var webResponse = (HttpWebResponse)webReq.GetResponse())
using (var responseStream = webResponse.GetResponseStream())
using (var streamReader = new StreamReader(responseStream, Encoding.UTF8))
{
rtn = streamReader.ReadToEnd();
}
return rtn;
}
実際にやる
直前情報のURLを対象に実際にやってみる。
URLパターン
https://www.boatrace.jp/owpc/pc/race/beforeinfo?rno=[RaceNum]&jcd=[RacePlace]&hd=[RaceDate]
- [RaceNum]:レース番号(1,2,3,4,5,6,7,8,9,10,11,12)
- [RacePlace]:開催場下2桁固定(01,02,03,.....,21,22,23,24)
- [RaceDate]:開催年月日8桁(yyyymmdd)
例:2020年9月31日 ボートレース戸田 8R の場合(実際あるかは知らない)
https://www.boatrace.jp/owpc/pc/race/beforeinfo?rno=8&jcd=02&hd=20200931
HTMLのパターン
実際に取得しパターンを確認してみた。
以下の部分がスタート展示の情報。
<tr>
<td colspan="3">
<div class="table1_boatImage1">
<span class="table1_boatImage1Number is-type1">1</span>
<span class="table1_boatImage1Line"><span class="table1_boatImage1Boat" style="left: 59%;"><img src="/static_extra/pc/images/img_boat2_1.png" width="54" height="27" alt=""></span></span>
<span class="table1_boatImage1Time">.06</span>
</div><!-- /.table1_boatImage1 -->
</td>
</tr>
<tr>
<td colspan="3">
<div class="table1_boatImage1">
<span class="table1_boatImage1Number is-type2">2</span>
<span class="table1_boatImage1Line"><span class="table1_boatImage1Boat" style="left: 37%;"><img src="/static_extra/pc/images/img_boat2_2.png" width="54" height="27" alt=""></span></span>
<span class="table1_boatImage1Time">.28</span>
</div><!-- /.table1_boatImage1 -->
</td>
</tr>
<tr>
<td colspan="3">
<div class="table1_boatImage1">
<span class="table1_boatImage1Number is-type3">3</span>
<span class="table1_boatImage1Line"><span class="table1_boatImage1Boat" style="left: 56%;"><img src="/static_extra/pc/images/img_boat2_3.png" width="54" height="27" alt=""></span></span>
<span class="table1_boatImage1Time">.09</span>
</div><!-- /.table1_boatImage1 -->
</td>
</tr>
<tr>
<td colspan="3">
<div class="table1_boatImage1">
<span class="table1_boatImage1Number is-type4">4</span>
<span class="table1_boatImage1Line"><span class="table1_boatImage1Boat" style="left: 42%;"><img src="/static_extra/pc/images/img_boat2_4.png" width="54" height="27" alt=""></span></span>
<span class="table1_boatImage1Time">.23</span>
</div><!-- /.table1_boatImage1 -->
</td>
</tr>
<tr>
<td colspan="3">
<div class="table1_boatImage1">
<span class="table1_boatImage1Number is-type5">5</span>
<span class="table1_boatImage1Line"><span class="table1_boatImage1Boat" style="left: 54%;"><img src="/static_extra/pc/images/img_boat2_5.png" width="54" height="27" alt=""></span></span>
<span class="table1_boatImage1Time">.11</span>
</div><!-- /.table1_boatImage1 -->
</td>
</tr>
<tr>
<td colspan="3">
<div class="table1_boatImage1">
<span class="table1_boatImage1Number is-type6">6</span>
<span class="table1_boatImage1Line"><span class="table1_boatImage1Boat" style="left: 38%;"><img src="/static_extra/pc/images/img_boat2_6.png" width="54" height="27" alt=""></span></span>
<span class="table1_boatImage1Time">.27</span>
</div><!-- /.table1_boatImage1 -->
</td>
</tr>
上から1,2,3,4,5,6コースとなる(艇番ではなく)
競番の検出はここで行う。
<span class="table1_boatImage1Number is-type[Course]">[Value]</span>
- [Course]:コース
- [Value]:枠番
タイムの検出はここで行う。
<span class="table1_boatImage1Time">[Time]</span>
- [Time]:スタートタイム(.XX)
実際にまとめると以下の通りとなる。
static public string[] SearchTenjiSt(string html)
{
var lines = html.Split('\n');
string[] rtn = new string[12] { "", "", "", "", "", "", "", "", "", "", "", "" };
int num = 0;
foreach (var line in lines)
{
if (line.Contains("table1_boatImage1Number"))
{
var temp = line.Replace("<", ">");
var temp2 = temp.Split(">");
rtn[num++] = temp2[2];
}
if (line.Contains("table1_boatImage1Time"))
{
var temp = line.Replace("<", ">");
var temp2 = temp.Split(">");
rtn[num++] = temp2[2];
}
}
if (num == 0)
{
rtn = null;
}
return rtn;
}
実行結果
まとめることが可能になった。
2019,10,01,5,1,1,.06,2,.28,3,.09,4,.23,5,.11,6,.27,
まとめ
スクレイピングが可能になった。
試しに1年間分を取得間隔2.5秒で実施したら、3日かかった。
次回は今まで取得したデータをまとめていきたいと思う。