【C#】HttpClientでWebページのHTMLテキストを非同期に取得する

目次

概要

指定したURL(Webページ)にアクセスし、レスポンスボディ(HTMLやテキスト)を文字列として取得する最も基本的な実装です。 System.Net.Http.HttpClientGetStringAsync メソッドを使用することで、HTTP GETリクエストの発行から文字列への変換までを1行で完結させます。

仕様(入出力)

  • 入力: 取得対象のURL(例: ニュースサイトのトップページ)。
  • 出力: 取得したHTMLソースコードの文字数と、先頭部分の抜粋。
  • 前提: .NET標準ライブラリ(System.Net.Http)を使用。インターネット接続が必要。

基本の使い方

HttpClient インスタンス(シングルトン推奨)の GetStringAsync にURLを渡します。

// 静的フィールドでインスタンスを共有
private static readonly HttpClient sharedClient = new HttpClient();

public async Task PrintHtmlAsync()
{
    // 非同期でテキストを取得
    string html = await sharedClient.GetStringAsync("https://www.example.com");
    Console.WriteLine(html);
}

コード全文

ここでは「自社サイトの利用規約ページを取得して内容を確認する」というシナリオで実装します。 例外処理を含め、実務で使える形にしています。

using System;
using System.Net.Http;
using System.Threading.Tasks;

class Program
{
    // 【重要】HttpClientは都度newせず、アプリケーション全体で共有する
    // これによりソケット枯渇問題(Socket Exhaustion)を防ぎます
    private static readonly HttpClient _httpClient = new HttpClient();

    static async Task Main()
    {
        // 取得対象のURL(サンプルとしてexample.comを使用)
        string targetUrl = "https://www.example.com";

        Console.WriteLine($"リクエスト送信中: {targetUrl}");

        try
        {
            // タイムアウトを明示的に設定(デフォルトは100秒)
            _httpClient.Timeout = TimeSpan.FromSeconds(10);

            // WebサーバーからHTMLを文字列として取得
            string content = await _httpClient.GetStringAsync(targetUrl);

            Console.WriteLine("--- 取得成功 ---");
            Console.WriteLine($"データサイズ: {content.Length} 文字");
            Console.WriteLine("--- 先頭 500文字 ---");
            
            // 長すぎる場合は切り詰めて表示
            string preview = content.Length > 500 
                ? content.Substring(0, 500) + "..." 
                : content;
                
            Console.WriteLine(preview);
        }
        catch (HttpRequestException ex)
        {
            // 404 Not Found や DNSエラーなど
            Console.WriteLine($"[通信エラー] {ex.Message}");
            if (ex.StatusCode.HasValue)
            {
                Console.WriteLine($"HTTPステータス: {ex.StatusCode}");
            }
        }
        catch (TaskCanceledException)
        {
            // タイムアウト時
            Console.WriteLine("[タイムアウト] 応答がありませんでした。");
        }
        catch (Exception ex)
        {
            // その他の予期せぬエラー
            Console.WriteLine($"[システムエラー] {ex.Message}");
        }
    }
}

カスタムポイント

  • ヘッダーの追加: APIや特定のサイトへアクセスする場合、認証トークンやUser-Agentが必要になることがあります。C#_httpClient.DefaultRequestHeaders.Add("User-Agent", "MyApp/1.0"); _httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer my_token");
  • バイト配列での取得: 画像データのダウンロードや、エンコーディング指定が必要な場合(Shift-JISのサイトなど)は、GetStringAsync ではなく GetByteArrayAsync を使用し、Encoding クラスで手動変換します。

注意点

  1. インスタンスのライフサイクル: コード内でも触れましたが、using (var client = new HttpClient()) でリクエストごとに生成・破棄を行うのはアンチパターンです。高負荷時にポートが枯渇します。必ず static で共有するか、IHttpClientFactory を使用してください。
  2. DNSの更新: static で持ち続けるとDNSの変更が反映されない問題がありますが、.NET Core 2.1以降(.NET 5/6/8含む)では SocketsHttpHandler が内部で適切にハンドリングするため、基本的にはシングルトンで問題ありません。
  3. 非同期の徹底: GetStringAsync(...).Result のように同期的に待機すると、GUIアプリやASP.NETでデッドロックの原因になります。必ず await を使用してください。

応用

ストリームとして処理する(メモリ節約)

巨大なHTMLやテキストを取得する場合、全データを文字列としてメモリに展開する GetStringAsync は非効率です。GetStreamAsync を使い、読み込みながら処理します。

using (var stream = await _httpClient.GetStreamAsync(targetUrl))
using (var reader = new System.IO.StreamReader(stream))
{
    // 1行ずつ読み込んで処理(メモリ消費を抑える)
    while (!reader.EndOfStream)
    {
        string? line = await reader.ReadLineAsync();
        if (line != null && line.Contains("<title>"))
        {
            Console.WriteLine($"タイトルタグ発見: {line}");
        }
    }
}

まとめ

実運用では、ネットワークエラーやタイムアウトを想定した例外処理(try-catch)が必須です。

Web上のテキストデータを取得するには HttpClient.GetStringAsync が最もシンプルです。

HttpClient は「使い捨て」ではなく「使い回す」クラスです。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次