C# でお手軽スクレイピング 2020 年夏よりちょっと未来

@otchy さんの [Node でお手軽スクレイピング 2020 年夏](https://qiita.com/otchy/items/244c19c561ecb7211fa5) を見て自分も C# でやってみようと思いました。

## HTML パーサー

[C#でモダンにスクレイピングするならAngleSharp](https://qiita.com/matarillo/items/a92e7efbfd2fdec62595) で紹介されている AngleSharp を使ってみようと思います。

## C# 9.0 でやろう

node.js とかのお手軽なところとして CLI でサクッと作れてファイルにおもむろに `console.log('xxx');` のように書き始められるところがあると思います。
C# 9.0 (現時点ではまだプレビュー) でも [トップ レベル ステートメント](https://ufcpp.net/study/csharp/cheatsheet/ap_ver9/#top-level-statements) という機能が追加されて、同じ要領で書けるようになります。素敵。

### CLI でさくっと

.NET 5 のプレビュー SDK を入れます。VSCode の C# の拡張機能も入れておきましょう。

私が試した .NET の SDK のバージョンは以下の通りです。

```
> dotnet --version
5.0.100-preview.6.20318.15
```

では、コンソール アプリのプロジェクトを作って HTML パーサーのパッケージを追加します。どうせ、ちょっと未来を体験するつもりなので最新のプレビュー版を入れることにしました。

コマンドとしては以下のようになります。

```
> dotnet new console
> dotnet add package AngleSharp --version 1.0.0-alpha-827
```

拡張子が csproj のファイルを開いて言語のバージョンをプレビューにしておきます。最新の VS2019 プレビューだとデフォルトが C# 9.0 になってるっぽいけど、この定義を追加しないで CLI からビルドするとエラーになった。何が違うんだろう…。

```xml
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net5.0</TargetFramework>
    <LangVersion>preview</LangVersion> <!-- この行追加 -->
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="AngleSharp" Version="1.0.0-alpha-827" />
  </ItemGroup>

</Project>
```


コードは、以下のような感じになります。Main メソッドと、それを囲むクラスや名前空間とかの定義がまるっといらなくなって凄くすっきりしますね。

```csharp:Program.cs
// 必要な名前空間を using
using System;
using System.Linq;
using System.Net.Http;
using AngleSharp.Html.Parser;

// ページの HTML を取得
var client = new HttpClient();
var res = await client.GetStringAsync("https://www.jma.go.jp/jp/week/319.html");
// HTML をパース
var parser = new HtmlParser();
var doc = await parser.ParseDocumentAsync(res);
// セレクターで目的の要素をゲット
var nodes = doc.QuerySelectorAll("#infotablefont tr:nth-child(4) td");

// 整形して出力
var tokyoWeathers = string.Join(", ", nodes.Select(x => x.TextContent.Trim()));
Console.WriteLine(tokyoWeathers);
```

実行してみましょう。`dotnet run` で実行できます。

```
> dotnet run
曇のち時々雨, 曇一時雨, 曇, 曇, 曇時々晴, 曇時々晴, 曇
```

因みに exe にしたかったら `dotnet publish` コマンドで出来ます。本番用なら `-c Release` にすることでリリース モードでのビルドです。

```
> dotnet publish -c Release
.NET 向け Microsoft (R) Build Engine バージョン 16.7.0-preview-20310-07+ee1c9fd0c
Copyright (C) Microsoft Corporation.All rights reserved.

  復元対象のプロジェクトを決定しています...
  復元対象のすべてのプロジェクトは最新です。
  プレビュー版の .NET Core を使用しています。https://aka.ms/dotnet-core-preview をご覧ください
  SampleApp -> C:\Labs\SampleApp\bin\Release\net5.0\SampleApp.dll
  SampleApp -> C:\Labs\SampleApp\bin\Release\net5.0\publish\
```

プロジェクトの bin\Release\net5.0\publish フォルダーに、こんな感じの成果物が出来上がります。

```
Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a---          2020/07/14    23:29         832512 AngleSharp.dll
-a---          2020/07/21    19:35           2524 SampleApp.deps.json
-a---          2020/07/21    19:35           6656 SampleApp.dll
-a---          2020/07/21    19:35         144896 SampleApp.exe
-a---          2020/07/21    19:35           9676 SampleApp.pdb
-a---          2020/07/21    19:35            165 SampleApp.runtimeconfig.json
```

ここではやりませんが、やろうと思えばランタイム不要な単一 exe にもビルド出来ます。では、exe も実行してみましょう。

```
> .\SampleApp.exe
曇のち時々雨, 曇一時雨, 曇, 曇, 曇時々晴, 曇時々晴, 曇
```

当然ですがちゃんと動きました。.NET Core 2.1 以降は .NET Core ツールという仕組みもあって、これを使うと `npm install` でインストールできるツールのようなのと同じ感覚でインストール可能なツールを作ることが出来ます。

[.NET Core ツールの管理方法](https://docs.microsoft.com/ja-jp/dotnet/core/tools/global-tools)

## GUI でも

Visual Studio 2019 Preview 版を入れると CLI でやってたことが GUI でもぽちぽちできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/70288/661e746d-902d-dd9b-7135-7ee847755575.png)

Visual Studio Code でもコードを書けますが追加するパッケージを GUI で確認したり、コード補完が Code よりも強力な部分があったりと、まだ VS Code より多少重くても（個人の感覚）C# を書く場合には VS 2019 のほうを使ってしまいます。

## まとめ

C# でもスクレイピングをさくっと出来たのと C# 9.0 のトップ レベル ステートメントは、単純にコードが短くなって素敵なので正式リリースが待ち遠しいです。