ASP.NET Core(C#) + AngleSharp + AWSでスクレイピング結果通知アプリを作ってみた。
はじめに
特定のサイトのお知らせ欄が更新されたかな?と毎回見に行くのが面倒だったのでスクレイピングして結果をLINEで送ってくれるバッチ処理を作ってみました。
アプリ概要と構成図
Amazon EventBridgeが特定の時間になったらLambda関数を実行します。 Lambda関数は実行後、特定のサイトからお知らせ内容をスクレイピングし、LINE Notifyを通して特定のグループLINEへ結果を通知する作りとなっています。 EventBridgeとLambda関数はserverless.templateで管理しています。
アプリ構成図は以下です。
スクレイピング
スクレイピングでは『AngleSharp』というライブラリを使用しました。 anglesharp.github.io
QuerySelectorやGetElementByIdなどJavaScriptでよく使うメソッドが利用できるので、特定のサイトの欲しい箇所を取得するのも結構楽にできました。
public async ValueTask<IHtmlCollection<IElement>> GetTopicDataAsync() { using var stream = await _clientFactory.CreateClient().GetStreamAsync(new Uri(_scrapingTargetsConfig.Url)); IHtmlDocument doc = await new HtmlParser().ParseDocumentAsync(stream); return doc.GetElementById("TopicId").QuerySelectorAll("table > tbody > tr"); }
データ保存
当初はバッチ実行から1日前までの時間内のトピックのみ取得する、というロジックを組んでいたのですが、スクレイピング先のサイトのバグなのか、投稿日時が2日ほどずれており正常にトピックが取得できませんでした。 そこで、AWS S3へCSVファイルを保存し、そのCSVファイルに取得したものを保存し、そこにないもののみスクレイピングで取得していくというロジックへ変更しました。 ASP.NET CoreでS3の操作をする処理についても『AWSSDK.S3』『AWSSDK.Extensions.NETCore.Setup』パッケージをNugetから取得することで比較的楽に作成することができました。
public async ValueTask<GetObjectResponse> GetCsvFile() => await _amazonS3Client.GetObjectAsync(_awsConfig.S3.BacketName, _awsConfig.S3.Key); public async ValueTask UpdateCsvFile() { var putRequest = new PutObjectRequest { BucketName = _awsConfig.S3.BacketName, Key = _awsConfig.S3.Key, FilePath = _localStorageConfig.CsvPath }; await _amazonS3Client.PutObjectAsync(putRequest); }
LINEへの送信
LINEへの送信についてはLINE Notifyというサービスを利用することで作成しました。 以下の記事にまとめましたが、とても良いサービスなので今後も似た処理を作る際は重宝しそうです。
AWS CloudFormationでインフラをコード化
こちらは以下の記事にまとめましたが、Visual StudioでServerlessプロジェクトを起動するとserverless.templateにてインフラ構成をJson形式で作成することができます。 EventBridgeなどもコード側で調整してサクッと反映させることができるのでとても良い感じでした。
おわりに
作った当初はLINEではなくメールで送信する感じだったり、AWS上にデプロイせずに自身のローカルPCのタスクスケジューラにセットしていたりと、今とは全然違う構成でした。 「こんな感じのほうが便利かな?」という感じでどんどん途中変更していった感じですがそれを通してたくさんの技術が学べてとても楽しかったです。 また今後も色々作っていこうと思います!