Saltar al contenido
Empezar gratis
Volver al blog

Alternativas a PhantomJS: qué utilizar ahora y cómo realizar la migración

Sorin-Gabriel MaricaÚltima actualización el 21 min read
Alternativas a PhantomJS: qué utilizar ahora y cómo realizar la migración
En resumen: La mejor alternativa a PhantomJS depende de lo que hacía tu script antiguo, porque el desarrollo de PhantomJS se suspendió en marzo de 2018. Usa Playwright para la mayoría de los proyectos nuevos, Puppeteer para la migración más corta en Node.js si solo necesitas Chrome, y Selenium si tus pruebas ya se ejecutan en un grid de WebDriver. Si la página se renderiza en el servidor, basta con un cliente HTTP y un analizador.

La mejor alternativa a PhantomJS depende de lo que hiciera tu script anterior. Para la mayoría de los proyectos nuevos, utiliza Playwright. Si trabajas con Node.js y solo necesitas Chrome, Puppeteer es la opción más sencilla. Si tus pruebas ya se ejecutan en una red de WebDriver, cambia a Selenium con Chrome o Firefox en modo sin interfaz gráfica. Si la página se renderiza en el servidor, es posible que ni siquiera necesites un navegador. Bastará con un cliente HTTP y un analizador sintáctico.

Necesitas un sustituto porque el desarrollo de PhantomJS se suspendió en marzo de 2018 y su repositorio de GitHub ahora está archivado. Esta guía confirma las fechas, asigna cada tarea antigua a una herramienta, mapea las llamadas de PhantomJS línea por línea a Playwright y Puppeteer, y muestra cómo eliminar los paquetes sobrantes que mantienen a PhantomJS en tus compilaciones.

Puntos clave

  • El desarrollo de PhantomJS se suspendió en marzo de 2018. La última versión es la 2.1.1 (enero de 2016) y el repositorio pasó a ser de solo lectura en mayo de 2023.
  • CasperJS y Zombie.js también están archivados, por lo que no son alternativas válidas.
  • Playwright es el sustituto general más cercano, y su motor WebKit es el que más se asemeja al renderizado de PhantomJS.
  • La mayoría de las llamadas a PhantomJS tienen equivalentes directos: page.open se convierte en page.goto, y page.render se convierte en page.screenshot o page.pdf.
  • Si los datos están en el HTML inicial, un cliente HTTP es más rápido que cualquier navegador.

¿Se ha dejado de desarrollar PhantomJS?

Sí. El desarrollo de PhantomJS se suspendió en marzo de 2018, después de que su principal responsable dejara el cargo en 2017. La última versión estable es la 2.1.1, de enero de 2016, y el repositorio de GitHub se archivó como de solo lectura en mayo de 2023. Una vulnerabilidad conocida relacionada con la lectura de archivos, CVE-2019-17221, no tiene versión parcheada.

PhantomJS era un navegador sin interfaz gráfica programable, basado en QtWebKit y controlado mediante JavaScript. Ariya Hidayat lo lanzó en 2011 y, durante años, fue la forma predeterminada de extraer datos de páginas JavaScript, capturar capturas de pantalla, generar archivos PDF y ejecutar pruebas de front-end en CI sin necesidad de una pantalla. Posteriormente, Chrome incorporó su propio modo sin interfaz gráfica, y la razón para mantener una versión independiente de WebKit dejó de tener sentido.

Fecha

Evento

Fuente

Enero de 2011

Primera versión pública

Historial del proyecto (primera incorporación: diciembre de 2010)

23 de enero de 2016

Se anuncia PhantomJS 2.1. La versión 2.1.1 le sigue el 24 de enero de 2016 y sigue siendo la última versión estable

Lanzamientos en phantomjs.org, etiqueta de GitHub

Abr. de 2017

El responsable del proyecto, Vitaly Slobodin, dimite, poco después de que se lanzara Chrome sin interfaz gráfica en la versión 59 de Chrome

Lista de correo de PhantomJS

3 de marzo de 2018

La incidencia n.º 15344 anuncia «Archivado del proyecto: suspensión del desarrollo»

Incidencia en GitHub

2019

CVE-2019-17221: lectura arbitraria de archivos a través de file:// URL en page.open(), puntuación CVSS 3.1: 7,5 (Alta), sin solución

NVD

30 de mayo de 2023

Repositorio de GitHub archivado (solo lectura)

Banner del repositorio de GitHub

En la práctica, «descontinuado» significa cuatro cosas. No se lanzan parches de seguridad, por lo que el CVE anterior permanece abierto. No se incorporan nuevas funciones de la plataforma web, ya que el motor es una versión de WebKit de 2016 que no incluye años de cambios en CSS y JavaScript. Los envoltorios de npm están obsoletos. Selenium ha eliminado la compatibilidad con PhantomJS, por lo que los conjuntos de pruebas basados en él no se pueden actualizar. Los binarios antiguos siguen ejecutándose y cargando páginas sencillas, pero no reciben mantenimiento y no son seguros para páginas que no controlas.

¿Se ha dejado de desarrollar CasperJS?

Sí. El repositorio de GitHub de CasperJS se archivó en junio de 2020 y se indica que ya no se mantiene de forma activa. Su última versión, la 1.1.4-2, se lanzó en noviembre de 2017. CasperJS era una capa de scripts que se ejecutaba sobre PhantomJS o SlimerJS, por lo que no puede sustituir a PhantomJS. En su lugar, traslada los scripts de CasperJS a Playwright o Puppeteer.

Los scripts de CasperJS son una cadena de pasos de navegación, lo que facilita su portabilidad. Cada then paso se convierte en una llamada «await», y los localizadores de Playwright esperan a los elementos por sí mismos, por lo que desaparecen la mayoría de las esperas explícitas:

CasperJS

Playwright (Node)

casper.start(url) / casper.thenOpen(url)

await page.goto(url)

casper.thenClick(sel)

await page.locator(sel).click()

casper.waitForSelector(sel, fn)

await page.locator(sel).waitFor()

casper.capture('shot.png')

await page.screenshot({ path: 'shot.png' })

Zombie.js también está archivado. Su última versión, la 6.1.4, se lanzó en noviembre de 2018. Nunca fue un navegador real: simulaba un DOM dentro de Node.js, por lo que no puede renderizar páginas ni capturar capturas de pantalla. Las pruebas escritas para él se portan mejor al ejecutor de pruebas de Playwright.

SlimerJS, el proyecto basado en Gecko que compartía la API de PhantomJS, lleva años inactivo. Ninguna de estas tres herramientas tiene cabida en un nuevo proyecto.

¿Qué debería sustituir a PhantomJS?

Elige en función de lo que hiciera tu script de PhantomJS. Utiliza Playwright para el scraping, las capturas de pantalla y las pruebas entre navegadores. Utiliza Puppeteer para la automatización de Chrome solo en Node y para archivos PDF. Utiliza Selenium WebDriver si tus pruebas ya se ejecutan en una red de WebDriver. Si los datos se encuentran en el HTML inicial de la página, omite el navegador y utiliza un cliente HTTP.

La mayoría de los equipos utilizaban PhantomJS para realizar una de estas pocas tareas. Busca la tuya en la columna de la izquierda:

Qué hacía tu script de PhantomJS

Usa ahora

Por qué

Extraía datos de páginas renderizadas en JavaScript

Playwright o Puppeteer

Una versión actual de Chromium, con espera integrada, y page.evaluate funciona de la misma manera

Páginas renderizadas por el servidor extraídas

Un cliente HTTP más un analizador de HTML

No se necesita navegador, por lo que es más rápido y barato de ejecutar

Capturas de pantalla

Playwright o Puppeteer page.screenshot()

Las capturas de pantalla de página completa y de elementos están integradas

Archivos PDF generados

Puppeteer page.pdf() o Playwright page.pdf() (solo Chromium)

La función «Imprimir a PDF» sustituye a page.render('file.pdf')

Ejecución de pruebas unitarias en Karma

El lanzador sin interfaz gráfica de Chrome de Karma a corto plazo; un ejecutor de pruebas moderno a largo plazo

Karma en sí mismo está obsoleto

Se han ejecutado pruebas de Selenium a través de GhostDriver

Selenium con Chrome o Firefox sin interfaz gráfica

Selenium 4 ha eliminado la compatibilidad con PhantomJS

Se necesitaba específicamente el renderizado de WebKit

Playwright WebKit

El motor más parecido al QtWebKit de PhantomJS

Ejecutaba pruebas en Java sin un navegador real

HtmlUnit

Un navegador para Java, sin interfaz gráfica de usuario y en activo

Ninguna herramienta ha sustituido por sí sola a PhantomJS. Los navegadores modernos cuentan ahora con un auténtico modo sin interfaz gráfica, y funcionan gracias a un conjunto de bibliotecas. Por eso, es mejor tomar una decisión caso por caso para cada script que optar por una solución única para todo el equipo.

¿Qué alternativas a PhantomJS siguen manteniéndose?

Playwright, Puppeteer y Selenium se mantienen activamente y cubren casi todos los casos de uso de PhantomJS. Headless Chrome también puede ejecutarse de forma independiente desde la línea de comandos. HtmlUnit se mantiene para realizar pruebas en Java sin un navegador real. Splash sigue existiendo para los usuarios de Scrapy, pero rara vez se distribuye. CasperJS, Zombie.js y el propio PhantomJS están archivados.

Herramienta

Estado

Protocolo

Lenguajes

Motores

Ideal para

Playwright

Activo

Protocolo Chrome DevTools para Chromium; protocolos propios de Playwright para Firefox y WebKit

JavaScript/TypeScript, Python, Java, .NET

Chromium, Firefox, WebKit

La mayor parte del trabajo nuevo, pruebas entre navegadores, paridad con WebKit

Puppeteer

Activo

Protocolo Chrome DevTools; WebDriver BiDi para Firefox

JavaScript/TypeScript

Chrome, Firefox

Node.js Automatización de Chrome, archivos PDF

Selenium WebDriver

Activo

W3C WebDriver, WebDriver BiDi

Java, Python, C#, Ruby, JavaScript

Todos los principales navegadores

Conjuntos de pruebas existentes, redes de pruebas, múltiples lenguajes

Chrome sin interfaz gráfica (CLI)

Activo

Opciones de línea de comandos; Protocolo Chrome DevTools

Cualquiera (shell)

Chrome

Capturas de pantalla puntuales, archivos PDF, volcados del DOM

HtmlUnit

Activo (5.6.0, octubre de 2026)

En proceso

Java

Motor propio, sin renderizado

Pruebas en Java sin necesidad de un navegador

Splash

Poca actividad (última actualización del código en agosto de 2024)

API HTTP más scripts de Lua

Cualquiera (a través de HTTP)

Basado en WebKit

Configuraciones existentes de Scrapy

CasperJS, Zombie.js, PhantomJS

Archivado

n/a

n/a

n/a

Migrar a otra plataforma

Playwright

Playwright está mantenido por Microsoft y controla Chromium, Firefox y WebKit a través de una única API. Sus localizadores esperan a que los elementos estén vinculados, sean visibles y estén estables antes de actuar, lo que elimina la mayor parte del código de sincronización que llevaban los scripts de PhantomJS. Cada contexto de navegador está aislado, con sus propias cookies y almacenamiento, por lo que puedes ejecutar muchas sesiones en un mismo proceso del navegador. También incluye un ejecutor de pruebas con seguimiento, capturas de pantalla en caso de fallo y trabajadores en paralelo.

Para los usuarios de PhantomJS, el motor WebKit es el detalle clave. Si necesitas reproducir antiguas capturas de pantalla de PhantomJS o comprobar cómo se representa una página en un motor similar a Safari, ejecuta webkit en lugar de chromium y deja el resto del script sin cambios.

Los equipos de Python obtienen la misma API a través de pip install playwright seguido de playwright install, y los equipos de Java pueden añadir el com.microsoft.playwright paquete de Maven. Nuestra guía de extracción de datos web con Playwright abarca los selectores, la paginación y la exportación de datos, y la documentación de Playwright enumera todas las API utilizadas a continuación.

Puppeteer

Puppeteer lo mantiene el equipo de Chrome y está pensado principalmente para Node.js. Es la adaptación más sencilla desde PhantomJS JavaScript, ya que el objeto de página asíncrono y page.evaluate resulta familiar, y un script típico conserva su estructura. Gestiona bien las capturas de pantalla y la generación de PDF, y ahora controla Firefox a través de WebDriver BiDi, además de Chrome.

La diferencia fundamental entre PhantomJS y Puppeteer es el motor. Puppeteer controla una versión actual de Chrome, mientras que PhantomJS ejecuta una versión de WebKit de 2016. Las páginas que fallan en PhantomJS debido a JavaScript o CSS modernos suelen representarse correctamente en Puppeteer sin necesidad de un tratamiento especial.

Para obtener una guía completa sobre selectores, navegación y extracción de datos, lee nuestra guía sobre scraping con Puppeteer y Node.js. La documentación de Puppeteer cubre las opciones de inicio, incluido el headless: 'shell' modo que se describe a continuación.

Selenium WebDriver

Selenium implementa el estándar WebDriver del W3C, con enlaces oficiales para Java, Python, C#, Ruby y JavaScript. Es compatible con todos los navegadores principales, se escala horizontalmente a través de Selenium Grid y está incorporando WebDriver BiDi para eventos bidireccionales, como los registros de la consola y la actividad de red. A diferencia de Puppeteer, no depende del protocolo Chrome DevTools para sus comandos básicos. Es la solución natural para los equipos de Java y Ruby que utilizaban PhantomJS, así como para las suites que ejecutaban PhantomJS a través de GhostDriver.

Los enlaces de Python dejaron de admitir PhantomJS en la versión 3.8.1 y lo eliminaron en la 4.0 Alpha 6, por lo que webdriver.PhantomJS() ya no existe. Cambia a Chrome o Firefox con la opción «headless», y tus localizadores y afirmaciones seguirán funcionando. En Java, eso significa new ChromeOptions().addArguments("--headless=new").

Si estás empezando desde cero en Python, consulta nuestra guía para crear un scraper de Selenium en Python. La documentación de Selenium trata sobre los controladores, las esperas y la configuración de Grid.

Chrome sin interfaz gráfica por sí solo

Chrome se ejecuta en modo sin interfaz gráfica desde la versión 59, en 2017. Desde la versión 112, el modo sin interfaz gráfica es el mismo navegador que el Chrome habitual, pero sin ventanas visibles. La implementación anterior, independiente, sigue existiendo como un binario autónomo llamado chrome-headless-shell (desde Chrome 132), que Puppeteer expone como headless: 'shell'.

Las tareas puntuales no necesitan una biblioteca. Un único comando sustituye a un breve script de PhantomJS:

google-chrome --headless --screenshot=shot.png --window-size=1280,800 https://books.toscrape.com/
google-chrome --headless --print-to-pdf=page.pdf https://books.toscrape.com/
google-chrome --headless --dump-dom https://books.toscrape.com/ > page.html

Los parámetros están documentados en la documentación del modo sin interfaz gráfica de Chrome. Los lectores de Python pueden comparar las opciones en nuestra descripción general de los navegadores sin interfaz gráfica en Python.

HtmlUnit y Splash

HtmlUnit es un navegador sin interfaz gráfica para programas en Java. Ejecuta JavaScript, pero no renderiza píxeles, por lo que resulta adecuado para pruebas en Java que comprueban la lógica de las páginas y los formularios, no para capturas de pantalla. Se sigue actualizando activamente; la versión más reciente es la 5.6.0, de octubre de 2026.

Splash es un servicio de renderizado programable con una API HTTP y scripts en Lua, que se utiliza principalmente a través de Scrapy-Splash. Sigue funcionando para los equipos que ya lo utilizan, pero la actividad de desarrollo ha sido escasa desde 2024. Para nuevos proyectos de scraping, Playwright es la opción más segura.

Si estás comparando Puppeteer con sus propios competidores en lugar de como sustituto de PhantomJS, consulta nuestra comparación de alternativas a Puppeteer.

¿Cómo se corresponden los comandos de PhantomJS con los de Playwright y Puppeteer?

La mayoría de las llamadas de PhantomJS tienen un equivalente uno a uno tanto en Playwright como en Puppeteer, por lo que la adaptación consiste principalmente en cambiar los nombres. page.open se convierte en page.goto, page.render se convierte en page.screenshot o page.pdf, page.evaluate mantiene su nombre, y las funciones de devolución de llamada se convierten en async/await. El verdadero cambio está en las esperas. Sustituye los tiempos de espera fijos por esperas basadas en selectores o en el estado de carga.

PhantomJS

Playwright (Node.js)

Puppeteer

require('webpage').create()

const page = await browser.newPage()

const page = await browser.newPage()

page.open(url, callback)

await page.goto(url)

await page.goto(url)

page.evaluate(fn)

await page.evaluate(fn, arg)

await page.evaluate(fn, ...args)

page.render('shot.png')

await page.screenshot({ path: 'shot.png', fullPage: true })

await page.screenshot({ path: 'shot.png', fullPage: true })

page.render('doc.pdf') con page.paperSize

await page.pdf({ path: 'doc.pdf', format: 'A4' }) (solo Chromium)

await page.pdf({ path: 'doc.pdf', format: 'A4' })

page.viewportSize = { width, height }

await page.setViewportSize({ width, height })

await page.setViewport({ width, height })

page.settings.userAgent = ua

await browser.newContext({ userAgent: ua })

await page.setUserAgent({ userAgent: ua })

phantom.addCookie(cookie)

await context.addCookies([cookie])

await browser.setCookie(cookie)

page.onConsoleMessage = fn

page.on('console', (msg) => …)

page.on('console', (msg) => …)

page.onResourceRequested = fn

await page.route('**/*', (route) => …)

await page.setRequestInterception(true) además de page.on('request', …)

page.injectJs(file) / page.includeJs(url)

await page.addScriptTag({ path }) o ({ url })

await page.addScriptTag({ path }) o ({ url })

page.sendEvent('click', x, y)

await page.locator(sel).click()

await page.click(sel)

setTimeout espera / page.onLoadFinished

await page.locator(sel).waitFor() o await page.waitForLoadState()

await page.waitForSelector(sel)

--proxy=host:port opción de línea de comandos

chromium.launch({ proxy: { server: 'http://host:port' } })

puppeteer.launch({ args: ['--proxy-server=host:port'] })

system.args

process.argv

process.argv

phantom.exit()

await browser.close()

await browser.close()

Se han modificado dos filas en las últimas versiones de Puppeteer. Las cookies ahora residen en el navegador o en el contexto del navegador (browser.setCookie), ya que los métodos de cookies a nivel de página han quedado obsoletos. Además, setUserAgent toma un objeto de opciones. Los tutoriales más antiguos que llaman a page.setCookie siguen funcionando, pero muestran advertencias de obsolescencia.

Antes: un script de PhantomJS

Este script abre la tienda de práctica «Books to Scrape», lee el título de la página y los cinco primeros enlaces a libros, guarda una captura de pantalla y se cierra:

// legacy.js (PhantomJS 2.1.1): run with `phantomjs legacy.js`
var page = require('webpage').create();
var url = 'https://books.toscrape.com/';

page.viewportSize = { width: 1280, height: 800 };

page.open(url, function (status) {
  if (status !== 'success') {
    console.log('Failed to load ' + url);
    phantom.exit(1);
  }
  var data = page.evaluate(function () {
    var links = document.querySelectorAll('article.product_pod h3 a');
    return {
      title: document.title.trim(),
      books: Array.prototype.slice.call(links, 0, 5).map(function (a) {
        return { title: a.getAttribute('title'), href: a.href };
      })
    };
  });
  console.log(JSON.stringify(data, null, 2));
  page.render('books.png');
  phantom.exit();
});

Después: el mismo script en Playwright

Instala Playwright con npm install playwright y npx playwright install chromium, y a continuación ejecuta el puerto como un módulo ES:

// modern.mjs (Playwright for Node.js): run with `node modern.mjs`
import { chromium } from 'playwright';

const url = 'https://books.toscrape.com/';
const browser = await chromium.launch();
const page = await browser.newPage({ viewport: { width: 1280, height: 800 } });

try {
  await page.goto(url);
  await page.locator('article.product_pod').first().waitFor();

  const data = await page.evaluate(() => ({
    title: document.title.trim(),
    books: [...document.querySelectorAll('article.product_pod h3 a')]
      .slice(0, 5)
      .map((a) => ({ title: a.getAttribute('title'), href: a.href })),
  }));

  console.log(JSON.stringify(data, null, 2));
  await page.screenshot({ path: 'books.png', fullPage: true });
} finally {
  await browser.close();
}

Ambos scripts muestran los mismos datos:

{
  "title": "All products | Books to Scrape - Sandbox",
  "books": [
    {
      "title": "A Light in the Attic",
      "href": "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html"
    },
    {
      "title": "Tipping the Velvet",
      "href": "https://books.toscrape.com/catalogue/tipping-the-velvet_999/index.html"
    },
    {
      "title": "Soumission",
      "href": "https://books.toscrape.com/catalogue/soumission_998/index.html"
    },
    {
      "title": "Sharp Objects",
      "href": "https://books.toscrape.com/catalogue/sharp-objects_997/index.html"
    },
    {
      "title": "Sapiens: A Brief History of Humankind",
      "href": "https://books.toscrape.com/catalogue/sapiens-a-brief-history-of-humankind_996/index.html"
    }
  ]
}

La estructura apenas cambia. La llamada de retorno pasa a ser de nivel superior await, try/finally sustituye a las llamadas dispersas phantom.exit() , de modo que el navegador siempre se cierre, y una espera explícita en las fichas de productos sustituye a la esperanza de que page.open se active lo suficientemente tarde. La función que pasas a page.evaluate sigue ejecutándose dentro de la página, por lo que tu código DOM se traslada tal cual, y puedes prescindir de las soluciones alternativas de ES5 como Array.prototype.slice.call.

Para utilizar Puppeteer en su lugar, importa puppeteer, llama a puppeteer.launch(), configura la ventana gráfica con page.setViewport()y sustituye la espera del localizador por page.waitForSelector('article.product_pod'). Todo lo demás permanece igual.

¿Cómo se migra un script de PhantomJS paso a paso?

Haz un inventario de lo que hace cada script y, a continuación, elige el sustituto adecuado para cada tarea. Instala Playwright o Puppeteer y adapta las llamadas con la tabla de correspondencias. Sustituye las esperas fijas por esperas de selector y compara los resultados con capturas de pantalla o datos antiguos. Por último, elimina los binarios de PhantomJS y los paquetes envolventes de tus dependencias, imágenes de CI y archivos Dockerfile.

  1. Inventario. Busca en el código fuente phantomjs, require('webpage'), casper, GhostDriver, y karma-phantomjs-launcher. Revisa también las configuraciones de CI y los archivos Dockerfile, ya que PhantomJS suele ocultarse en un paso de compilación más que en el código de la aplicación.
  2. Clasifica cada script por tarea. Utiliza la tabla de selección rápida anterior. Una tarea de captura de pantalla y una suite de Selenium necesitan sustitutos diferentes, incluso en el mismo repositorio.
  3. Instala el sustituto. Playwright descarga sus propias compilaciones de navegador con npx playwright install, por lo que la integración continua (CI) necesita ese paso o la imagen oficial de Docker. Los equipos de Python utilizan pip install playwright y playwright install en su lugar.
  4. Adapta las llamadas. Sigue la tabla de correspondencias. Las llamadas de retorno se convierten en async/await, y las propiedades de los controladores de eventos, como page.onConsoleMessage se convierten en page.on(...) escuchas.
  5. Corrige las esperas. Esta es la fuente más habitual de diferencias tras una migración. Sustituye cada setTimeout y onLoadFinished truco por una espera del elemento o del estado de carga que realmente necesites.
  6. Compara el resultado. Compara el HTML, los datos extraídos o las capturas de pantalla con una ejecución de PhantomJS. Es de esperar que haya algunas diferencias de renderizado, ya que el nuevo motor admite fuentes, maquetación y CSS que WebKit de 2016 no admitía.
  7. Actualiza la integración continua (CI) y los contenedores. Instala las bibliotecas del sistema que necesita el nuevo navegador y elimina el binario de PhantomJS y cualquier OPENSSL_CONF solución alternativa de fontconfig que hayas añadido para él.
  8. Elimina los restos. Elimina los paquetes y lanzadores antiguos, tal y como se explica a continuación.

¿Qué sustituye a karma-phantomjs-launcher, phantomjs-prebuilt y GhostDriver?

Sustituye karma-phantomjs-launcher por el lanzador Chrome Headless de Karma y, a continuación, planifica el abandono de Karma, que ya está en desuso. Elimina phantomjs-prebuilt, que npm marca como obsoleto, y adapta sus scripts a Playwright o Puppeteer. Sustituye las sesiones de GhostDriver por los controladores de Selenium para Chrome o Firefox en modo sin interfaz gráfica, ya que Selenium 4 ha eliminado PhantomJS.

Estos restos son donde PhantomJS suele sobrevivir más tiempo, ya que se encuentran en herramientas de pruebas y automatización de navegadores que nadie toca hasta que falla una compilación.

Karma. El repositorio «karma-phantomjs-launcher» se archivó tras su última actividad en 2017. La solución rápida consiste en instalar karma-chrome-launcher y configurar browsers: ['ChromeHeadless'] en karma.conf.js. Eso mantiene la suite en verde, pero Karma es el mayor problema. El aviso de obsolescencia de Karma indica que ya no admite nuevas funcionalidades ni correcciones generales de errores. Angular ha añadido Jest y Web Test Runner como vías de migración, y cualquiera de las dos es adecuada para las pruebas unitarias que antes se ejecutaban en PhantomJS.

Paquetes de npm. phantomjs-prebuilt (última versión 2.1.16) aparece marcado en npm con «este paquete ya está obsoleto», y el antiguo phantomjs apunta a él. Ambos descargan el binario 2.1.1, que ya no recibe mantenimiento. Elimínalos con npm uninstall phantomjs-prebuilt phantomjs, y a continuación comprueba tu archivo de bloqueo, ya que otras dependencias de desarrollo a veces los incluyen.

Selenium y GhostDriver. DesiredCapabilities.PHANTOMJS y webdriver.PhantomJS() han desaparecido de Selenium 4. En Python, el cambio se realiza en tres líneas:

from selenium import webdriver

options = webdriver.ChromeOptions()
options.add_argument("--headless=new")
driver = webdriver.Chrome(options=options)

Selenium Manager busca o descarga un controlador compatible, por lo que ya no es necesario incluir un binario de GhostDriver por separado. Firefox funciona de la misma manera con FirefoxOptions y el -headless argumento.

Imágenes de Docker. Elimina cualquier apt-get install phantomjs o instalación global de PhantomJS mediante npm. Utiliza la imagen oficial de Playwright o sigue las instrucciones de Puppeteer sobre las bibliotecas del sistema que necesita Chrome en un contenedor.

¿Realmente necesitas un navegador sin interfaz gráfica?

A menudo, no. Muchos rastreadores de PhantomJS se escribieron cuando la renderización parecía más segura, pero si los datos ya están en el HTML inicial de la página o en un punto final JSON, un cliente HTTP junto con un analizador sintáctico es más rápido y sencillo. Comprueba primero el código fuente de la página y utiliza un navegador solo cuando el contenido aparezca después de que se ejecute JavaScript.

Una comprobación rápida te llevará un minuto:

  1. Abre la página y visualiza su código fuente, no el DOM inspeccionado.
  2. Busca en el código fuente el valor que quieras extraer, como un precio o el nombre de un producto.
  3. Si no está ahí, abre la pestaña «Red» en las herramientas de desarrollo de tu navegador y busca solicitudes XHR o fetch que devuelvan JSON.

Si en el paso 2 se encuentra el valor, una simple solicitud HTTP y un analizador lo obtienen en una fracción del tiempo y la memoria que necesita un navegador. Si en el paso 3 se encuentra un punto final JSON, llámalo directamente y omite también el análisis del HTML. Nuestra comparación entre Cheerio y Puppeteer muestra ambos enfoques uno al lado del otro en Node.js.

Reserva el navegador para las tareas que lo requieran: navegar por flujos, iniciar sesión, desplazamiento infinito, capturas de pantalla, archivos PDF y pruebas visuales.

¿Cuándo deberías dejar de ejecutar navegadores por tu cuenta?

Deja de alojarlos tú mismo cuando el mantenimiento del navegador cueste más de lo que valen los scripts. Las señales más comunes son los fallos y las fugas de memoria a gran escala, la divergencia de versiones del navegador en la integración continua (CI), las solicitudes bloqueadas y la necesidad de comprobar páginas desde varios países y dispositivos. Una API gestionada ejecuta el navegador y devuelve HTML, datos o capturas de pantalla a través de solicitudes HTTP simples.

Ejecutar un navegador sin interfaz gráfica es fácil. Ejecutar cientos es otra historia. Tienes que gestionar los límites de concurrencia, limpiar los procesos de Chrome que nunca se cierran, mantener sincronizadas las versiones del navegador entre los portátiles de los desarrolladores y la integración continua (CI), y lidiar con sitios web que bloquean el tráfico del centro de datos. Si necesitas ver una página tal y como la ven los visitantes de otro país, también necesitas infraestructura en ese país.

La API de navegador de WebScrapingAPI libera a tus servidores de esa carga. Envías una URL con tiempos de espera, como wait_until o wait_for_css, y acciones en la página, como hacer clic, desplazarse, escribir, seleccionar y enviar. Devuelve HTML renderizado, un DOM en formato JSON, campos extraídos o una captura de pantalla en base64. Se trata de una interfaz REST de solicitud-respuesta sin sesión de navegador en tiempo real, por lo que no es necesario integrarla con Puppeteer ni Playwright. Describes los pasos en la solicitud y recibes el resultado.

En cuanto a las tareas de capturas de pantalla y control de calidad que solía gestionar PhantomJS, nuestra solución de pruebas de sitios web en distintos mercados y dispositivos comprueba las páginas públicas por país, dispositivo y ventana de visualización, y guarda capturas de pantalla como prueba.

Si solo necesitas HTML renderizado, compara las API de acceso web para encontrar la opción más sencilla que se adapte a tus necesidades.

FAQ

¿Sigue siendo seguro utilizar PhantomJS?

No para páginas en las que no se confíe. PhantomJS no ha recibido parches de seguridad desde que se suspendió su desarrollo en 2018, y la vulnerabilidad CVE-2019-17221 permite que una página lea archivos locales page.open() sin que exista una versión parcheada. Si debes mantenerlo durante un breve periodo, ejecútalo únicamente en páginas que controles, en un contenedor aislado, mientras realizas la migración.

¿Puedo seguir instalando PhantomJS desde npm?

Puedes, pero no deberías. El phantomjs-prebuilt paquete está marcado como obsoleto en npm, y sus binarios corresponden a la versión 2.1.1, que ya no recibe mantenimiento. En los proyectos nuevos se debería instalar Playwright o Puppeteer en su lugar. Ambos descargan una versión actual del navegador y cuentan con mantenedores activos y documentación.

¿Qué es mejor para sustituir a PhantomJS: Playwright o Puppeteer?

Playwright se adapta a la mayoría de los equipos. Es compatible con Chromium, Firefox y WebKit, cuenta con enlaces para Python, Java y .NET, y espera automáticamente a que los elementos estén listos. Puppeteer es una buena opción para proyectos Node que solo necesitan Chrome, o para la generación de PDF. Ambos adaptan los scripts de PhantomJS con un esfuerzo similar, ya que page.evaluate funcionan de la misma manera.

¿Selenium sigue siendo compatible con PhantomJS?

No. Selenium dejó de recomendar PhantomJS en la versión 3.8.1 y lo eliminó en Selenium 4, por lo que webdriver.PhantomJS() las sesiones de PhantomJS y GhostDriver ya no funcionan. Cambia esas pruebas a Chrome o Firefox con la opción «headless». Tus localizadores y aserciones de WebDriver se mantienen prácticamente iguales, por lo que la adaptación suele ser mínima.

¿Qué ha sustituido a PhantomJS en Karma?

El lanzador «Chrome Headless» de Karma es el sustituto habitual de «karma-phantomjs-launcher». Sin embargo, el propio Karma ya está en desuso. Para una solución a largo plazo, traslada las pruebas unitarias a un ejecutor que se mantenga activamente, como Jest o Web Test Runner, que Angular ha añadido como rutas de migración.

¿Qué alternativa a PhantomJS utiliza WebKit?

Playwright. Incluye una versión de WebKit junto con Chromium y Firefox, lo que lo convierte en la opción de renderizado más similar al motor QtWebKit de PhantomJS. Úsalo cuando necesites reproducir capturas de pantalla antiguas de PhantomJS o probar un renderizado similar al de Safari. Para todo lo demás, Chromium es la opción predeterminada habitual.

¿Qué alternativa a PhantomJS deberías elegir?

Elige según la tarea. Utiliza Playwright para la mayoría de tareas de scraping, capturas de pantalla y pruebas entre navegadores; Puppeteer para la automatización de Chrome con Node.js y archivos PDF; y Selenium para las suites de WebDriver existentes en cualquier lenguaje. Antes de portar un scraper, comprueba si los datos ya están en el HTML, porque el navegador más rápido es aquel que no ejecutas. A continuación, elimina los binarios, los wrappers y los lanzadores de PhantomJS para que nada vuelva a incorporar el motor antiguo a tus compilaciones.

Olvídate del mantenimiento del navegador

Renderiza páginas JavaScript sin ejecutar un navegador. Envía una URL a la API de Scraper y obtén el HTML renderizado. Empieza con 5.000 solicitudes gratuitas. La renderización de JavaScript y la geolocalización no suponen ningún coste adicional, y las solicitudes fallidas no se facturan.

Explora la API de Scraper

Acerca del autor

Sorin-Gabriel Marica, Desarrollador full-stack @ WebScrapingAPI

Sorin-Gabriel Marica

Desarrollador full-stack

Sorin Marica es ingeniero Full Stack y DevOps en WebScrapingAPI, donde se encarga de desarrollar funciones para los productos y de mantener la infraestructura que garantiza el buen funcionamiento de la plataforma.

Extracción de datos web con AWS Lambda: guía para Python y Java 2026
Guías

Extracción de datos web con AWS Lambda: guía para Python y Java 2026

TL;DR: En resumen: el web scraping con AWS Lambda funciona mejor cuando cada invocación es breve, está delimitada y se puede reintentar de forma independiente. Empieza con HTTP directo, AWS SAM y S3, y añade SQS, contenedores, renderización en navegador, proxies o una capa de recuperación gestionada solo cuando la carga de trabajo demuestre que los necesita.

Suciu Dan33 min read
Leer artículo
Cómo utilizar GoSpider: rastrear, depurar URL y extraer datos
Guías

Cómo utilizar GoSpider: rastrear, depurar URL y extraer datos

TL;DR: En resumen: GoSpider es un rastreador de línea de comandos diseñado para descubrir URL, no un extractor completo de datos estructurados. Esta guía sobre cómo utilizar GoSpider muestra cómo realizar un rastreo limitado, gestionar correctamente los resultados, pasar los datos de Colly a CSV y seguir una ruta de diagnóstico para respuestas 403 o páginas que requieren renderización con JavaScript.

Suciu Dan24 min read
Leer artículo
Cómo raspar Redfin: Guía Python de Datos Inmobiliarios
Guías

Cómo raspar Redfin: Guía Python de Datos Inmobiliarios

TL;DR: Redfin expone puntos finales de API ocultos que devuelven JSON estructurado para los listados de propiedades, lo que permite omitir por completo el frágil análisis HTML. Esta guía te guía a través de la construcción de un raspador de Python que extrae datos de alquiler y venta, busca por ubicación, supervisa los nuevos listados a través de mapas de sitio XML y exporta resultados limpios a CSV o JSON.

Suciu Dan14 min read
Leer artículo

Empieza a crear

¿Estás listo para ampliar tu recopilación de datos?

Únete a más de 2000 empresas que utilizan WebScrapingAPI para extraer datos de la web a escala empresarial sin ningún gasto de infraestructura.