概要
Webスクレイピングや特定のWeb APIを利用する際、クライアント(呼び出し元)の情報をサーバーに伝えるために User-Agent ヘッダーの設定が必須となる場合があります。 HttpClient では、文字列を直接指定する方法と、専用のクラスを使用して構造的に指定する方法の2通りがあり、これらを適切に実装することでアクセス拒否(403 Forbidden)などを回避できます。
仕様(入出力)
- 入力: アクセス先のURL。
- 出力: サーバーが認識したUser-Agent情報(コンソール表示)。
- 動作: カスタムUser-Agentヘッダーを付与してGETリクエストを送信する。
基本の使い方
DefaultRequestHeaders プロパティを使用して設定します。ParseAdd メソッドを使うのが最も手軽で一般的です。
// 文字列で直接指定する場合
client.DefaultRequestHeaders.UserAgent.ParseAdd("MyApp/1.0 (compatible; MyBot)");
// または Add メソッド(検証なし)
client.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "Mozilla/5.0...");
コード全文
ここでは、HTTPリクエストの内容をエコーバック(返信)してくれるテスト用サービス(httpbin.org)に対して、独自のUser-Agentを設定してアクセスするコードを提示します。
using System;
using System.Net.Http;
using System.Net.Http.Headers; // ProductHeaderValue用
using System.Threading.Tasks;
class Program
{
// HttpClientはアプリケーション全体で共有する
private static readonly HttpClient _sharedClient = new HttpClient();
static async Task Main()
{
// 1. User-Agentの設定
// 方法A: 文字列でそのまま追加(ブラウザのふりをする場合などに便利)
// _sharedClient.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (Windows NT 10.0; Win64; x64)...");
// 方法B: 型安全に指定(製品名とバージョン)
// ここでは「MyDataCollector」というボットとして振る舞う設定を行います
var productValue = new ProductHeaderValue("MyDataCollector", "1.0");
var commentValue = new ProductInfoHeaderValue("(+https://example.com/bot-info)");
// 既存の設定がある場合はクリアしてから追加
_sharedClient.DefaultRequestHeaders.UserAgent.Clear();
_sharedClient.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue(productValue));
_sharedClient.DefaultRequestHeaders.UserAgent.Add(commentValue);
// ターゲットURL(User-Agentを確認できるエンドポイント)
string url = "https://httpbin.org/user-agent";
Console.WriteLine($"リクエスト送信: {url}");
try
{
// 2. リクエスト実行
string responseJson = await _sharedClient.GetStringAsync(url);
Console.WriteLine("--- サーバーからの応答 ---");
Console.WriteLine(responseJson);
}
catch (HttpRequestException ex)
{
Console.WriteLine($"通信エラー: {ex.Message}");
}
}
}
実行結果例
--- サーバーからの応答 ---
{
"user-agent": "MyDataCollector/1.0 (+https://example.com/bot-info)"
}
カスタムポイント
- Add vs TryAddWithoutValidation:
AddやParseAddはヘッダー値の形式が規格(RFC)に準拠しているか厳密にチェックします。一部の特殊な(行儀の悪い)User-Agent文字列を設定したい場合は、検証をスキップするTryAddWithoutValidationを使用してください。 - リクエストごとの変更:
HttpClientを共有しつつ、リクエストごとに異なるUser-Agentを使いたい場合は、DefaultRequestHeadersではなくHttpRequestMessageを作成して個別に設定します。C#var request = new HttpRequestMessage(HttpMethod.Get, url); request.Headers.UserAgent.ParseAdd("OneTimeBot/1.0"); await client.SendAsync(request);
注意点
- 行儀の良いボット: スクレイピング等を行う際は、User-Agentに自身の連絡先(URLやメールアドレス)を含めるのがマナーです。これにより、サーバー管理者がアクセス元を特定しやすくなります。
- 偽装のリスク: 一般的なブラウザ(ChromeやEdge)のUser-Agentを偽装してアクセスする場合、サイトの利用規約に違反する可能性があるため、対象サイトのルールを必ず確認してください。
- 共有インスタンスへの影響:
DefaultRequestHeadersはそのHttpClientインスタンスを使用する全てのリクエストに適用されます。途中で書き換えると、並行して走っている他のスレッドのリクエストにも影響が出るため、初期化時以外は変更しないのが原則です。
応用
User-Agentローテーション
大量のアクセスを行う際に、検知回避のためにリストからランダムにUser-Agentを選択して送信する実装例です(HttpRequestMessage を使用)。
var agents = new[]
{
"Mozilla/5.0 (Windows NT 10.0; Win64; x64)...",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)..."
};
var randomAgent = agents[new Random().Next(agents.Length)];
var request = new HttpRequestMessage(HttpMethod.Get, url);
request.Headers.TryAddWithoutValidation("User-Agent", randomAgent);
var response = await _sharedClient.SendAsync(request);
まとめ
HttpClientでUser-Agentを設定するには、初期化時に DefaultRequestHeaders.UserAgent プロパティへ値を追加するのが基本であり、これによりサーバー側へ適切なクライアント情報を通知することができます。ただし、HttpClientはシングルトン運用が推奨されるため、ヘッダー情報はアプリケーション起動時に一度だけ設定するか、動的に変更が必要な場合はリクエストメッセージ単位で個別に設定する設計が求められます。
