# スティッキーセッションとIPローテーション：セッションID、TTL、接続再利用

> レジデンシャルプロキシゲートウェイのスティッキーセッションとIPローテーションの仕組み：セッションID、TTL、各ライブラリの接続再利用、セッションプール解説。

- URL: https://crawlrelay.com/ja/docs/sessions/
- 最終更新: 2026-10-13
- Publisher: CrawlRelay (https://crawlrelay.com)

ローテーションは接続単位、スティッキーはセッションID単位。使うライブラリが接続をどう再利用するかがわかれば、IP変更タイミングを正確に把握できます。

**クイックアンサー — レジデンシャルプロキシでスティッキーセッションとIPローテーションはどう動く？**

**CrawlRelay**では、セッションIDなしのユーザー名はTCP接続ごとにプールからIPが割り当てられ、通常は違うIPです。`-session-<id>-ttl-<minutes>`はそのIDに対して最大30分間間IPを保持しますが、早く変わることもあります。ローテーションはHTTPリクエストではなく接続に基づくため、キープアライブがIP変更タイミングを決定します。レジデンシャルトラフィックは$0.50/GBで50GBから。KYC不要で暗号通貨払い可能です。

## セッションルール概要

| 属性 | 値 |
| --- | --- |
| ローテーション単位 | 新規TCP接続ごとにプールから別IPを割当てる |
| スティッキーセッション | ユーザー名に`-session-<id>-ttl-<minutes>`を付加 |
| セッション長さ | 最大30分間 |
| セッションID | 1～32文字の英数字で、フローごとに1つのID |
| セッションを早期終了させる要因 | 背後のレジデンシャルデバイスがオフラインになること |
| 共有ID | 同じIDを送信するクライアントは同じ出口を共有します |
| コスト | なし：セッションとローテーションはGB単価に含まれています |

## セッションIDを送信したときにゲートウェイで何が起こる？

ゲートウェイは新しい接続ごとにユーザー名を読み取ります。セッションパートがなければ、その接続に対してターゲティングに合うレジデンシャルプロキシ出口を選びます。セッションパートがあれば、設定したTTLまでそのIDに対し同じ出口を保持します。

スティッキーIPは実際の家庭用接続なので、TTL終了前に消える場合があります：デバイスの電源が切れる、Wi-Fiを失う、ネットワークが変わるなどです。長時間のフローはこれに耐える必要があり、チェックポイントで出口IPを確認し、ジョブ全体を失敗させる代わりにチェックポイントから再スタートします。

## 各ライブラリはどう接続を再利用する？

ライブラリが接続を維持していれば、その接続の全リクエストは同じ出口を共有します。これがそれぞれの動作を意図的に得る方法です。

| ライブラリ | デフォルト | リクエストごとに新しいIP | フローごとに1つのIP |
| --- | --- | --- | --- |
| Python requests | `Session`は接続を生かします | ヘッダー`Connection: close`、またはリクエストごとに新しい`Session` | ユーザー名にセッションIDを入れた1つの`Session` |
| httpx | クライアントは接続をプールします | `httpx.Limits(max_keepalive_connections=0)` | セッションIDごとに1つのクライアント |
| aiohttp | `TCPConnector`は接続をプールします | `TCPConnector(force_close=True)` | プロキシURLのユーザー名にセッションID |
| Scrapy | プロキシ認証情報・ホストごとにプール | `meta={"proxy_session": "new"}`は当社の[middleware](https://crawlrelay.com/ja/docs/scrapy/)と | フローに固定の`proxy_session` |
| Playwright / Puppeteer | Chromeはコンテキスト単位でプール | ページごとに新しいコンテキスト | セッションIDごとに1コンテキスト |
| Node.js undici, axios, got | エージェントはソケットを維持 | リクエストごとに新しいエージェント、あるいはkeep-aliveオフ | セッションIDごとに1エージェント |
| curl | コマンドごとに1接続 | すでにそうなっています | 各コマンドで同じセッションID |

## どのスクレイピング案件にどのセッション戦略が適切？

| 案件 | 戦略 | 推奨TTL |
| --- | --- | --- |
| 独立した商品、記事、またはリスティングページ | 回転: セッションIDなし | — |
| 次のページがクッキーやカーソルに依存するページネーション | リスティングごとに1つの固定セッション | 10～30分 |
| 検索→結果→詳細ページ | 検索ごとに1つの固定セッション | 10～20分 |
| ヘッドレスブラウザで1つのサイトの複数ページをレンダリング | ブラウザコンテキストごとに1つの固定セッション | コンテキストの寿命、最大30分 |
| 複数の都市でページの表示内容を確認 | 都市ごとに1回の短いセッション | 5分 |
| 同じページを毎時再チェック | 回転 | — |

## Pythonで固定セッションのプールをどう管理する？

小規模なプールは安定した出口を数台で分散し、一定のリクエスト数か502や503など退出エラー検出でそれぞれを順次廃棄します。注意すべきは**IPを403や429突破用に切り替えない**ことです。これらはサイトが速度を落とすように指示しているので、プールはコード側に例外を投げます。

*Python: 固定セッションのプール*

```python
import random
import uuid

import requests

GATEWAY = "gw.crawlrelay.com:7777"
BASE_USER, PASSWORD = "USERNAME-country-us", "PASSWORD"


class SlowDown(Exception):
    """The target asked us to slow down (403 or 429): back off, do not rotate."""


class StickySession:
    def __init__(self, ttl=15, max_requests=50):
        self.id = uuid.uuid4().hex[:10]
        self.max_requests, self.used = max_requests, 0
        user = "%s-session-%s-ttl-%d" % (BASE_USER, self.id, ttl)
        proxy = "http://%s:%s@%s" % (user, PASSWORD, GATEWAY)
        self.http = requests.Session()
        self.http.proxies = {"http": proxy, "https": proxy}


class SessionPool:
    EXIT_PROBLEMS = {502, 503, 504}

    def __init__(self, size=5, **options):
        self.options = options
        self.sessions = [StickySession(**options) for _ in range(size)]

    def _replace(self, i):
        self.sessions[i].http.close()
        self.sessions[i] = StickySession(**self.options)

    def get(self, url, **kwargs):
        i = random.randrange(len(self.sessions))
        s = self.sessions[i]
        s.used += 1
        try:
            r = s.http.get(url, timeout=(10, 30), **kwargs)
        except requests.exceptions.RequestException:
            self._replace(i)  # dropped exit or timeout: start a fresh session
            raise
        if r.status_code in (403, 429):
            raise SlowDown("%s returned %d" % (url, r.status_code))
        if r.status_code in self.EXIT_PROBLEMS or s.used >= s.max_requests:
            self._replace(i)
        return r


pool = SessionPool(size=5, ttl=15, max_requests=50)
print(pool.get("https://api.ipify.org").text)
```

## 固定IPが変わったかどうかは？

問い合わせます。`https://api.ipify.org`のようなIPエコーサービスを同じセッション内でフロー開始時と各チェックポイントで呼び出し結果を比較します。変わればセッションの後ろにある出口が変わったので、前のチェックポイントからやり直すか新しいセッションを開くべきです。ログにはセッションIDを記録して、デバッグ時にIP変更とサイト挙動を区別できます。

## セッションのミスで一番コストがかかるのは？

- **マルチステップフローのすべてのリクエストで回転させること。** カートやカーソル、検索トークンが国をまたいで跳んでサイトがリセット。
- **全ワーカーで同一セッションIDを使うこと。** セッションは1フロー用なのでワーカーやフローごとにIDを分ける。
- **ジョブよりずっと長いセッション継続。** 2分タスクに30分TTLは無駄にIPを占有しログも読みにくい。
- **429をIP問題と勘違いする。** 新IPでもサイトルールは変わらず、速度を落とすことが必要。 [429 Too Many Requests](https://crawlrelay.com/ja/docs/errors/429-too-many-requests/) を参照。
- **リクエストごとの回転を当然と思う。** Keep-aliveは出口を維持。使うライブラリ別に上表を確認。

## セッションと回転に関する質問

### 固定セッションはどれくらい続く？

スティッキーセッションで設定した時間（ttl、分単位、最大30分間）同じIPを維持。例外としてレジデンシャルデバイスがオフラインになると早期変更あり。。対象フローより少し長めのTTLを選び、各チェックポイントで出口を確認。

### 固定セッションは回転より高くつく？

いいえ。CrawlRelayはGB単位のトラフィック課金で、セッションも回転もターゲティングも料金に含まれます。固定セッションは1つのキープアライブ接続で毎回TLSハンドシェイクを省略でき、トラフィック節約にも。

### すべてのリクエストで回転させるのがスクレイピングで良い？

独立ページなら回転は負荷分散になり、1IPで何時間も1サイトにアクセスするのを防げます。クッキーに紐づくページネーションなど状態を持つものはフローが壊れます。ほとんどのクロールは両方混在：アイテム間で回転・フロー内は固定。

### 正確なIPを選べる？

できません。レジデンシャルゲートウェイがリアルタイムで変わるプールから出口を割り当て、ユーザー名のターゲティングにマッチします。国、都市、米国州、ZIPコード、ASNは選べます。IPをセッションで維持はできますが特定のアドレスを予約することはできません。

**回転とセッションは全プランに含む** $1.50は1 GB、$0.50/GBは50 GBから。 [料金を見る](https://crawlrelay.com/ja/pricing/) · [同時実行性ガイド](https://crawlrelay.com/ja/docs/concurrency/)

---

CrawlRelay: CrawlRelayは開発者第一のレジデンシャルプロキシおよび4G/5Gモバイルプロキシの回転型サービスです：有効期限なしの使った分だけ支払うトラフィックを$0.50/GBから暗号通貨で購入、IDアップロード不要。KYC不要 — IDもセルフィーも書類も不要。暗号通貨で支払い可能。
