En Python 3.15.0, la mayor parte de un stack de scraping se instala desde wheels ya compilados y pasó una prueba de humo. Todo lo que necesita brotli o zstandard falla en una máquina sin compilador de C, porque ninguno de los dos tiene wheel para 3.15, y eso incluye un simple pip install scrapy. La solución rápida es instalar gcc antes de pip install (solución 1, más abajo) o quedarse en Python 3.14 hasta que brotli publique wheels cp315 (solución 2).
Última comprobación: 16 de octubre de 2026, 10:09 UTC. En ese momento PyPI seguía sin wheel cp315 para brotli 1.2.0 y zstandard 0.25.0. zope.interface 8.7, publicado el 15 de octubre, ya trae wheels cp315.
| Paquete | Versión | Wheel cp315 | Con compilador | Sin compilador | Notas |
|---|---|---|---|---|---|
scrapy | 2.19.0 | Python puro; no (brotli 1.2.0) | se instala | falla al compilar brotli | exige brotli en CPython desde la 2.18.0 |
requests[socks] | 2.34.2 + PySocks 1.7.1 | Python puro | se instala | se instala | |
httpx[socks] | 0.28.1 + socksio 1.0.0 | Python puro | se instala | se instala | |
httpx[brotli] | 0.28.1 | no (brotli 1.2.0) | se instala | falla al compilar brotli | httpx brotlicffi se instala sin compilador |
httpx[zstd] | 0.28.1 | no (zstandard 0.25.0) | se instala | falla al compilar zstandard | la compilación más lenta |
aiohttp | 3.14.5 | sí | se instala | se instala | |
aiohttp[speedups] | 3.14.5 + aiodns 4.0.4 | no (Brotli 1.2.0) | se instala | falla al compilar Brotli | aiohttp aiodns brotlicffi se instala |
aiohttp-socks | 0.12.0 | Python puro | se instala | se instala | |
urllib3[brotli] | 2.8.0 | no (brotli 1.2.0) | se instala | falla al compilar brotli | urllib3 brotlicffi se instala |
curl_cffi | 0.16.3 | abi3 | se instala | se instala | |
playwright | 1.64.0 | no depende de la versión | se instala | se instala | navegadores sin probar |
lxml | 6.1.3 | sí | se instala | se instala | |
beautifulsoup4 | 4.15.0 | Python puro | se instala | se instala | |
parsel | 1.12.1 | Python puro | se instala | se instala | |
selectolax | 1.0.0 | sí | se instala | se instala | 1.0: selectolax.parser lanzó ImportError, usa selectolax.lexbor |
pandas | 3.0.6 + numpy 2.5.4 | sí | se instala | se instala | |
pydantic | 2.14.1 + pydantic-core 2.50.1 | pydantic-core: sí | se instala | se instala | |
orjson | 3.13.0 | sí | se instala | se instala | |
tenacity | 9.2.1 | Python puro | se instala | se instala |
"Con compilador" y "sin compilador" son la imagen oficial python:3.15-slim con y sin gcc, y cada paquete se instaló tanto con pip como con uv, que coincidieron en todos los casos. Un paquete de Python puro no tiene código compilado, así que no necesita wheel cp315. Cada instalación correcta pasó su prueba de humo.
pip install scrapy falla en Python 3.15: Failed building wheel for brotli
En la imagen slim, pip 26.2.1 se detiene en brotli:
× 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
╰─> brotliuv 0.13.1 falla en el mismo paquete y muestra la cadena:
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`La cadena es corta. Scrapy 2.19.0 es Python puro, pero requiere brotli>=1.2.0; implementation_name != "pypy", así que toda instalación en CPython arrastra brotli. Ese requisito llegó con Scrapy 2.18.0 (20 de agosto de 2026); la 2.17.0 no lo tenía. brotli 1.2.0, publicado el 5 de noviembre de 2025, tiene wheels para CPython 2.7 y de 3.6 a 3.14, y nada más reciente. Sin un wheel compatible, pip y uv descargan el archivo de código fuente y compilan la extensión _brotli, que necesita gcc. Lo mismo ocurre con httpx[brotli], aiohttp[speedups] y urllib3[brotli], que en CPython también piden el paquete brotli, y con httpx[zstd], que pide zstandard 0.25.0.
Solución 1: añadir un compilador a la imagen
Esta única línea, ejecutada en la imagen slim, bastó para todos los paquetes que fallaban:
apt-get update && apt-get install -y --no-install-recommends gcc libc6-devInstaló gcc 14.2.0. Después, pip install scrapy tardó 28 s en lugar de fallar, uv tardó 19 s, y el spider rastreó sus páginas de prueba, incluida una comprimida con brotli. La compilación lenta es la de zstandard: 63 s para httpx[zstd] con pip. En un Dockerfile, pon la línea antes del pip install.
Solo se probó esta línea de Debian. En Windows, el compilador que necesitan estas compilaciones viene con las C++ Build Tools de Microsoft; no probamos Windows.
Solución 2: quedarse en Python 3.14 hasta que existan los wheels
Python 3.14 tiene wheels de brotli y zstandard, así que allí el problema no existe. Para saber si brotli ya se ha puesto al día, ejecuta esto con Python 3.15:
python3 -m pip download --only-binary :all: --no-deps -d /tmp/wheel-check brotliEl 16 de octubre seguía terminando con ERROR: No matching distribution found for brotli. Cuando descargue un archivo .whl, los wheels cp315 estarán publicados y pip install scrapy funcionará sin compilador.
En el proyecto original, el issue #25 de google/brotli-wheels, "Python 3.15 wheels missing", se abrió el 9 de octubre y el 16 de octubre no tenía respuestas. El pull request #1583 de google/brotli añade un trabajo de CI que compila wheels cp315. El 16 de octubre seguía abierto sin revisión, y el único comentario era el del bot del CLA. Su descripción indica que un mantenedor aún tendría que publicar los wheels en PyPI.
¿No usas Scrapy? brotlicffi tiene wheel
brotlicffi 1.2.0.2 publica un wheel abi3 que pip instaló en 3.15. HTTPX, urllib3 y aiohttp lo aceptan en lugar de brotli, así que sin compilador estas combinaciones funcionaron y descomprimieron una respuesta en brotli:
pip install httpx brotlicffi
pip install urllib3 brotlicffi
pip install aiohttp aiodns brotlicffiLa última es aiohttp[speedups] sin el requisito Brotli. Scrapy no puede usar esta vía: en CPython exige el propio paquete brotli.
Con zstd es más fácil de lo que parece. En Python 3.14 y posteriores, urllib3 2.8.0 y aiohttp 3.14.5 descomprimen zstd con el módulo compression.zstd de la biblioteca estándar, así que ambos ofrecieron zstd y descomprimieron una respuesta en zstd sin ningún paquete adicional. Solo httpx[zstd] necesita zstandard.
No uses --only-binary a ciegas
--only-binary :all: le dice a pip que nunca compile desde el código fuente. Parece la solución obvia, y no falla:
pip install --only-binary :all: "httpx[brotli]" "aiohttp[speedups]"pip imprimió INFO: This is taking longer than usual mientras buscaba y después instaló httpx 0.18.2 (junio de 2021) y aiohttp 0.13.1 (diciembre de 2014). La única otra pista fue una línea:
WARNING: aiohttp 0.13.1 does not provide the extra 'speedups'El resolvedor retrocedió por versiones antiguas hasta encontrar unas cuyos requisitos podían cumplirse solo con wheels. uv pip install --no-build eligió las mismas dos versiones e imprimió warning: The package `aiohttp==0.13.1` does not have an extra named `speedups` .
Limitar el flag a un paquete no lo hace seguro. pip install --only-binary brotli scrapy también termina con código 0 e instala Scrapy 2.17.0, la última versión sin el requisito de brotli. uv hizo lo mismo. Ese Scrapy rastreó las páginas de prueba, pero solo ofrecía a los servidores gzip, deflate, mientras que 2.19.0 con brotli ofrecía gzip, deflate, br, zstd. Si tus spiders usan async def start(), 2.17.0 los sigue ejecutando.
Para detectar una bajada de versión silenciosa, revisa las versiones instaladas después de cada instalación:
pip list
uv pip listPara que falle de forma visible, fija la versión que quieres junto al flag:
pip install --only-binary brotli "scrapy==2.19.0"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 con la misma versión fijada se detuvo con error: No solution found when resolving dependencies. Un requirements.txt con versiones exactas para tus paquetes principales te da la misma protección en cada build.
Resuelto el 15 de octubre: zope.interface sin aceleraciones en C
Twisted, y con él Scrapy, depende de zope.interface. zope.interface 8.6 solo tiene wheels hasta CPython 3.14. El 14 de octubre, sin compilador, pip y uv lo instalaron igualmente en 3.15: su compilación pasa a Python puro cuando la extensión en C no se puede compilar. La salida de la instalación no mostró ningún error ni advertencia.
El coste se veía en la comprobación básica de interfaces. En el laboratorio, IThing.providedBy(obj) tardó 271 ns por llamada sin la extensión en C y 101 ns con ella. El laboratorio no midió qué supone eso para un rastreo completo.
zope.interface 8.7, publicado el 15 de octubre, incluye wheels cp315. El 16 de octubre, una instalación limpia sin compilador obtuvo el wheel binario 8.7 con pip y con uv, la extensión en C se importó y la misma comprobación tardó 102 ns. Un entorno virtual creado antes del 15 de octubre conserva la 8.6 en Python puro hasta que actualices zope.interface.
Para ver cuál tienes:
python -c "import zope.interface._zope_interface_coptimizations"Un ModuleNotFoundError significa la versión de respaldo en Python puro. Con el wheel 8.7, o con gcc instalado, la importación funcionó.
Otros cambios de 3.15 que importan al hacer scraping
El que más se va a notar es el modo UTF-8, ahora activado por defecto (PEP 686). What's New in Python 3.15 dice que las operaciones de E/S sin una codificación explícita, como open('flying-circus.txt'), usan ahora UTF-8 sea cual sea el entorno del sistema. En el laboratorio, con LANG=C, open() sin encoding escribió UTF-8 en 3.15; con -X utf8=0 volvió a ANSI_X3.4-1968, es decir, ASCII.
En scraping esto aparece sobre todo en las exportaciones. Un CSV o JSON escrito con open(path, "w") es ahora UTF-8 en cualquier máquina, incluidos los sistemas Windows donde 3.14 usaba la página de códigos de la configuración regional. Normalmente es lo que quieres. Si una herramienta posterior espera la codificación antigua, pasa encoding="locale" o define PYTHONUTF8=0; mejor aún, indica la codificación de forma explícita al escribir y al leer.
Si actualizas Scrapy al mismo tiempo
Pasar a Python 3.15 suele venir con un Scrapy nuevo. Desde la 2.16, Scrapy ya no llama a start_requests(): un spider que solo define ese método se abre, no envía nada y se cierra como terminado, sin ninguna advertencia. Scrapy rastrea 0 páginas después de actualizar tiene la corrección de una línea, async def start(), que es la que usó el spider de este laboratorio.
Método y límites
Registrado el 14 de octubre de 2026 en un host Ubuntu x86_64, dentro del sistema de archivos de la imagen oficial python:3.15-slim (Debian 13 trixie, digest de índice sha256:ea4f1f29…, construida el 12 de octubre de 2026), ejecutado en un espacio de nombres privado de Linux en lugar de Docker. El intérprete informó Python 3.15.0 (main, Oct 12 2026, 22:33:31) [GCC 14.2.0], con el pip 26.2.1 incluido y uv 0.13.1. La copia con compilador añadió gcc 14.2.0 con la línea de apt de arriba. La tabla sale de esas ejecuciones. El 16 de octubre se repitieron sin compilador los casos de Scrapy, --only-binary brotli y zope.interface: todo coincidió con el 14 de octubre salvo zope.interface, que ahora vino del wheel 8.7.
Cada caso tuvo un entorno virtual nuevo y ninguna caché de paquetes. Las versiones instaladas y si cada una venía de un wheel binario, de un wheel de Python puro o de una compilación local se leyeron de las etiquetas de los wheels. Las pruebas de humo usaron un http.server local que solo comprime con las codificaciones que ofrece el cliente. Playwright se instaló, pero no sus navegadores. No se usó ningún proxy.
El laboratorio no dice nada sobre macOS, Windows, ARM, imágenes basadas en musl ni builds sin GIL. PyPI cambia a diario, así que repite la comprobación de wheels antes de actuar según cualquier fila. El script, las pruebas de humo y la salida en bruto están en la carpeta de descarga: lab315.py, results.csv, results.json y la repetición del 16 de octubre, results-2026-10-16.json.
Relacionado
- Proxies en Scrapy 2.19, para autenticación, rotación y los errores de proxy que registra Scrapy.
- Proxies en aiohttp y proxies en curl_cffi, que se instalaron desde wheels en 3.15.
- Corregir "Missing dependencies for SOCKS support", el otro error de instalación de este stack.
- ¿Cuántos GB de proxies necesito?, para dimensionar el tráfico cuando el stack funcione. La compresión importa ahí: un cliente que ofrece menos codificaciones puede descargar más bytes.
ipvolt está construyendo infraestructura de proxies para desarrolladores y agentes. Únete a la lista de espera para recibir un correo cuando se abra el acceso.
Fuentes
- Python.org: página de la versión Python 3.15.0
- What's New in Python 3.15: UTF-8 como codificación por defecto
- PEP 686: Make UTF-8 mode default
- PyPI: archivos de brotli 1.2.0
- PyPI: archivos de zstandard 0.25.0
- PyPI: archivos de zope.interface 8.6
- PyPI: archivos de zope.interface 8.7
- PyPI: Scrapy 2.19.0
- google/brotli-wheels, issue #25: Python 3.15 wheels missing
- google/brotli, pull request #1583: Build and test CPython 3.15 wheels in CI
- Microsoft C++ Build Tools