---
title: "Scrapyの使い方とScrapy Cloudへのデプロイ手順【2.19対応】"
url: "https://www.issoh.co.jp/column/details/2611/"
published: 2024-06-18
updated: 2026-10-31
categories: ["自動化"]
publisher: "株式会社一創"
---

# Scrapyの使い方とScrapy Cloudへのデプロイ手順【2.19対応】

Scrapyの入門記事の多くは、スパイダーの起点を `start_requests()` で書いています。このメソッドは2026年5月の2.16.0で削除され、呼ばれなくなりました。例外も警告も出ないため、`start_requests()` だけを定義したスパイダーは0リクエストで「正常終了」します。本記事は2026年9月10日公開の2.19.0を基準に、インストールからパイプライン、Scrapy Cloudへのデプロイまでを、Docker上のScrapy 2.19.0で動かしたコードで説明します。

## まとめ

- 現行版は2.19.0（2026年9月10日）。対応PythonはPython 3.10〜3.15です。
- スパイダーの起点は `async def start()`。旧 `start_requests()` は2.16.0で削除され、定義しても無視されます。
- パイプラインは `process_item(self, item)` と書きます。`spider` 引数付きの書き方は2.14.0から非推奨の警告が出ます。
- 2.19.0では、実行中のクロールにHTTPでコードを送れる `RemoteControl` 拡張が既定で有効です。待ち受けは127.0.0.1だけですが、不要なら `REMOTE_CONTROL_ENABLED=False` で止めます。
- Scrapy Cloudの最新スタックは `scrapy:2.18-20260824`（Scrapy 2.18.0・Python 3.14.5）で、2.19の機能はまだ使えません。デプロイする場合は、ローカルの版もスタックに合わせます。
- Scrapy Cloudの無料枠は同時実行1ジョブ・1ジョブ最大1時間・データ保持最大7日で、管理画面の定期実行は利用できません。有料は1ユニット月9ドルからです。

## Scrapyの担当範囲とライブラリの選び方

Scrapyは、Python製のクローリング・スクレイピングフレームワークです。リンクをたどってページを集める「クローリング」と、HTMLから値を抜き出す「スクレイピング」を1つの枠組みで扱います。リクエストのスケジューリング、同時実行数の制御、リトライ、重複URLの除外、ファイル出力までが組み込まれている点が、HTMLパーサ単体との違いです。両者の線引きやAPI利用との使い分け、法務面の判断は[スクレイピングとは？クローリング・APIとの違いと実装・法務の判断を解説](/tech/details/13414/)で扱っています。

| 選択肢                    | 向く規模     | JS描画       | 待機・リトライ | 導入の重さ       |
| ---------------------- | -------- | ---------- | ------- | ----------- |
| Scrapy                 | 数百ページ以上  | 不可（別手段と連携） | 組み込み    | プロジェクト構成が必要 |
| requests＋BeautifulSoup | 数十ページ    | 不可         | 自作      | スクリプト1本     |
| Selenium／Playwright    | 数十〜数百ページ | 可          | 自作      | ブラウザ実体が必要   |

ページ数よりも、待機間隔やリトライを自分で書きたいかどうかで決めます。書きたくないならScrapy、単発の取得ならパーサ単体で足ります。パーサ側は[BeautifulSoupとは？pip installと使い方（find・select）・文字化け対策を解説【bs4 4.15】](/tech/details/3018/)、JavaScriptで描画されるページは[Playwright MCPとは？設定・使い方からDify連携まで実務ガイド【2026年版】](/tech/details/6172/)が参考になります。Scrapyはブラウザを内蔵しないため、描画後のDOMが必要なサイトでは別の手段と組み合わせます。

## 動作環境と2.13〜2.19の変更点

### 版ごとの対応Pythonと主な変更

| 版      | 公開日        | Python    | 主な変更                     |
| ------ | ---------- | --------- | ------------------------ |
| 2.13.0 | 2025-05-08 | 3.9〜      | start()導入／asyncioリアクタ既定化 |
| 2.14.0 | 2026-01-05 | 3.10〜     | 3.9とPyPy 3.10を切り捨て       |
| 2.16.0 | 2026-05-19 | 3.10〜3.14 | start\_requests()を削除     |
| 2.17.0 | 2026-07-07 | 3.10〜3.14 | s3://を既定でHTTPS化          |
| 2.18.0 | 2026-08-20 | 3.10〜3.14 | brotli・zstd必須化           |
| 2.19.0 | 2026-09-10 | 3.10〜3.15 | RemoteControl拡張          |

2.19.0のパッケージ定義は `requires_python >=3.10` です。Python 3.9の環境で `pip install scrapy` を実行すると2.13系までしか解決しません。古い解説どおりに進めてインストールが通らないときは、まず手元のPythonのマイナーバージョンを確認してください。版ごとの変更の全文は[Scrapy公式のリリースノート](https://docs.scrapy.org/en/latest/news.html)にあります。

### 2.18・2.19で変わった既定の挙動

2.18.0では、Brotliと`Zstandard`の展開が必須の依存になりました。リクエストの `Accept-Encoding` に `br` と `zstd` が常に入るため、以前と違う圧縮形式のレスポンスが返ってくるサイトがあります。同じ版で、スパイダー属性の `download_delay` が非推奨になりました。待機は `DOWNLOAD_DELAY` 設定か、ドメイン別の `DOWNLOAD_SLOTS` で指定します。`start()` の中で例外が出たときに、終了理由が `finished` ではなく `start_error` になったのも2.18.0からです。

2.19.0では `RANDOMIZE_DOWNLOAD_DELAY` が非推奨になり、揺らぎの幅を数値で指定する `DOWNLOAD_DELAY_JITTER`（既定0.5＝±50%）に置き換わりました。旧設定を書くと `ScrapyDeprecationWarning` が出ることを2.19.0で確認しています。`FEEDS` 設定では、`format` を省くと出力先の拡張子から形式が推定されるようになりました。

### RemoteControl拡張と公式MCPサーバー

2.19.0で運用時に確認したい変更の一つが、既定で有効な `RemoteControl` 拡張です。クロール中のプロセスにHTTPで接続し、統計の確認やコードの実行ができます。[2.19.0のソース](https://github.com/scrapy/scrapy/blob/2.19.0/scrapy/extensions/remote%5Fcontrol.py)では、待ち受けは `127.0.0.1` のランダムなポートで、Bearerトークンによる認証が必要です。トークンとポートはジョブファイルに書き出されます。実行すると、ログに次の1行が出ます。

```
[scrapy.extensions.remote_control] INFO: Remote control HTTP server listening on port 42297 (job 19-57dc5568f92f4a75ab2ee2d6eacc0f38)
```

外部から直接は届きませんが、同じホストの別ユーザーがジョブファイルを読めれば、クロール中のプロセスでコードを実行できます。共用サーバーや、複数の利用者が同じ環境で動かすコンテナでは、`REMOTE_CONTROL_ENABLED = False` を `settings.py` に書いて止めておくのが安全です。ジョブファイルの置き場所は `REMOTE_CONTROL_JOBS_DIR` で変えられ、既定は `platformdirs` のユーザー状態ディレクトリ配下です。

この拡張の使い道は、コーディングエージェントからの調査です。公式は2.19.0で、エージェント向けのプラグイン（`scrapy/scrapy-agent-plugin`）と、実行中のクロールにつなぐ[Scrapy MCPサーバー](https://github.com/scrapy/scrapy-mcp-official)を案内しています。統計の推移を見て「リクエストは出ているのにアイテムが出ない」原因を探す、といった用途です。MCPそのものの仕組みは[MCPとは？AIと外部ツールをつなぐ標準規格とMCPサーバーの仕組み・作り方を解説](/tech/details/5736/)を参照してください。

### 2.17未満に残る既知の脆弱性

2.14.2（2026年3月12日）で修正された GHSA-cwxj-rr6w-m6w7 は深刻度「高」で、影響範囲は1.4.0〜2.14.1です。`RefererMiddleware` がレスポンスの `Referrer-Policy` ヘッダを呼び出し可能オブジェクトのパスとして解釈し、クロール先のサーバーが任意のモジュールを読み込ませることができました。もう1件の GHSA-76g3-c3x4-crvx も深刻度「高」で、2.16以下の `S3DownloadHandler` が署名済みのS3リクエストを平文HTTPで送っていました。どちらも[Scrapyのセキュリティアドバイザリ](https://github.com/scrapy/scrapy/security/advisories)に掲載されています。版を固定するなら2.17.0以上にしてください。

## インストールからスパイダー実行までの手順

### インストールとプロジェクト生成

```
pip install scrapy
scrapy startproject quotes_crawler
cd quotes_crawler
```

`startproject` は `scrapy.cfg`、`settings.py`、`items.py`、`pipelines.py`、`spiders` ディレクトリを作ります。このとき作られる `settings.py` はフレームワークの既定値より抑制的な値を持つため（後述）、練習でもプロジェクトを作ってから始めるほうが安全です。

### genspiderでのスパイダー雛形作成

```
scrapy genspider quotes quotes.toscrape.com
```

2.19.0で生成されるのは、`name`、`allowed_domains`、`start_urls`、空の `parse` だけの最小構成です。`start_urls` を書けば、`Spider.start` の既定実装がそこからリクエストを作るため、起点のコードは不要です。`allowed_domains` に無いドメインへのリクエストは `Filtered offsite request` というログとともに捨てられ、統計の `offsite/filtered` に件数が出ます。練習用には公式チュートリアルと同じ quotes.toscrape.com を使います。練習用サイトにもリクエスト処理の負荷は生じるため、待機間隔と同時実行数を抑えて利用します。2.19.0からは `-t` にテンプレートファイルのパスも渡せます。

### parseメソッドの実装とページ送り

```
import scrapy


class QuotesSpider(scrapy.Spider):
    name = "quotes"
    allowed_domains = ["quotes.toscrape.com"]
    start_urls = ["https://quotes.toscrape.com/page/1/"]

    def parse(self, response):
        for card in response.css("div.quote"):
            yield {
                "text": card.css("span.text::text").get(),
                "author": card.css("small.author::text").get(),
                "tags": card.css("div.tags a.tag::text").getall(),
            }
        next_page = response.css("li.next a::attr(href)").get()
        if next_page:
            yield response.follow(next_page, callback=self.parse)
```

`parse` で辞書を `yield` すればアイテムになり、`items.py` の定義は必須ではありません。`response.follow` は相対URLを解決するので、`urljoin` は要りません。値が取れないと `.get()` は `None` を返してそのまま進むため、セレクタは後述のシェルで先に確かめます。

### crawlの実行とファイル出力

```
scrapy crawl quotes -O quotes.json
scrapy crawl quotes -o quotes.jsonl
```

`-O`（大文字）は上書き、`-o`（小文字）は追記です。JSON形式で `-o` を繰り返すと、配列の後ろに次の配列が続き、1つのJSONとして読めないファイルになります。結果を貯めるなら1行1件の `jsonl`、毎回作り直すなら `-O` を使います。試しに `-s CLOSESPIDER_PAGECOUNT=3` を付けて走らせると、2.19.0で上の `quotes` を最後まで走らせると、10ページから100件が出力され、robots.txtを含めて11リクエストでした。

### scrapy shellでのセレクタ検証

```
scrapy shell "https://quotes.toscrape.com/page/1/"
>>> response.css("span.text::text").get()
>>> response.css("li.next a::attr(href)").get()
```

シェルはレスポンスを保持したまま対話的にセレクタを試せるので、スパイダーの書き換えと再実行の往復がなくなります。ブラウザの開発者ツールに見えるのはJavaScript実行後のDOMで、Scrapyが受け取るのはHTMLそのものです。開発者ツールからコピーしたセレクタが効かないときは、`response.text` に目的の要素があるかを先に見ます。

## Item Pipelineとスパイダー引数の書き方

### process\_itemでの検証と重複除去

取れた値の整形・検証・保存はパイプラインに分けます。`pipelines.py` に書き、`settings.py` の `ITEM_PIPELINES` で有効にします。数字が小さいほど先に実行されます。

```
# pipelines.py
from itemadapter import ItemAdapter
from scrapy.exceptions import DropItem


class CleanQuotesPipeline:
    def open_spider(self):
        self.seen = set()

    def process_item(self, item):
        adapter = ItemAdapter(item)
        text = (adapter.get("text") or "").strip("“”")
        if not text:
            raise DropItem("text が空")
        if text in self.seen:
            raise DropItem(f"重複: {text[:20]}")
        self.seen.add(text)
        adapter["text"] = text
        return item

# settings.py
ITEM_PIPELINES = {
    "quotes_crawler.pipelines.CleanQuotesPipeline": 300,
}
```

既存の解説の多くは `process_item(self, item, spider)` と書いています。2.19.0でこの形のまま動かすと、`open_spider()` と `process_item()` のそれぞれに「spider引数は将来渡されなくなる」という `ScrapyDeprecationWarning` が出ました。この警告は2.14.0から出ており、2.17.0では `startproject` の雛形からも `spider` 引数が消えています。スパイダーの情報が必要なら、`from_crawler()` で受け取った `crawler` を保持し、その `spider` 属性から読みます。

### \-aオプションによる起点URLの切り替え

起点をコマンドラインから変えたいときは、スパイダー引数（`-a`）を受け取り、`start()` でリクエストを作ります。

```
import scrapy


class ByTagSpider(scrapy.Spider):
    name = "bytag"
    allowed_domains = ["quotes.toscrape.com"]

    def __init__(self, tag="love", *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.tag = tag

    async def start(self):
        yield scrapy.Request(f"https://quotes.toscrape.com/tag/{self.tag}/")

    def parse(self, response):
        for card in response.css("div.quote"):
            yield {
                "text": card.css("span.text::text").get(),
                "author": card.css("small.author::text").get(),
                "tags": card.css("div.tags a.tag::text").getall(),
            }
        next_page = response.css("li.next a::attr(href)").get()
        if next_page:
            yield response.follow(next_page, callback=self.parse)
```

```
scrapy crawl bytag -a tag=humor -O humor.jsonl
```

2.19.0でこのコマンドを実行すると、humorタグの12件が出力されました。`-a` の値は文字列で渡るので、数値として使うなら `int()` で変換します。

## start()への移行と2.16での削除

`Spider.start` は2.13で追加された非同期ジェネレータで、既定の実装は `start_urls` を順に読んでリクエストを作ります。`start_urls` だけを書くスパイダーは何も変えずに動きます。書き換えが要るのは、起点でPOSTを投げる、ヘッダやクッキーを付ける、DBから対象URLを読むなど、`start_requests()` を自分で定義していた場合です。

```
# 2.16.0で削除された書き方
def start_requests(self):
    yield scrapy.Request("https://quotes.toscrape.com/page/1/")

# 2.13以降の書き方
async def start(self):
    yield scrapy.Request("https://quotes.toscrape.com/page/1/")
```

上のようにリクエストを直接yieldする例では、`def` を `async def` に変え、メソッド名を差し替えれば移行できます。問題は削除後の挙動です。`start_requests()` だけを定義したスパイダーを2.19.0で実行すると、WARNINGは1行も出ず、ダウンロードは0件、終了理由は `finished` でした。2.13より前の版でも動かす必要があるなら、`start()` と `start_requests()` を両方定義します。2.16以降では後者が無視されるだけです。

2.13では `TWISTED_REACTOR` の既定が `AsyncioSelectorReactor` になり、asyncio前提のライブラリを設定なしで `await` できるようになりました。一方、サードパーティのスパイダーミドルウェアのうち同期版 `process_spider_output()` しか持たないものは2.16.0で動かなくなっています。外部プラグインを使っている場合は、対応状況を確かめてから版を上げてください。

## settings.pyの既定値と雛形の差

| 設定キー                              | フレームワークの値 | startproject雛形の値 |
| --------------------------------- | --------- | ---------------- |
| ROBOTSTXT\_OBEY                   | False     | True             |
| DOWNLOAD\_DELAY                   | 0         | 1                |
| CONCURRENT\_REQUESTS\_PER\_DOMAIN | 8         | 1                |
| FEED\_EXPORT\_ENCODING            | None      | utf-8            |
| DOWNLOAD\_DELAY\_JITTER           | 0.5       | （指定なし）           |
| REMOTE\_CONTROL\_ENABLED          | True      | （指定なし）           |

公式ドキュメントは「`startproject` が設定する値をDefault、`scrapy.settings.default_settings` の値をfallback」として記載しています。ドキュメントの「Default」は、プロジェクト外で動かしたときの値と一致しないことがあります。プロジェクトの外で、個別の上書きをしない1ファイルのスパイダーを `scrapy runspider` で動かすと、`ROBOTSTXT_OBEY` はFalse、`DOWNLOAD_DELAY` は0、`FEED_EXPORT_ENCODING` は `None` でした。robots.txtを読まず、待機なしで連続してリクエストを送る状態です。robots.txtの書き方と効く範囲は[robots.txtとは？クロール制御の書き方と効く場面・不要な場面【2026年時点】](/column/details/16577/)で整理しています。

`FEED_EXPORT_ENCODING` が `None` のままだと、JSON系の出力で日本語が `\u65e5\u672c\u8a9e` のような数値エスケープになります。2.19.0で確かめたところ、`.json` だけでなく `.jsonl` でも同じでした。プロジェクト外で動かすときは `-s FEED_EXPORT_ENCODING=utf-8` を付けます。なお `RETRY_TIMES` の既定2は「初回＋再試行2回＝計3リクエスト」の意味です。

## Scrapy Cloudへのデプロイ手順と料金

### shubでのログインとデプロイ

```
pip install shub
shub login
shub deploy
```

`shub` はScrapy Cloudのコマンドラインクライアントで、2026年10月時点の最新は2.18.1（2026年7月8日公開・Python 3.10以上）です。`shub login` はAPIキーを `~/.scrapinghub.yml` に保存します。CIでは対話入力を避けて `SHUB_APIKEY` 環境変数を使います。初回の `shub deploy` ではウィザードが起動し、プロジェクトIDを `scrapy.cfg` と同じ階層の `scrapinghub.yml` に保存します。

```
# scrapinghub.yml
projects:
  default: 12345
stack: scrapy:2.18-20260824
requirements:
  file: requirements.txt
```

実行環境は `stack` で固定します。2026年10月26日時点で[公開されている最新のスタック](https://github.com/scrapinghub/scrapinghub-stack-scrapy/tags)は `scrapy:2.18-20260824` で、中身はScrapy 2.18.0とPython 3.14.5です。2.19.0のスタックはまだありません。ローカルを2.19.0で開発して `DOWNLOAD_DELAY_JITTER` を書いても、クラウド側の2.18.0では使えません。デプロイ前提のプロジェクトは、ローカルも `pip install "scrapy==2.18.0"` で合わせておくと、手元とクラウドで結果が食い違いません。追加のパッケージは `requirements.txt` に書き、`requirements` の `file` で指定します（[shubの設定ドキュメント](https://shub.readthedocs.io/en/latest/configuration.html)）。

### ジョブの実行とログ・アイテムの取得

```
shub schedule quotes
shub log -f 2/34
shub items -f 2/34
```

`shub schedule` にスパイダー名を渡すと、クラウドでジョブが走ります。ジョブIDは「プロジェクトID／スパイダーID／ジョブID」の形式で、`scrapinghub.yml` に既定のプロジェクトがあれば `2/34` のように省略できます。`-f` を付けると、実行中のログとアイテムを追い続けます。ローカルの `scrapy crawl` と出力ファイルの確認が、そのまま `shub schedule` と `shub items` に置き換わります。[Zyteのサポート記事](https://support.zyte.com/support/solutions/articles/22000200419-scheduling-periodic-jobs)によれば、管理画面の定期実行（Periodic Jobs）は2017年10月10日から有料プラン限定です。

### 無料プランと有料プランの分かれ目

| 項目             | 無料        | 有料（1ユニット月9ドル）     |
| -------------- | --------- | ----------------- |
| ジョブ実行時間        | 最大1時間     | 制限なし              |
| データ保持          | 7日        | 最大120日            |
| リソース           | 通常ユニットの半分 | RAM 1GB／ディスク2.5GB |
| 同時実行           | 1本        | 保有ユニット数まで         |
| 定期実行           | 不可        | 可                 |
| カスタムDockerイメージ | 不可        | 可                 |

境目はリクエスト数ではなく、1ジョブの時間と定期実行の可否です。[Zyteの料金ドキュメント](https://docs.zyte.com/scrapy-cloud/pricing.html)では、無料枠に付くのは通常ユニットの半分のリソースを持つlow-resource unitで、有料は1ユニット月9ドルです。無料枠は1時間でジョブが打ち切られるので、ページ数と `DOWNLOAD_DELAY` から所要時間を先に見積もります。1秒間隔で1時間送り続けても単純計算で3,600リクエストで、応答時間・再試行・robots.txtの取得を差し引くと、完了するページ数はそれより少なくなります。

## Scrapy Cloud・Scrapyd・cronの選び分け

| 運用先               | 定期実行             | ログ・結果の閲覧      | 費用        |
| ----------------- | ---------------- | ------------- | --------- |
| Scrapy Cloud      | 有料プランで管理画面から     | Web画面・shub    | 月9ドル／ユニット |
| Scrapyd（自前サーバー）   | なし（cronからAPIを叩く） | HTTP API・簡易画面 | サーバー代のみ   |
| cron＋scrapy crawl | cronで設定          | ファイルとログを自前で管理 | サーバー代のみ   |

Scrapy Cloudを選ぶ理由は、ジョブ履歴・ログ・アイテムの保存と閲覧を作らずに済む点に尽きます。スパイダーが1〜2本で、結果を毎回DBやS3に書き出すなら、cronから `scrapy crawl` を叩くだけで足ります。スパイダーが増えて「どれがいつ失敗したか」を追うのがつらくなったら、Scrapy Cloudに移す時期です。Scrapydは中間の選択肢で、最新の1.6.0（2025年7月22日）は既定で `127.0.0.1:6800` にHTTP APIを開き、`schedule.json` でジョブを登録します。ただし定期実行の機能は持たないため、cronから `curl http://localhost:6800/schedule.json -d project=myproject -d spider=quotes` を叩く形になります。

Scrapy Cloudに向かないのは、クロール対象が社内ネットワークにある場合と、取得データを社外のクラウドに置けない場合です。どちらもデータの置き場所の問題なので、自前のサーバーで動かします。収集の仕組みを業務システムに組み込む場合は、[フルスクラッチ開発](/service/system/fullscratch/)で収集・保存・画面までまとめて設計する方法もあります。

## つまずきやすいエラーの切り分け

- アイテムが0件で、ログにも統計にもダウンロードが無い：`start_requests()` だけで起点を書いていないかを見ます。2.16以降は無視されます。
- アイテムが0件で、ログに `Forbidden by robots.txt:` がある：雛形の `ROBOTSTXT_OBEY=True` によるスキップで、リクエスト自体が送られていません。
- 統計に `offsite/filtered` が出ている：たどったリンクが `allowed_domains` の外です。サブドメインを含めるなら親ドメインを書きます。
- 要素が `None` になる：JavaScript描画が原因か、セレクタの誤りかを `scrapy shell` の `response.text` で切り分けます。
- 2.18.0に上げたら `crawler.stats` を読む行で `RuntimeError`：クロール開始前に `stats` などを読むと、`None` ではなく例外になりました。`if crawler.stats:` のような判定は書き換えます。
- POSTの後でフォームの値が消える：2.14.2以降はPOSTへの301リダイレクトがGETに変わります。`scrapy.FormRequest` は2.16.0で非推奨になりましたが、2.17.0でクラス自体の非推奨は撤回されました。引き続き非推奨なのは `from_response()` で、form2requestへの移行が案内されています。

ログレベルの既定はDEBUGで、雛形も上書きしません。どこで止まっているか分からないときはまずログを読み、多すぎれば `scrapy crawl quotes -L INFO` で絞ります。

## よくある質問

### Scrapy Cloudの無料プランだけで定期クロールを回せますか？

管理画面の定期実行は有料プラン限定なので、無料のままでは設定できません。外部のcronやCIから、`SHUB_APIKEY` を渡して `shub schedule` を実行すればジョブは起動できます。ただし1ジョブ1時間・データ保持7日の制限は残るため、日次で少数のページを巡回し、その都度結果を取り出す用途に限られます。

### Scrapy CloudでScrapy 2.19を使えますか？

2026年10月26日時点の最新スタックは `scrapy:2.18-20260824` で、2.19.0のスタックは公開されていません。`RemoteControl` 拡張や `DOWNLOAD_DELAY_JITTER` などの2.19の機能は、2.18スタックでは使えません。有料プランならカスタムDockerイメージをデプロイできるので、2.19の実行環境を自分で用意する方法はあります。スタックの一覧は更新されるので、デプロイ前に公開されているタグを確認してください。

### Python 3.9でScrapyを動かせますか？

2.14.0でPython 3.9のサポートが切れたため、3.9では `pip install "scrapy<2.14"` で2.13系に固定するしかありません。`shub` も2.16.0以下に揃えます。ただし2.13系は、上で挙げた深刻度「高」の脆弱性2件の両方に該当します。Pythonを3.10以上に上げるのが先です。

### ScrapyとBeautifulSoupは併用できますか？

`parse` の中で `BeautifulSoup(response.text, "html.parser")` を呼べば併用できます。ただしScrapyには `response.css` と `response.xpath` があるため、抽出の書き方が2系統になるだけです。既存のBeautifulSoupのコードを流用する移行期を除き、Scrapyのセレクタに寄せるほうが保守は楽です。

### robots.txtを無視する設定にしても問題ありませんか？

`ROBOTSTXT_OBEY=False` はいつでも設定できますが、技術的にできることと許されることは別です。サイトの利用規約、アクセス頻度による業務妨害、取得データの利用目的は、それぞれ別の論点です。判断の枠組みは[スクレイピングとは？クローリング・APIとの違いと実装・法務の判断を解説](/tech/details/13414/)で整理しています。Python以外で書く場合はGo言語の[Collyの運用設定｜robots.txt・レート制限・文字化けを実測で解説](/tech/details/3320/)も比較材料になります。

## 関連記事

- [スクレイピングとは？クローリング・APIとの違いと実装・法務の判断を解説](/tech/details/13414/)
- [BeautifulSoupとは？pip installと使い方（find・select）・文字化け対策を解説【bs4 4.15】](/tech/details/3018/)
- [Playwright MCPとは？設定・使い方からDify連携まで実務ガイド【2026年版】](/tech/details/6172/)
- [robots.txtとは？クロール制御の書き方と効く場面・不要な場面【2026年時点】](/column/details/16577/)
- [Collyの運用設定｜robots.txt・レート制限・文字化けを実測で解説](/tech/details/3320/)

---

出典: [Scrapyの使い方とScrapy Cloudへのデプロイ手順【2.19対応】](<https://www.issoh.co.jp/column/details/2611/>)（株式会社一創）
