コンテナを使用してクリスマス プレゼントの価格を追跡しますか?
クリスマスが近づいてきました。愛する人への完璧な贈り物を見つけるという楽しい仕事がやって来ます。あなたも私と同じなら、お得に買い物をするのが大好きかもしれませんが、ホリデー シーズン中に人気商品の価格が高騰する中を歩き回るのは、本物のそりに乗っているような気分になるかもしれません。エキサイティングではありますが、少し大変です。今年は、毎日の価格チェックに夢中になるのではなく、自分の技術スキルを有効に活用してプロセスを自動化することにしました。

ソフトウェア開発者として、またテクノロジーを活用して日常の問題を解決することに情熱を注いでいた私は、価格チェックのプロセスを自動化する方法を見つけました。価格を比較するために毎日複数のオンライン ストアを手動で訪問するのではなく、それを実行できるシステムを作成することにしました。これにより、時間を節約できるだけでなく、毎日のチェックのストレスを感じることなく、最良の取引を確実に入手できるようになります。
価格監視を自動化する理由
価格監視の自動化は、サンタの妖精のチームを24時間体制で働かせて、何もせずに最高の取引を確実に入手できるようにするようなものです。気に入っていただける理由は次のとおりです:
- 高価なアイテム: クリスマス プレゼントは、特にガジェットやおもちゃがリストにある場合、かなり高価になる可能性があることは誰もが知っています。これらでお金を節約することは、在庫にある最後のツリートップを見つけるのと同じくらい満足できることです。
- 毎日のチェック: 毎日価格をチェックする時間 (または忍耐力) がある人はいるでしょうか?私じゃないよ!
- 自動化: ホリデー シーズンの寄付の精神を受け入れ、効率性という贈り物を自分自身に与えましょう。
- 精度: 自動化により、価格チェックがルドルフの鼻のように正確であることが保証されます。
コアテクノロジー
独自のサンタの小さなヘルパーを構築するために、いくつかの主要なテクノロジーを使用することにしました。
コンテナ
コンテナはソフトウェアのクリスマスラッピングのようなものです。アプリケーションをすべての機能 (依存関係) とバンドルして、すべてが新雪のそりのようにスムーズに動作するようにします。これらのコンテナを作成するには Docker が頼りになります。
ブレザー
Blazor は、.NET を使用してインタラクティブな Web アプリケーションを構築するための優れたフレームワークです。それは、一般的なクリスマスキャロルを、カスタマイズされ、効率的で、とても楽しい、独自のホリデー プレイリストに置き換えるようなものです。
Docker-Compose
Docker-Compose は、北極の運営のマネージャーです。これは、API や Blazor フロントエンドなどのすべてのサービスを完全に調和して実行するのに役立ちます。それを私たちのホリデー交響楽団の指揮者だと考えてください。
ステップバイステップガイド
さあ、サンタさんのワークショップに飛び込んで、このプロジェクトを実現させましょう!
ステップ 1: API の作成
1.1 プロジェクトのセットアップ
コーディング用のサンタ帽をかぶって、新しい ASP.NET Core Web API プロジェクトをセットアップします。ターミナルを開いて (アドベントカレンダーを開くのと似ています)、次のコマンドを実行します。
dotnet new webapi -o PriceMonitorApi
cd PriceMonitorApi
このコマンドは、PriceMonitorApi という名前の新しいディレクトリを作成し、基本的な Web API プロジェクトをセットアップします。ジンジャーブレッドハウスの頑丈な土台を作るようなものだと想像してください。
1.2 HttpClient の追加とライブラリのスクレイピング次に、HttpClient と HTML を解析するライブラリを追加します。これは、価格データを取得して読み取るための信頼できるそりになります。
dotnet add package HtmlAgilityPack
HtmlAgilityPack は、HTML ドキュメントの解析を支援するエルフです。
1.3 モデルの作成
模型はおもちゃの設計図のようなものです。製品情報を表すモデルを作成しましょう。
namespace PriceMonitorApi.Models
{
public class ProductInfo
{
public string Title { get; set; }
public decimal Price { get; set; }
public DateTime Date { get; set; }
}
}
データに最適なテンプレートを作成しました。
1.4 スクレーパー サービスの実装
私たちのスクレイパー サービスはサンタさんの小さなヘルパーのようなもので、私たちのために情報を取得して処理します。
using HtmlAgilityPack;
using PriceMonitorApi.Models;
using System.Globalization;
namespace PriceMonitorApi.Services
{
public class ScraperService
{
private readonly HttpClient _httpClient;
public ScraperService(HttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task<ProductInfo> ScrapeProductInfoAsync(string url)
{
var response = await _httpClient.GetStringAsync(url);
var htmlDoc = new HtmlDocument();
htmlDoc.LoadHtml(response);
var title = htmlDoc.DocumentNode.SelectSingleNode("//h1[@class='product-title']").InnerText.Trim();
var priceString = htmlDoc.DocumentNode.SelectSingleNode("//span[@class='product-price']").InnerText.Trim();
if (decimal.TryParse(priceString, NumberStyles.Currency, CultureInfo.InvariantCulture, out var price))
{
return new ProductInfo
{
Title = title,
Price = price,
Date = DateTime.UtcNow
};
}
throw new Exception("Unable to parse price");
}
}
}
このスニペットは、HtmlAgilityPack をホリデーの魔法の杖に変えます。
1.5 API コントローラーの作成
データのゲートキーパーのように機能するコントローラーを作成しましょう。
using Microsoft.AspNetCore.Mvc;
using PriceMonitorApi.Models;
using PriceMonitorApi.Services;
namespace PriceMonitorApi.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class ScraperController : ControllerBase
{
private readonly ScraperService _scraperService;
public ScraperController(ScraperService scraperService)
{
_scraperService = scraperService;
}
[HttpGet("productinfo")]
public async Task<ActionResult<ProductInfo>> GetProductInfo(string url)
{
try
{
var productInfo = await _scraperService.ScrapeProductInfoAsync(url);
return Ok(productInfo);
}
catch (Exception ex)
{
return BadRequest(new { Message = ex.Message });
}
}
}
}
私たちのコントローラーは、サンタさんが煙突から下りてくるよりも早くデータが配信されることを保証します。
1.6 DIコンテナへのサービスの登録
最後に、ScraperService を登録して、必要なときに利用できるようにします。
services.AddHttpClient<ScraperService>();
これで、クリスマスイブのサンタのそりのように、API の準備が整いました。
ステップ 2: Blazor アプリケーションの作成
Blazor を使用すると、プロジェクトをクリスマス ツリーのように飾り、視覚的に魅力的でインタラクティブにすることができます。
2.1 Blazor プロジェクトのセットアップ
次に、価格監視そりのインターフェイスとして機能する Blazor プロジェクトを作成します。
dotnet new blazor -o PriceMonitorBlazor
cd PriceMonitorBlazor
このコマンドは、基本的な Blazor WebAssembly プロジェクトをセットアップするための休日の魔法をいくつか散りばめています。
2.2 モデルの追加
オーナメントを設定するのと同じように、Blazor プロジェクトに ProductInfo モデルを追加します。
namespace PriceMonitorBlazor.Models
{
public class ProductInfo
{
public string Title { get; set; }
public decimal Price { get; set; }
public DateTime Date { get; set; }
}
}
2.3 API 呼び出し用のサービスの作成
API からデータを取得するサービスを作成します。これをオンライン ショッピングの友達と考えてください。
using PriceMonitorBlazor.Models;
using System.Net.Http;
using System.Net.Http.Json;
using System.Threading.Tasks;
namespace PriceMonitorBlazor.Services
{
public class ScraperService
{
private readonly HttpClient _httpClient;
public ScraperService(HttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task<ProductInfo> GetProductInfoAsync(string url)
{
var response = await _httpClient.GetFromJsonAsync<ProductInfo>($"https://localhost:5001/api/scraper/productinfo?url={url}");
return response;
}
}
}
2.4 DIコンテナへのサービスの登録
ScraperService がコンポーネントに挿入できるように、ScraperService が登録されていることを確認してください。
builder.Services.AddScoped<ScraperService>();
2.5 Blazor コンポーネントの作成
Pages/Index.razor を更新して、楽しくインタラクティブなインターフェイスを追加します。
@page "/"
@using PriceMonitorBlazor.Models
@using PriceMonitorBlazor.Services
@inject ScraperService ScraperService
<h3>Price Monitor</h3>
<p>
<label for="urlInput">Product URL:</label>
<input id="urlInput" @bind="productUrl" />
<button @onclick="FetchProductInfo">Fetch Price</button>
</p>
@if (productInfos.Any())
{
<table class="table">
<thead>
<tr>
<th>Title</th>
<th>Price</th>
<th>Date</th>
</tr>
</thead>
<tbody>
@foreach (var product in productInfos)
{
<tr>
<td>@product.Title</td>
<td>@product.Price</td>
<td>@product.Date</td>
</tr>
}
</tbody>
</table>
}
@code {
private string productUrl;
private List<ProductInfo> productInfos = new List<ProductInfo>();
private async Task FetchProductInfo()
{
if (!string.IsNullOrEmpty(productUrl))
{
var productInfo = await ScraperService.GetProductInfoAsync(productUrl);
productInfos.Add(productInfo);
}
}
}
これは、お祭りのディスプレイをセットアップするようなもので、アプリをインタラクティブで楽しいものにします。
ステップ 3: Docker-Compose を使用してすべてを接続する
それでは、Docker-Compose を使用してすべてを接続し、プロジェクトを十分に油を注いだそりに変えてみましょう。
3.1 Dockerfile の作成
API プロジェクトと Blazor プロジェクトの両方の Dockerfile を作成します。
PriceMonitorApi/Dockerfile:
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["PriceMonitorApi/PriceMonitorApi.csproj", "PriceMonitorApi/"]
RUN dotnet restore "PriceMonitorApi/PriceMonitorApi.csproj"
COPY . .
WORKDIR "/src/PriceMonitorApi"
RUN dotnet build "PriceMonitorApi.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "PriceMonitorApi.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "PriceMonitorApi.dll"]
PriceMonitorBlazor/Dockerfile:
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["PriceMonitorBlazor/PriceMonitorBlazor.csproj", "PriceMonitorBlazor/"]
RUN dotnet restore "PriceMonitorBlazor/PriceMonitorBlazor.csproj"
COPY . .
WORKDIR "/src/PriceMonitorBlazor"
RUN dotnet build "PriceMonitorBlazor.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "PriceMonitorBlazor.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "PriceMonitorBlazor.dll"]
3.2 docker-compose.yml の作成
すべてのドット (クリスマス ライト) を 1 つの docker-compose.yml ファイルで接続します。
version: '3.4'
services:
api:
image: pricemonitorapi
build:
context: ./PriceMonitorApi
dockerfile: Dockerfile
ports:
- "5000:80"
networks:
- price-monitor-network
blazor:
image: pricemonitorblazor
build:
context: ./PriceMonitorBlazor
dockerfile: Dockerfile
ports:
- "5001:80"
depends_on:
- api
networks:
- price-monitor-network
networks:
price-monitor-network:
driver: bridge
図表
以下は、さまざまなコンポーネントとデータ フローを視覚化するのに役立つ図です。これは、サンタの世界で実際に何が起こっているのかを理解するのに役立ちます。
システムアーキテクチャ図

データ フロー図

シーケンス図

Docker セットアップのコンポーネント図

ステップ 4: URL 管理、更新、自動定期更新このデモではメモリに保存するだけですが、実際のアプリケーションではデータベースを使用します。この楽しいプロジェクトでは、メモリ内ストレージにこだわりましょう。
4.1 URL を管理するためのサービスの変更
まず、サービスが URL の追加と取得、および製品情報の取得を処理できることを確認します。
Services/ScraperService.cs を更新します:
using PriceMonitorBlazor.Models;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Json;
using System.Threading.Tasks;
namespace PriceMonitorBlazor.Services
{
public class ScraperService
{
private readonly HttpClient _httpClient;
private List<string> urls = new List<string>();
public ScraperService(HttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task<ProductInfo> GetProductInfoAsync(string url)
{
var response = await _httpClient.GetFromJsonAsync<ProductInfo>($"http://localhost:5000/api/scraper/productinfo?url={url}");
return response;
}
public void AddUrl(string url)
{
if (!urls.Contains(url))
{
urls.Add(url);
}
}
public List<string> GetUrls()
{
return urls;
}
public void ClearUrls()
{
urls.Clear();
}
}
}
4.2 URL 管理と更新のための Blazor コンポーネントの更新
次に、Pages/Index.razor を更新して、URL 管理、更新、自動定期更新を追加します。
@page "/"
@using PriceMonitorBlazor.Models
@using PriceMonitorBlazor.Services
@inject ScraperService ScraperService
<h3>Price Monitor</h3>
<p>
<label for="urlInput">Product URL:</label>
<input id="urlInput" @bind="productUrl" />
<button @onclick="AddUrl">Add URL</button>
</p>
<p>
<button @onclick="RefreshPrices">Refresh All Prices</button>
</p>
@if (productInfos.Any())
{
<table class="table">
<thead>
<tr>
<th>Title</th>
<th>Price</th>
<th>Date</th>
</tr>
</thead>
<tbody>
@foreach (var product in productInfos)
{
<tr>
<td>@product.Title</td>
<td>@product.Price</td>
<td>@product.Date</td>
</tr>
}
</tbody>
</table>
}
@code {
private string productUrl;
private List<ProductInfo> productInfos = new List<ProductInfo>();
private Timer _timer;
protected override void OnInitialized()
{
StartTimer();
}
private void StartTimer()
{
// Set up the timer to call RefreshPrices every minute (60000 ms)
_timer = new Timer(async _ => await InvokeAsync(RefreshPrices), null, TimeSpan.Zero, TimeSpan.FromMinutes(1));
}
private void AddUrl()
{
if (!string.IsNullOrEmpty(productUrl))
{
ScraperService.AddUrl(productUrl);
productUrl = string.Empty;
}
}
private async Task RefreshPrices()
{
productInfos.Clear();
var urls = ScraperService.GetUrls();
foreach (var url in urls)
{
var productInfo = await ScraperService.GetProductInfoAsync(url);
productInfos.Add(productInfo);
}
StateHasChanged();
}
}
この更新されたコンポーネントでは次のようになります。
Timerを使用して、RefreshPricesメソッドを毎分定期的に呼び出します。StartTimerメソッドは、タイマーを初期化してすぐに開始し、その後 60 秒ごとにトリガーします。OnInitializedライフサイクル メソッドは、コンポーネントが初期化されて定期更新を開始するときにStartTimerを呼び出します。
4.3 ソリューションの実行
新しい機能を備えた更新された Blazor アプリケーションを実行するには、Docker コンテナーを再構築して再起動します。
docker-compose build
docker-compose up
ブラウザーに http://localhost:5001 を読み込んだ後、Blazor アプリは手動更新と URL 管理に加えて、商品価格を 1 分ごとに自動的に更新するようになります。
結論
この価格監視システムの構築は非常に楽しいものでした。毎日の価格チェックのストレスから解放されただけでなく、最新の Web テクノロジーの魔法を見せてくれました。
フェスティブテックカレンダー2024

私はこの投稿を Festive Tech Calendar 2024 イベントの一環として作成しました。このイベントでは、テクノロジー愛好家、イノベーター、デジタル夢想家が集まり、知識を共有し、お祭り気分とテクノロジーの驚異の融合を祝います。この取り組みは、学び、つながるだけでなく、恩返しすることも目的としています。
Festive Tech Calendar 2024 は今年、Beatson Cancer Charity をサポートしています。 Beatson Cancer Charity は、がんに苦しむ人々、その家族、そして彼らの世話をする医療従事者を支援することに専念しています。彼らの素晴らしい仕事についての詳細は、https://www.beatsoncancercharity.org/ でご覧いただけます。
よくある質問とイベントの詳細については、Festive Tech Calendar Web サイト (https://festivetechcalendar.com) をご覧ください。
ホーホーホー!
このプロジェクトの作成は、お祭り騒ぎのテクノロジー コミュニティに貢献し、同時に大きな目的をサポートする素晴らしい方法でした。
このガイドがお役に立ち、テクノロジーを使用して日常業務を簡素化するさらなる方法を探求するきっかけになれば幸いです。
ご質問がある場合、またはさらにサポートが必要な場合は、お気軽にお問い合わせください。
コーディングを楽しんでください!