# Python 3.15 для веб-скрапинга: что устанавливается, а что ломается

Source: https://ipvolt.com/ru/blog/python-3-15-web-scraping
Markdown: https://ipvolt.com/ru/blog/python-3-15-web-scraping.md
Language: ru

[ipvolt — главная](https://ipvolt.com/ru.md) / [Блог](https://ipvolt.com/ru/blog.md) / Python 3.15 для веб-скрапинга: что ставится, а что ломается

Анализ
Опубликовано: 2026-10-16
Обновлено: 2026-10-16
Автор: ipvolt
8 мин чтения

pip install scrapy на Python 3.15 без компилятора C падает: у brotli нет колеса cp315. Мы поставили 19 пакетов для скрапинга через pip и uv и проверили остальное.

На Python 3.15.0 большая часть стека для скрапинга ставится из готовых колёс (wheels) и проходит smoke-тест. Всё, что требует brotli или zstandard, на машине без компилятора C не ставится, потому что ни у одного из них нет колеса для 3.15, и это касается даже простого `pip install scrapy`. Быстрое решение — установить `gcc` перед `pip install` (решение 1 ниже) или остаться на Python 3.14, пока brotli не опубликует колёса cp315 (решение 2).

**Последняя проверка: 16 октября 2026 года, 10:09 UTC.** На тот момент на PyPI всё ещё не было колёс cp315 для brotli 1.2.0 и zstandard 0.25.0. В zope.interface 8.7, вышедшем 15 октября, колёса cp315 появились.

| Пакет | Версия | Колесо cp315 | С компилятором | Без компилятора | Примечания |
| --- | --- | --- | --- | --- | --- |
| `scrapy` | 2.19.0 | чистый Python; нет (brotli 1.2.0) | ставится | ошибка сборки brotli | требует brotli на CPython с 2.18.0 |
| `requests[socks]` | 2.34.2 + PySocks 1.7.1 | чистый Python | ставится | ставится |  |
| `httpx[socks]` | 0.28.1 + socksio 1.0.0 | чистый Python | ставится | ставится |  |
| `httpx[brotli]` | 0.28.1 | нет (brotli 1.2.0) | ставится | ошибка сборки brotli | `httpx brotlicffi` ставится без компилятора |
| `httpx[zstd]` | 0.28.1 | нет (zstandard 0.25.0) | ставится | ошибка сборки zstandard | самая долгая сборка |
| `aiohttp` | 3.14.5 | да | ставится | ставится |  |
| `aiohttp[speedups]` | 3.14.5 + aiodns 4.0.4 | нет (Brotli 1.2.0) | ставится | ошибка сборки Brotli | `aiohttp aiodns brotlicffi` ставится |
| `aiohttp-socks` | 0.12.0 | чистый Python | ставится | ставится |  |
| `urllib3[brotli]` | 2.8.0 | нет (brotli 1.2.0) | ставится | ошибка сборки brotli | `urllib3 brotlicffi` ставится |
| `curl_cffi` | 0.16.3 | abi3 | ставится | ставится |  |
| `playwright` | 1.64.0 | не зависит от версии | ставится | ставится | браузеры не проверялись |
| `lxml` | 6.1.3 | да | ставится | ставится |  |
| `beautifulsoup4` | 4.15.0 | чистый Python | ставится | ставится |  |
| `parsel` | 1.12.1 | чистый Python | ставится | ставится |  |
| `selectolax` | 1.0.0 | да | ставится | ставится | 1.0: `selectolax.parser` выдал ImportError, используйте `selectolax.lexbor` |
| `pandas` | 3.0.6 + numpy 2.5.4 | да | ставится | ставится |  |
| `pydantic` | 2.14.1 + pydantic-core 2.50.1 | pydantic-core: да | ставится | ставится |  |
| `orjson` | 3.13.0 | да | ставится | ставится |  |
| `tenacity` | 9.2.1 | чистый Python | ставится | ставится |  |

«С компилятором» и «без компилятора» — это официальный образ `python:3.15-slim` с `gcc` и без него. Каждый пакет ставился и через pip, и через uv, и результаты совпали во всех случаях. У чисто питоновского пакета нет скомпилированного кода, поэтому колесо cp315 ему не нужно. Каждая успешная установка прошла свой smoke-тест.

## pip install scrapy падает на Python 3.15: Failed building wheel for brotli

В slim-образе pip 26.2.1 останавливается на brotli:

```text
  × Building wheel for brotli (pyproject.toml) did not run successfully.
  │ exit code: 1
      error: [Errno 2] No such file or directory: 'gcc'
  ERROR: Failed building wheel for brotli
error: failed-wheel-build-for-install

× Failed to build installable wheels for some pyproject.toml based projects
╰─> brotli
```

uv 0.13.1 падает на том же пакете и показывает цепочку зависимостей:

```text
error: Failed to build `brotli==1.2.0`
  cause: The build backend returned an error
hint: `brotli` (v1.2.0) was included because `scrapy` (v2.19.0) depends on `brotli`
```

Цепочка короткая. Scrapy 2.19.0 написан на чистом Python, но требует `brotli>=1.2.0; implementation_name != "pypy"`, так что любая установка на CPython тянет brotli. Это требование появилось в Scrapy 2.18.0 (20 августа 2026 года); в 2.17.0 его не было. У brotli 1.2.0, выпущенного 5 ноября 2025 года, есть колёса для CPython 2.7 и 3.6–3.14 и ничего новее. Без подходящего колеса pip и uv скачивают архив исходников и компилируют расширение `_brotli`, а для этого нужен `gcc`. То же происходит с `httpx[brotli]`, `aiohttp[speedups]` и `urllib3[brotli]`, которым на CPython тоже нужен пакет `brotli`, и с `httpx[zstd]`, которому нужен zstandard 0.25.0.

### Решение 1: добавить компилятор в образ

Этой одной строки в slim-образе хватило для всех пакетов, которые падали:

```sh
apt-get update && apt-get install -y --no-install-recommends gcc libc6-dev
```

Она установила gcc 14.2.0. После этого `pip install scrapy` занял 28 с вместо ошибки, uv — 19 с, а паук обошёл тестовые страницы, включая сжатую brotli. Дольше всего собирается zstandard: 63 с для `httpx[zstd]` через pip. В Dockerfile поставьте эту строку перед `pip install`.

Проверена только эта строка для Debian. В Windows компилятор для таких сборок входит в Microsoft [C++ Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/); Windows мы не проверяли.

### Решение 2: остаться на Python 3.14, пока не появятся колёса

Для Python 3.14 колёса brotli и zstandard есть, так что там этой проблемы нет. Чтобы узнать, появились ли колёса brotli, запустите это на Python 3.15:

```sh
python3 -m pip download --only-binary :all: --no-deps -d /tmp/wheel-check brotli
```

16 октября команда всё ещё завершалась строкой `ERROR: No matching distribution found for brotli`. Как только она скачает файл `.whl`, колёса cp315 опубликованы и `pip install scrapy` работает без компилятора.

В апстриме [issue #25 в google/brotli-wheels](https://github.com/google/brotli-wheels/issues/25), «Python 3.15 wheels missing», открыли 9 октября, и на 16 октября ответов в нём не было. [Pull request #1583 в google/brotli](https://github.com/google/brotli/pull/1583) добавляет в CI задачу, которая собирает колёса cp315. На 16 октября он всё ещё был открыт без ревью, а единственный комментарий оставил бот CLA. В его описании сказано, что опубликовать колёса на PyPI всё равно должен мейнтейнер.

### Не Scrapy? У brotlicffi есть колесо

brotlicffi 1.2.0.2 поставляется с колесом `abi3`, которое pip установил на 3.15. HTTPX, urllib3 и aiohttp принимают его вместо `brotli`, поэтому без компилятора эти варианты сработали и распаковали ответ, сжатый brotli:

```sh
pip install httpx brotlicffi
pip install urllib3 brotlicffi
pip install aiohttp aiodns brotlicffi
```

Последняя строка — это `aiohttp[speedups]` без требования `Brotli`. Scrapy так не умеет: на CPython ему нужен именно пакет `brotli`.

С zstd всё проще, чем кажется. На Python 3.14 и новее urllib3 2.8.0 и aiohttp 3.14.5 распаковывают zstd модулем стандартной библиотеки `compression.zstd`, поэтому оба предложили серверу `zstd` и распаковали ответ в zstd без дополнительных пакетов. zstandard нужен только для `httpx[zstd]`.

## Не используйте --only-binary вслепую

`--only-binary :all:` запрещает pip собирать что-либо из исходников. Это выглядит как очевидный обходной путь, и ошибки он не даёт:

```sh
pip install --only-binary :all: "httpx[brotli]" "aiohttp[speedups]"
```

pip вывел `INFO: This is taking longer than usual`, пока перебирал версии, и установил httpx 0.18.2 (июнь 2021 года) и aiohttp 0.13.1 (декабрь 2014 года). Единственной другой подсказкой была одна строка:

```text
WARNING: aiohttp 0.13.1 does not provide the extra 'speedups'
```

Резолвер откатывался по старым выпускам, пока не нашёл те, чьи зависимости можно удовлетворить одними колёсами. `uv pip install --no-build` выбрал те же две версии и вывел ``warning: The package `aiohttp==0.13.1` does not have an extra named `speedups` ``.

Если сузить флаг до одного пакета, безопаснее не станет. `pip install --only-binary brotli scrapy` тоже завершается с кодом 0 и ставит Scrapy 2.17.0 — последний выпуск без требования brotli. uv сделал то же самое. Этот Scrapy обошёл тестовые страницы, но предлагал серверам только `gzip, deflate`, тогда как 2.19.0 с brotli предлагал `gzip, deflate, br, zstd`. Если ваши пауки используют `async def start()`, 2.17.0 их всё равно запустит.

Чтобы заметить тихий откат версии, смотрите установленные версии после каждой установки:

```sh
pip list
uv pip list
```

Чтобы установка вместо этого громко падала, закрепите нужную версию рядом с флагом:

```sh
pip install --only-binary brotli "scrapy==2.19.0"
```

```text
ERROR: Could not find a version that satisfies the requirement brotli>=1.2.0; implementation_name != "pypy" (from scrapy) (from versions: none)
ERROR: No matching distribution found for brotli>=1.2.0; implementation_name != "pypy"
```

uv с тем же закреплением остановился на `error: No solution found when resolving dependencies`. `requirements.txt` с точными версиями пакетов верхнего уровня даёт ту же защиту при каждой сборке.

## Исправлено 15 октября: zope.interface без C-ускорений

Twisted, а вместе с ним и Scrapy, зависит от zope.interface. У zope.interface 8.6 колёса есть только до CPython 3.14. 14 октября без компилятора pip и uv всё равно установили его на 3.15: если C-расширение не собирается, сборка переходит на чистый Python. Ни ошибки, ни предупреждения в выводе установки не было.

Цена была видна на базовой проверке интерфейса. В лаборатории `IThing.providedBy(obj)` занимал 271 нс на вызов без C-расширения и 101 нс с ним. Что это значит для целого обхода, лаборатория не измеряла.

В zope.interface 8.7, вышедшем 15 октября, есть колёса cp315. 16 октября чистая установка без компилятора получила через pip и uv бинарное колесо 8.7, C-расширение импортировалось, а та же проверка заняла 102 нс. Виртуальное окружение, созданное до 15 октября, остаётся с 8.6 на чистом Python, пока вы не обновите zope.interface.

Чтобы узнать, какой вариант у вас:

```sh
python -c "import zope.interface._zope_interface_coptimizations"
```

`ModuleNotFoundError` означает запасной вариант на чистом Python. С колесом 8.7 или с установленным gcc импорт прошёл.

## Другие изменения 3.15, важные для скрапинга

Заметнее всего будет режим UTF-8, теперь включённый по умолчанию ([PEP 686](https://peps.python.org/pep-0686/)). В [What's New in Python 3.15](https://docs.python.org/3.15/whatsnew/3.15.html#whatsnew315-utf8-default) сказано, что операции ввода-вывода без явной кодировки, например `open('flying-circus.txt')`, теперь используют UTF-8 независимо от окружения системы. В лаборатории с `LANG=C` вызов `open()` без `encoding` на 3.15 писал в UTF-8, а с `-X utf8=0` возвращался к `ANSI_X3.4-1968`, то есть к ASCII.

Для скраперов это в основном касается экспорта. CSV- или JSON-файл, записанный через `open(path, "w")`, теперь в UTF-8 на любой машине, включая Windows-системы, где 3.14 брал кодовую страницу локали. Обычно это то, что нужно. Если программа дальше по цепочке ждёт старую кодировку, передайте `encoding="locale"` или задайте `PYTHONUTF8=0`; а лучше явно указывайте кодировку и при записи, и при чтении.

## Если вы заодно обновляете Scrapy

Переход на Python 3.15 часто идёт вместе с новым Scrapy. Начиная с 2.16, Scrapy больше не вызывает `start_requests()`: паук, в котором есть только этот метод, открывается, ничего не отправляет и закрывается как завершённый, без предупреждений. В статье [Scrapy обходит 0 страниц после обновления](/ru/guides/scrapy-start-requests-not-called) есть исправление в одну строку — `async def start()`, — и паук в этой лаборатории использовал именно его.

## Метод и ограничения

Записано 14 октября 2026 года на хосте Ubuntu x86_64, в файловой системе официального образа `python:3.15-slim` (Debian 13 trixie, дайджест индекса `sha256:ea4f1f29…`, собран 12 октября 2026 года), запущенной в отдельном пространстве имён Linux, а не в Docker. Интерпретатор сообщил `Python 3.15.0 (main, Oct 12 2026, 22:33:31) [GCC 14.2.0]`, с ним шли встроенный pip 26.2.1 и uv 0.13.1. В копию с компилятором gcc 14.2.0 был установлен строкой apt выше. Таблица составлена по этим запускам. 16 октября случаи Scrapy, `--only-binary brotli` и zope.interface повторили без компилятора: всё совпало с 14 октября, кроме zope.interface, который теперь пришёл из колеса 8.7.

Для каждого случая создавалось новое виртуальное окружение без кэша пакетов. Установленные версии и то, откуда пришёл каждый пакет — из бинарного колеса, из чисто питоновского колеса или из локальной сборки, — определялись по тегам колёс. Smoke-тесты обращались к локальному `http.server`, который сжимает ответ только кодировками, предложенными клиентом. Playwright был установлен, его браузеры — нет. Прокси не использовался.

Лаборатория ничего не говорит о macOS, Windows, ARM, образах на musl и сборках без GIL. PyPI меняется каждый день, поэтому повторите проверку колёс, прежде чем действовать по любой строке таблицы. Скрипт, smoke-тесты и сырые результаты лежат в [папке загрузок](/downloads/python-3-15-web-scraping/README.md): [lab315.py](/downloads/python-3-15-web-scraping/lab315.py), [results.csv](/downloads/python-3-15-web-scraping/results.csv), [results.json](/downloads/python-3-15-web-scraping/results.json) и повторный запуск 16 октября, [results-2026-10-16.json](/downloads/python-3-15-web-scraping/results-2026-10-16.json).

## Связанные материалы

- [Прокси в Scrapy 2.19](/ru/guides/scrapy-proxy-setup) — авторизация, ротация и ошибки прокси, которые пишет Scrapy.
- [Прокси в aiohttp](/ru/guides/aiohttp-proxy-setup) и [прокси в curl_cffi](/ru/guides/curl-cffi-proxy-setup) — оба установились на 3.15 из колёс.
- [Ошибка «Missing dependencies for SOCKS support»](/ru/guides/fix-missing-dependencies-for-socks-support) — другая ошибка установки в этом стеке.
- [Сколько ГБ прокси мне нужно?](/ru/blog/how-many-gb-of-proxies-do-i-need) — как оценить трафик, когда стек заработает. Сжатие там важно: клиент, предлагающий меньше кодировок, может скачивать больше байтов.

ipvolt строит прокси-инфраструктуру для разработчиков и агентов. [Вступите в лист ожидания](https://ipvolt.com/#waitlist-hero) — одно письмо, когда откроется доступ.

## Источники

- [Python.org: страница выпуска Python 3.15.0](https://www.python.org/downloads/release/python-3150/)
- [What's New in Python 3.15: UTF-8 как кодировка по умолчанию](https://docs.python.org/3.15/whatsnew/3.15.html#whatsnew315-utf8-default)
- [PEP 686: Make UTF-8 mode default](https://peps.python.org/pep-0686/)
- [PyPI: файлы brotli 1.2.0](https://pypi.org/project/brotli/1.2.0/#files)
- [PyPI: файлы zstandard 0.25.0](https://pypi.org/project/zstandard/0.25.0/#files)
- [PyPI: файлы zope.interface 8.6](https://pypi.org/project/zope.interface/8.6/#files)
- [PyPI: файлы zope.interface 8.7](https://pypi.org/project/zope.interface/8.7/#files)
- [PyPI: Scrapy 2.19.0](https://pypi.org/project/Scrapy/2.19.0/)
- [google/brotli-wheels, issue #25: Python 3.15 wheels missing](https://github.com/google/brotli-wheels/issues/25)
- [google/brotli, pull request #1583: Build and test CPython 3.15 wheels in CI](https://github.com/google/brotli/pull/1583)
- [Microsoft C++ Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/)

## Узнайте, когда откроется доступ к ipvolt.

Пока вы здесь

ipvolt в разработке. Оставьте email, и мы один раз напишем, когда откроется доступ.

Одно письмо, когда откроется доступ. Больше ничего.

[Получить ранний доступ](https://ipvolt.com/ru/blog/python-3-15-web-scraping#waitlist-blog-end)

[Конфиденциальность](https://ipvolt.com/privacy)


## Похожие статьи

- [Проверка прокси на утечки IP, DNS и WebRTC с помощью ToDetect](https://ipvolt.com/ru/blog/proxy-leak-check-todetect.md) (Анализ, 23 окт. 2026 г., 8 мин чтения): Проверяем браузерный прокси на утечки IP, DNS, WebRTC и часового пояса бесплатными инструментами ToDetect. Пример — замеры на мобильной линии 4G.
- [Парсинг японских цен: иены, полноширинные цифры и налоговые метки](https://ipvolt.com/ru/blog/japanese-price-parsing.md) (Анализ, 6 окт. 2026 г., 6 мин чтения): Разбирайте японские цены, не теряя валюту и признак налога. Запустите проверенную Python-фикстуру: полноширинная иена, смешанные цены и намеренные случаи «на проверку».
- [SOCKS5 и SOCKS5h: в чём разница и что отправляют 6 клиентов](https://ipvolt.com/ru/blog/socks5-vs-socks5h.md) (Сравнение, 4 окт. 2026 г., 7 мин чтения): socks5:// не везде означает локальный DNS. Мы записали, что curl, Requests, HTTPX, aiohttp, Playwright и Node отправляют SOCKS5-прокси для каждой схемы URL.

## Связанные руководства

- [Прокси в Scrapy 2.19: авторизация, ротация, ошибки](https://ipvolt.com/ru/guides/scrapy-proxy-setup.md): Настройка прокси в Scrapy 2.19: учётные данные в meta["proxy"], ротация по запросам, HTTP_PROXY и разбор TunnelError 407, пропущенного ответа 407 и ошибки socks5.
- [Scrapy: start_requests() не вызывается, Crawled 0 pages](https://ipvolt.com/ru/guides/scrapy-start-requests-not-called.md): В Scrapy 2.16 удалён Spider.start_requests(): паук пишет Crawled 0 pages и закрывается как finished без предупреждений. Решение: async def start(). Проверено на 2.19.
- [Прокси в aiohttp 3.14: авторизация, trust_env, ошибки](https://ipvolt.com/ru/guides/aiohttp-proxy-setup.md): Настройка прокси в aiohttp 3.14: чем заменить устаревшие BasicAuth и proxy_auth, как включить trust_env и что означают ошибки 407 и Bad status line. Проверено на 3.14.4.

## О ipvolt

Технический анализ от команды ipvolt.

Доступ к ipvolt пока не открыт.

[Читать оригинал на английском](https://ipvolt.com/blog/python-3-15-web-scraping.md)
