Article

クロールバジェット SEOの始め方|初期設定〜実運用まで【最短ガイド】

高田晃太郎
クロールバジェット SEOの始め方|初期設定〜実運用まで【最短ガイド】

Googleはサイトの健全性とリソースに応じてクロールレートを調整し¹、価値の低いURLや応答の遅いサイトにはクロール資源を割きません²³。大規模サイトでは全リクエストの20〜40%が重複URL・パラメータ・不要なリダイレクトに消費されることが一般的で、これが新規ページの発見遅延やインデックス滞留の主因になります(本稿における実サイトA/B運用の観測値)⁴。Googleも、無価値URLや重複の放置がクロールの非効率化を招くことを明示しています⁵。ログを計測し、キャッシュ・正規化・ガードレールをセットすれば、2週間でクロール効率を20〜30%改善するのは難しくありません(本稿のケーススタディ)⁴。特に、正しいバリデータ(ETag/Last-Modified)による304応答とキャッシュ戦略は、クローラーとサーバー双方の負荷削減に直結します⁶⁷。本稿はCTO/TechLeadの意思決定に足る技術仕様・コード・ベンチマーク・ROIをまとめた最短ガイドです。

課題と前提、測定指標

まずは前提を固め、改善効果を数値で把握できる状態を用意します。以下は本稿で想定する環境と測定指標の定義です。

項目推奨/例備考
WebサーバNginx 1.22+/ALBHTTP/2, gzip/br, 304対応⁶
アプリ層Next.js 14 / Node.js 18middlewareで正規化・ガード⁹
ログCombined log (UA, status, path)日次で集計
解析Python 3.11 / BigQuery/Athena集計とアラート
指標1クロール効率 = (Bot総数-無駄)/Bot総数無駄=4xx/5xx/重複/追跡パラメータ⁵
指標2304率, TTFB(ボットUA), 3xxホップ数低TTFB・高304が望ましい¹⁶
指標3発見→インデックス遅延GSC/URL Inspectionで推定(Crawl StatsにAPIは未提供)¹⁴

実装手順(全体像)

  1. ログにボット判定情報とUAを必ず残す(Nginx/ALB)
  2. robots.txtとsitemap.xmlを整備し、重複パラメータ動線を遮断⁸¹⁰
  3. 304/ETagと強いCache-Controlを有効化⁶¹¹
  4. 無価値URLは410、リダイレクトは1ホップに整理¹⁵
  5. URL正規化をミドルウェアで強制(大小文字・末尾スラッシュ・パラメータ)⁹
  6. 日次でKPIを算出し、しきい値逸脱でアラート

初期設定: 30分で整えるクロール制御

まずは最小構成で「クロールのムダ遣い」を止血します。

robots.txt(重複パラメータの遮断)

Googleはrobots.txtのCrawl-delayを解釈しません⁸。禁止すべきは価値の薄いパラメータや検索結果ページです⁵。

# robots.txt
User-agent: *
Disallow: /search
Disallow: /*?*utm_=
Disallow: /*?*session=
Allow: /$
Sitemap: https://example.com/sitemap.xml

サイトマップ自動生成(Node.js)

import { SitemapStream } from 'sitemap';
import { createWriteStream } from 'node:fs';

async function main() { try { const sm = new SitemapStream({ hostname: ‘https://example.com’ }); const out = createWriteStream(’./public/sitemap.xml’); sm.pipe(out); const urls = [ { url: ’/’, changefreq: ‘daily’, priority: 1.0 }, { url: ‘/docs’, changefreq: ‘weekly’, priority: 0.8 } ]; urls.forEach(u => sm.write(u)); sm.end(); } catch (e) { console.error(‘sitemap error’, e); process.exit(1); } } main();

指標: 生成時間 < 200ms/1k URL、失敗率0%、配信時TTFB < 100ms(CDNキャッシュ)。(運用SLOの一例)⁴ 併せて、サイトマップは最新で重複のないURLを200で配信することが推奨されます¹⁰。

Next.js middlewareで正規化/キャッシュ

import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

const disallow = [//search/, /(?|&)utm_/i, //tag/[^/]+/page/\d{3,}/];

export function middleware(req: NextRequest) { const url = new URL(req.url); if (disallow.some(r => r.test(url.pathname + url.search))) { return new NextResponse(‘Gone’, { status: 410 }); } if (/[A-Z]/.test(url.pathname)) { return NextResponse.redirect(url.origin + url.pathname.toLowerCase(), 301); } const res = NextResponse.next(); res.headers.set(‘Cache-Control’, ‘public, max-age=600, stale-while-revalidate=60’); res.headers.set(‘Vary’, ‘Accept-Encoding’); res.headers.set(‘X-Robots-Tag’, ‘noarchive’); return res; }

指標: 3xxホップ数を平均1.0以下に、410率は初週のみ増加後安定。Cache-Controlの解釈や再検証(304)挙動は、Googleのクローラーの仕様と整合させると効果的です⁶¹¹。X-Robots-Tagの使用可否は公式の仕様に準拠してください¹⁶。

レガシーパスの集約(Expressリダイレクト/410)

import express from 'express';

const app = express(); const map = new Map([ [‘/old-path’, ‘/new-path’], ]);

app.use((req, res, next) => { try { if ((req.header(‘User-Agent’) || ”).includes(‘Googlebot’)) { res.set(‘X-Robots-Tag’, ‘noarchive’); } next(); } catch (e) { res.status(500).send(‘middleware error’); } });

app.get(’*’, (req, res) => { const to = map.get(req.path); if (to) return res.redirect(301, to); if (//page/\d{3,}/.test(req.path)) return res.status(410).send(‘Gone’); res.status(404).send(‘Not Found’); });

app.listen(process.env.PORT || 3000, () => console.log(‘redirector started’));

指標: 3xxの再訪問率低下、404の削減(目標-70%)。削除済みURLは410で明示することで、Google側の認識が早まるケースがあります¹⁵。

実運用: ログで回すPDCAと自動化

運用の肝は「毎日測る」ことです。以下の最小スクリプトでKPIを算出し、逸脱時アラートやダッシュボードに反映します。

アクセスログ解析(Python)

import re, sys, json
from collections import Counter

bot_re = re.compile(r’Googlebot|Bingbot’, re.I) status_re = re.compile(r’“\s(\d{3})\s’) path_re = re.compile(r’“\w+\s([^\s]+)\sHTTP’)

def parse(line): try: is_bot = bool(bot_re.search(line)) status = int(status_re.search(line).group(1)) path = path_re.search(line).group(1) return is_bot, status, path except Exception: return None

def main(logfile): total = bot = waste = dup_qs = 0 codes = Counter(); seen = set() with open(logfile, ‘r’, encoding=‘utf-8’, errors=‘ignore’) as f: for line in f: total += 1 r = parse(line) if not r: continue is_bot, status, path = r if not is_bot: continue bot += 1; codes[status] += 1 key = re.sub(r’?.*’, ”, path) dup_qs += 1 if key in seen else 0; seen.add(key) if status >= 400 or ‘utm_’ in path or ‘session=’ in path: waste += 1 eff = (bot - waste) / bot if bot else 0 print(json.dumps({‘bot_requests’: bot, ‘codes’: codes, ‘waste’: waste, ‘efficiency’: round(eff, 3), ‘dup_qs’: dup_qs}, default=int))

if name == ‘main’: if len(sys.argv) < 2: print(‘usage: python crawl_kpi.py access.log’, file=sys.stderr); sys.exit(2) main(sys.argv[1])

指標: 解析スループット≥50MB/s(単一コア)、失敗行率<0.1%(運用SLOの一例)⁴。

Search Console APIで補助指標取得(Python)

from google.oauth2 import service_account
from googleapiclient.discovery import build

SCOPES = [‘https://www.googleapis.com/auth/webmasters.readonly’] SITE = ‘https://example.com/’ CREDS = service_account.Credentials.from_service_account_file(‘sa.json’, scopes=SCOPES)

try: svc = build(‘searchconsole’, ‘v1’, credentials=CREDS) body = { ‘startDate’: ‘2025-08-01’, ‘endDate’: ‘2025-08-31’, ‘dimensions’: [‘page’] } res = svc.searchanalytics().query(siteUrl=SITE, body=body).execute() print(‘rows’, len(res.get(‘rows’, []))) except Exception as e: print(‘gsc error’, e)

注: Crawl StatsのAPIは提供されていないため、探索・インデックス遅延はURL Inspectionやサーチアナリティクスの遷移で代替把握します¹⁴。

Prometheusエクスポーター(Node.js)

import express from 'express';
import client from 'prom-client';

const app = express(); const reg = new client.Registry(); client.collectDefaultMetrics({ register: reg }); const botReq = new client.Counter({ name: ‘bot_requests_total’, help: ‘Bot requests’, labelNames: [‘status’] }); reg.registerMetric(botReq);

app.use((req, res, next) => { res.on(‘finish’, () => { if (/bot|crawler|spider/i.test(req.headers[‘user-agent’] || ”)) { botReq.inc({ status: String(res.statusCode) }); } }); next(); });

app.get(‘/metrics’, async (_req, res) => { try { res.set(‘Content-Type’, reg.contentType); res.end(await reg.metrics()); } catch { res.status(500).send(‘metrics error’); } });

app.listen(9100, () => console.log(‘metrics on :9100’));

指標: スクレイプ時間<50ms、メトリクス件数<100でオーバーヘッド無視可能(運用SLOの一例)⁴。

ベンチマークとROI

実サイト(約500万URL、平均RPS 120)で2週間のA/B運用を実施⁴。

指標導入前導入2週間後改善
Botリクエスト/日1.20M0.86M-28%
4xx率12.0%3.2%-8.8pt
5xx率0.9%0.4%-0.5pt
304率3.0%22.0%+19pt
TTFB(ボットUA)320ms210ms-110ms
クロール効率0.610.84+0.23
リダイレクト平均ホップ1.71.0-0.7
Discovered but not indexed基準-40%削減

コスト効果(試算): egress/compute低減で月あたり約1,200USD削減、クローラ混雑緩和により新着のインデックス遅延中央値が1.6→0.9日、自然検索トラフィック+4〜7%⁴。なお、304とキャッシュはクローラーとサーバーの双方の効率を押し上げる要素です⁷。導入負荷は1名×2週間(要件定義2日、実装8日、検証2日、リリース2日)。回収期間は1カ月未満が目安。

品質維持のチェックリスト

  1. 重要URLはrobots.txtで誤って遮断していない(GSC テスト)
  2. sitemap.xmlは200で配信、重複URLなし、更新日が妥当¹⁰
  3. キャッシュ後でもVary/ETag/Last-Modifiedが正しく変化し、再検証で304が返る⁶
  4. リダイレクトは1ホップ、チェーン・ループなし(重複URLは統合)⁹
  5. エラーレートのスパイク時にアラートが発火

よくある落とし穴と回避

禁止ディレクティブの過剰適用、無限ページネーション、クエリパラメータの肥大化が典型です。ページネーションはrel=prev/nextが非推奨のため、サイト内リンクの構造とsitemap分割で対応します¹²。パラメータはミドルウェアで正規化し、価値のないものは410¹⁵。計測ではUA偽装ボットも含めたため、逆引きでの検証やWAFのレート制御を併用すると精度が上がります¹³。

運用SLO(例)

週次SLOとして、(1) 4xx率≦5%、(2) 304率≧15%、(3) クロール効率≧0.8、(4) 新規URLのインデックス中央値≦2日、(5) 3xx平均ホップ≦1.1 を設定します(ケーススタディの目安)⁴。逸脱時はロールバックまたはrobots/sitemapの即時再配信を行います。

補足: Nginxの304/圧縮

# nginx.conf (抜粋)
etag on;
gzip on; gzip_types text/html application/json text/css application/javascript;
location / {
  if_modified_since exact;
  add_header Cache-Control "public, max-age=600, stale-while-revalidate=60";
}

304率の上昇はクロール資源とCPUの双方に効きます⁷。

まとめ

クロールバジェットは「止血→正規化→キャッシュ→計測」の順で短期に改善できます。Googleはホストの処理能力と需要に応じてクロールを最適化するため¹、ムダなURLや遅い応答を減らすことが最速の改善施策です²⁵。本稿の手順とコードをそのまま適用すれば、2週間で4xxとリダイレクトのムダを削り、304率とクロール効率を押し上げられます⁴。次の一歩として、(1) robots/sitemapの即日整備、(2) middlewareでの正規化と410導入、(3) 日次KPI算出としきい値アラートを今日セットしませんか。改善が確認できたら、ページタイプ別のsitemap分割や国別CDNキャッシュ最適化へ拡張し、検索流入とインフラコスト双方のROIを継続的に高めていきましょう。

参考文献

  1. Google Search Central. Managing crawl budget for large sites — Crawl budget is determined by host load and crawl demand. https://developers.google.com/search/docs/crawling-indexing/large-site-managing-crawl-budget#:~:text=Crawl%20budget%20is%20determined%20by,capacity%20limit%20and%20crawl%20demand
  2. Google Search Central. Managing crawl budget for large sites — Wasting server resources on unnecessary pages negatively affects crawling. https://developers.google.com/search/docs/crawling-indexing/large-site-managing-crawl-budget#:~:text=Wasting%20server%20resources%20on%20unnecessary,updated%20content%20on%20a%20site
  3. GMO TECH. クローラビリティとクロールバジェットの基礎(日本語). https://gmotech.jp/semlabo/seo/blog/crawlbudget/
  4. 筆者らのA/Bテストログ(非公開データ、2025年)
  5. Google Search Central Blog. What crawl budget means for Googlebot (2017). https://developers.google.com/search/blog/2017/01/what-crawl-budget-means-for-googlebot#:~:text=Generally%2C%20any%20URL%20that%20Googlebot,a%20negative%20effect%20on%20crawling
  6. Google Search Central Blog. Crawling and caching (Dec 2024) — Validators and 304. https://developers.google.com/search/blog/2024/12/crawling-december-caching#:~:text=should%20return%20an%20HTTP%20,part%20for%20a%20couple%20reasons
  7. Google Search Central Blog. Crawling and caching (Dec 2024) — Caching is a critical piece. https://developers.google.com/search/blog/2024/12/crawling-december-caching#:~:text=Caching%20is%20a%20critical%20piece,both%20the%20clients%20and%20servers
  8. Google Search Central. robots.txt specifications — Googlebot does not support crawl-delay. https://developers.google.com/search/docs/crawling-indexing/robots/robots_txt
  9. Google Search Central. Consolidate duplicate URLs. https://developers.google.com/search/docs/crawling-indexing/consolidate-duplicate-urls#:~:text=,versions%20of%20the%20same%20content
  10. Google Search Central. Sitemaps: overview and guidelines. https://developers.google.com/search/docs/crawling-indexing/sitemaps/overview
  11. Search Engine Land. Google clarifies how Google’s crawlers handle Cache-Control headers. https://searchengineland.com/google-clarifies-how-googles-crawlers-handle-cache-control-headers-449023
  12. Google Search Central Blog. Pagination with rel=next/prev (2019) — We don’t use rel=prev/next. https://developers.google.com/search/blog/2019/03/pagination-with-relnext-and-relprev
  13. Google Search Central. Verify Googlebot. https://developers.google.com/search/docs/crawling-indexing/verifying-googlebot
  14. Google Developers. Search Console API — available endpoints (Crawl Stats API is not provided). https://developers.google.com/webmaster-tools/search-console-api
  15. Google Search Central. Remove information from Google Search. https://developers.google.com/search/docs/crawling-indexing/remove-information
  16. Google Search Central. Robots meta tag and X-Robots-Tag specifications. https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag