Web開発
JavaScriptなしでのボット検出:私のブログが測定したこと
Bot Detection Without JavaScript: What My Blog Measured (gkoreli.com)
要約
この記事では、JavaScriptに依存せずにブログへのトラフィックをボットと人間読者に分類する方法について説明します。著者はCloudflare Workerを使用してネットワークメタデータとリクエストヘッダーを分析し、多くのボットトラフィックを特定しましたが、人間読者の正確な数を把握することの難しさも浮き彫りにしました。比較分析を通じて、従来のUser-Agent文字列だけでは不十分であり、より詳細なネットワーク情報とヘッダー検証が必要であることが示されています。
全文翻訳
JavaScriptなしでのボット検出:私のブログが測定したこと
私のブログでは、ネットワークとリクエストヘッダーのルールにより、372件のブラウザUser-Agentリクエストのうち277件(74.5%)がブラウザカテゴリから除外されました。これにより、Cloudflare Workerに届くトラフィックの、より有用なアカウントが得られます。これは、サイトを読んだ人の数までは明らかにしてくれません。
同じ2つの完全なUTC日間で、残りの95件のブラウザHTML観測値は、依然として14件のCloudflare Web Analyticsページロードと異なっていました。有用な結果は、どのリクエストがルールによって分離されたか、なぜ分離されたか、そして証拠がどこで止まるかを知ることです。ネットワーク証拠は、ヘッダーチェックを通過したリクエストを捕捉します。そのウィンドウでは、60件のクラウド分類されたリクエストが、ブラウザルールが必要とするナビゲーションヘッダーを運んでいました。各分類の理由が、カウンターを説明可能にします。それはまた、間違いも露呈しました:HTML受け入れチェックが有効なヘッダーを誤って処理し、新しい行がネットワーク出所マーカーを欠いていました。両方ともその後修理されました。
クライアントの識別と読者数は異なる証拠を必要とします。9件の保存された署名検証は、クローラーや意図的なテストを含む署名者を識別します。それらは、アシスタントに読むように依頼する人々を数えません。残りの不一致は測定された問題です。より少ないブラウザ数も、スクリプトカウンターとの一致も、オーディエンスの精度を確立しません。
エッジページビューとスクリプトカウンターの比較
2つのカウンターを比較することで、私のファーストパーティ分析の問題点が露呈しました:私はブラウザUser-Agentを読者の証拠として扱っていました。カウンターは異なるイベントを測定するため、それらの不一致は調査の出発点となります。それ自体では、どのリクエストが自動化であったかを教えてくれません。
最初の警告は、9月3日に保存されたこの比較から来ました:
ソース イベント/ロード クライアントまたは訪問メトリック
D1 ブラウザ-UAクラス、9月2日までの7 UTC日間 1,209 578 日次クライアント識別子
Cloudflare Web Analytics、そのローリング7日間ダッシュボードウィンドウ 113 52 訪問
578対52の差は、11倍の読者数のように見えました。しかし、日次クライアント識別子は訪問ではなく、時間ウィンドウは同一ではなく、スクリプトダッシュボードには/statsが含まれていました。より比較可能な1,209対113のページ合計でさえ、これらの資格が必要でした。
元のクエリレコードは、比較が行われたまま保存されています。リクエストの中に、より強力な証拠がありました。9月2日、113の日次クライアントのうち100が1ページをロードしました。164のブラウザ-UAページ観測のうち156はリファラーがありませんでした。それらの事実だけでは、自動化を確立できませんでした。しかし、1つのクライアントはモバイルと分類され、同じタイムスタンプの秒で31の異なるページをフェッチしました。
その夜の私のメモは次のとおりでした:
今日の日次クライアントが113であるのを見ていますが、それは信じられないように思えます。どの記事を読んでいるのか、どこから来ているのか、など... 新しい記事を公開したばかりなのに、トップページビューセクションに表示されていません... 何が起こっているのでしょうか?投稿を公開すると、この特定の投稿にどれだけの読者が到着し、どのソースから来たのかを知りたいと思うことがありますが、それを理解するのは不可能です。
しかし、それでも最も奇妙なのは数字です。誰がこれらの記事を読んでいるのか、それは狂っているように見えますが、感謝していますが、自分自身をガスライティングしたくはありません。何かが合わないようです。
有用な比較には、比率を計算する前に4つの決定が必要です:
同じホストと明示的な開始包括、終了排他的UTCウィンドウを選択します。
ページイベントとページロードを比較します。
日次識別子と訪問を個別に報告します。
各システムが除外するルート、応答タイプ、ボット、所有者、テストリクエストを記録します。
サンプリング情報を結果とともに保持します。
不一致のリクエストを検査し、可能な収集の違いをテストします。
Cloudflareは、そのビーコンがページロードを見逃す理由として、スクリプトブロッカーとブラウザまたはネットワークの損失を文書化しています。ブラウザキャッシュと異なる適格性も、エッジカウンターに対してチェックする必要があります。スクリプトは自動化されたブラウザで実行される可能性があります。これらの原因を分離する普遍的な比率はありません。
Cloudflare Web Analytics FAQ、2026年9月6日チェック済み。比較は、調査できる質問を明らかにします。この記事の以前のバージョンである2未満の検証しきい値はサポートされておらず、削除しました。
Cloudflare Worker のリクエストルール
Worker は、記録されたリクエストの特性を分類します。クライアントを誰が制御したかを確立せずに、これらのルールを決定論的に適用できます。このセクションは、分類子を実装する人のためのものです。以下の測定結果は、実装の詳細なしに読むことができます。
エッジカウンターは、適格な成功したページGETの後にD1観測をスケジュールします。プリフェッチ、/stats、APIルート、非ページ応答を除外します。HTMLおよびネゴシエートされたMarkdownページ応答を含みます。直接の.mdリクエストは、このカウンターの範囲外です。その収集境界は、適格性コードに由来します。
4つの証拠源が分類にフィードします:
ネットワークメタデータ。Cloudflareはクライアントの自律システム番号(ASN)を提供します。これはエッジに到達するクライアントを説明します。クライアントはHTTPヘッダーを編集してそれを変更することはできませんが、別のネットワークまたはプロキシを介してサイトに到達できます。それはオペレーターの目的を確立しません。
フェッチメタデータ。Sec-Fetch-Mode: navigate および Sec-Fetch-Dest: document は、ページナビゲーションを説明します。Sec-Fetch-Site は none, same-origin, same-site, または cross-site のいずれかであり、分類子はそれを記録しますが、値を要求しません。
ヘッダー定義。Accept および Accept-Language。ルールは、HTMLが受け入れ可能かどうか、および言語ヘッダーが存在するかどうかをチェックします。これらはリクエストの特性であり、注意の証拠ではありません。
User-Agent。名前付きクローラーおよびアシスタントルールは、クライアントの宣言に一致します。同じ文字列が、以下で使用されるブラウザバージョン主張も提供します。クライアントはそれを模倣できます。
D1は、選択されたヘッダー、派生フラグ、名前、および分類理由を保存します。完全なUser-Agentは保持しません。既存のCloudflare運用ログには、追加のリクエスト詳細が含まれています。派生フラグを保存することは有用ですが、将来のすべてのパーサー変更を再生するのに十分な情報を提供しません。
ルール1:既知のホスティングネットワークをブラウザ形状の前に分類します。署名および名前付きクライアントルールに続いて、キュレートされたホスティングリスト上のブラウザUser-Agentリクエストは、ナビゲーションヘッダーチェックを通過した場合でも、クラウドブラウザになります。9月3日に終了した元の72時間ログサンプルでは、844件の成功したページGETのうち430件がホスティングネットワーク上のナビゲーション形状のトラフィックでした。最大のクラスターは、Chrome Mobile 114を主張する1つのGoogle Cloudクライアントに起因する374件のリクエストでした。ヘッダーの存在は、そのクラスターを分離できませんでした。
元の測定とカバレッジ
クラウドブラウザは、個人のために有用な作業を実行している可能性があります。私はそのアクセスを記録し、表示できるようにしたいです。ネットワークラベルはサイトにどのように到達したかを説明し、それをブラウザから移動しても、その観測は削除されません。キュレートされたネットワークリストは、いくつかの共有サービスおよびコンシューマーVPNネットワークを除外します。広範なホスティングリストには、正当なブラウジングを運ぶネットワークが含まれる場合があります。リストをキュレートすることは、反対のコストを受け入れます:一部の自動化は、それ以外のネットワークを介して到着します。
ルール2:主張されたブラウザバージョンに対する欠落したフェッチメタデータをチェックします。実装はChromium 76+、Firefox 90+、およびSafari/iOS 16.4+をチェックします。リクエストがそれらのエンジンのいずれかを主張しているがSec-Fetch-Modeを欠いている場合、それはno-fetch-metadataの理由でhttp-clientになります。古いまたは読み取れない主張はlegacy-browserを受け取ります。フェッチメタデータがあり、ナビゲーションの組み合わせに失敗したリクエストはnot-navigation-shapedを受け取ります。
分類子コード。
これらのバージョンしきい値は、2026年9月6日にチェックされたブラウザサポートデータに従います。それらは期待されるブラウザ機能を確立しますが、各リクエストを認証したり、すべての埋め込みクライアントに対してゼロ誤検知率を確立したりするものではありません。Sec-Fetch-Userは要求しません:Safariの互換性調査は、それなしで他のフェッチメタデータヘッダーのサポートを発見しました。フォローアップ監査は、私たち自身のAcceptチェックの欠陥も発見しました。元のex