C# .NetCoreで、ボートレース結果の解析　スタ展スクレイピング

# やらなきゃならないこと
ボートレース公式サイトからスタート展示情報のスクレイピングを行う。

## 開発環境
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,
```

## まとめ
スクレイピングが可能になった。
試しに１年間分を取得間隔2.5秒で実施したら、3日かかった。

次回は今まで取得したデータをまとめていきたいと思う。