Анализ8 мин чтения

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

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С компиляторомБез компилятораПримечания
scrapy2.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)ставитсяошибка сборки brotlihttpx brotlicffi ставится без компилятора
httpx[zstd]0.28.1нет (zstandard 0.25.0)ставитсяошибка сборки zstandardсамая долгая сборка
aiohttp3.14.5даставитсяставится
aiohttp[speedups]3.14.5 + aiodns 4.0.4нет (Brotli 1.2.0)ставитсяошибка сборки Brotliaiohttp aiodns brotlicffi ставится
aiohttp-socks0.12.0чистый Pythonставитсяставится
urllib3[brotli]2.8.0нет (brotli 1.2.0)ставитсяошибка сборки brotliurllib3 brotlicffi ставится
curl_cffi0.16.3abi3ставитсяставится
playwright1.64.0не зависит от версииставитсяставитсябраузеры не проверялись
lxml6.1.3даставитсяставится
beautifulsoup44.15.0чистый Pythonставитсяставится
parsel1.12.1чистый Pythonставитсяставится
selectolax1.0.0даставитсяставится1.0: selectolax.parser выдал ImportError, используйте selectolax.lexbor
pandas3.0.6 + numpy 2.5.4даставитсяставится
pydantic2.14.1 + pydantic-core 2.50.1pydantic-core: даставитсяставится
orjson3.13.0даставитсяставится
tenacity9.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:

code
  × 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 падает на том же пакете и показывает цепочку зависимостей:

code
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; 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, «Python 3.15 wheels missing», открыли 9 октября, и на 16 октября ответов в нём не было. Pull request #1583 в google/brotli добавляет в 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 года). Единственной другой подсказкой была одна строка:

code
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"
code
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). В What's New in Python 3.15 сказано, что операции ввода-вывода без явной кодировки, например 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 страниц после обновления есть исправление в одну строку — 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-тесты и сырые результаты лежат в папке загрузок: lab315.py, results.csv, results.json и повторный запуск 16 октября, results-2026-10-16.json.

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

ipvolt строит прокси-инфраструктуру для разработчиков и агентов. Вступите в лист ожидания — одно письмо, когда откроется доступ.

Источники

  1. Python.org: страница выпуска Python 3.15.0
  2. What's New in Python 3.15: UTF-8 как кодировка по умолчанию
  3. PEP 686: Make UTF-8 mode default
  4. PyPI: файлы brotli 1.2.0
  5. PyPI: файлы zstandard 0.25.0
  6. PyPI: файлы zope.interface 8.6
  7. PyPI: файлы zope.interface 8.7
  8. PyPI: Scrapy 2.19.0
  9. google/brotli-wheels, issue #25: Python 3.15 wheels missing
  10. google/brotli, pull request #1583: Build and test CPython 3.15 wheels in CI
  11. Microsoft C++ Build Tools

Теги:ProxiesTroubleshooting