Raspado web con Java: Jsoup, Playwright y flujos de trabajo con navegadores en la nube
Expert in Web Scraping Technologies
TL;DR:
- Jsoup analiza el HTML que se le proporciona. No ejecuta el JavaScript de la página para crear registros faltantes.
- Playwright Java proporciona una ruta de adquisición mediante navegador. El HTML renderizado puede alimentar el mismo contrato de extracción de Jsoup usado para una página estática.
- Agent Browser traslada la ejecución del navegador a la nube. Java sigue controlando los selectores, la validación de registros, el alcance de la paginación y la exportación.
- Un archivo CSV solo es útil cuando sus registros identifican la fuente prevista. Conserva IDs de registro estables y URLs resueltas, y rechaza los campos obligatorios ausentes.
El web scraping en Java comienza con una pregunta práctica: ¿el HTML del servidor ya contiene los registros, o es necesario que un navegador los cree? Elegir correctamente la ruta de adquisición evita escribir un selector para un documento que nunca contuvo los datos.
Este flujo de trabajo utiliza Jsoup para la extracción y Playwright Java para la adquisición de páginas renderizadas. Ambos caminos producen el mismo formato de registro. Una conexión dedicada de Scrapeless Agent Browser es la opción en la nube cuando la carga de trabajo del navegador debe ejecutarse fuera del host de tu aplicación.
Los ejemplos se dirigen a un listado de artículos controlado con atributos estables. Cambia ese contrato solo después de inspeccionar tu fuente permitida. La compilación de Java y la ejecución del navegador requieren el runtime y las credenciales que se listan a continuación; en esta guía no se afirma realizar captura Java en vivo.
Elige Jsoup o un Navegador a Partir del Contenido Real de la Página
Elige Jsoup cuando los registros requeridos estén presentes en el HTML recuperado. Elige un navegador cuando la página permitida requiera JavaScript o interacción antes de que esos registros existan.
| Ruta | HTML suministrado al parser | Tarea inicial adecuada | Responsabilidad que conservas |
|---|---|---|---|
| Fetch HTTP con Jsoup | Documento devuelto por el servidor | Listado estático de artículos o catálogo | Inspección de la fuente y extracción |
| Playwright Java local | Documento renderizado por el navegador | Desarrollo controlado de páginas dinámicas | Runtime de navegador y gestión de recursos |
| Agent Browser con Playwright Java | Documento de navegador en la nube | Flujo de trabajo dedicado con navegador remoto | Ciclo de vida de la conexión, selectores y comprobaciones de salida |
No elijas la ruta en función del framework usado para construir el sitio. Una aplicación JavaScript puede servir HTML útil, mientras que un listado aparentemente simple puede insertar registros después de la carga. Inspecciona la página específica y los campos requeridos.
Semántica de representación HTTP describe la respuesta que recibe un cliente. El estado de la página producido posteriormente por un navegador es una observación de adquisición diferente.
Prerrequisitos y Dependencias
Este proyecto necesita un JDK y Maven, además de las dependencias de Jsoup y Playwright Java. El proyecto mostrado se dirige a JDK 17; fija Jsoup 1.23.2 y Playwright 1.63.0 en lugar de reutilizar versiones de un tutorial antiguo.
Para el renderizado local, instala el runtime de navegador requerido por tu versión de Playwright en tu propio entorno de proyecto. Para el renderizado remoto, obtén una conexión dedicada de Agent Browser mediante la configuración actual de la cuenta y conserva su endpoint completo en SCRAPELESS_CDP_URL.
El destino debe ser público o estar autorizado de otro modo. TARGET_URL es una URL de listado de artículos permitida cuya estructura ya has inspeccionado. El contrato de selectores del ejemplo es main article[data-id], con un encabezado y un enlace dentro de cada artículo.
Nota: La herramienta de Java, la instalación de dependencias y el runtime de navegador son prerrequisitos de ejecución. Los fragmentos se contrastaron con las interfaces actuales de las librerías, pero no se compilaron ni ejecutaron en el entorno de verificación disponible. La ruta remota también requiere una conexión real dedicada de Scrapeless.
Guarda esta configuración de Maven como pom.xml y la clase siguiente como src/main/java/ArticleCollector.java:
xml
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>example</groupId>
<artifactId>article-collector</artifactId>
<version>1.0.0</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.23.2</version>
</dependency>
<dependency>
<groupId>com.microsoft.playwright</groupId>
<artifactId>playwright</artifactId>
<version>1.63.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
</plugin>
</plugins>
</build>
</project>
Conserva en este proyecto el target del compilador y las versiones de las dependencias para que otro entorno pueda reproducir la configuración antes de habilitar cualquier tarea de recolección.
Configura un Único Contrato de Extracción para Ambas Rutas
El contrato de extracción define un registro de artículo aceptado independientemente del transporte. Este ejemplo requiere un data-id no vacío, un encabezado h2 y un enlace que se resuelva a una URL HTTP o HTTPS.
Estos son atributos de un ejemplo controlado, no afirmaciones sobre los selectores actuales de un sitio público. Para tu fuente, prefiere atributos de registro estables o patrones de URL duraderos cuando estén disponibles. No reutilices una clase decorativa solo porque coincidió en una captura.
Mantén separados los campos obligatorios y opcionales. Un identificador ausente hace que se rechace el registro del ejemplo. Un resumen opcional puede seguir ausente sin cambiar la identidad del registro. Haz explícita esa política antes de exportar.
Implementación Básica: Obtener, Extraer y Exportar
La clase siguiente adquiere HTML mediante la ruta seleccionada, extrae registros de artículos con Jsoup y escribe un archivo CSV en UTF-8. Su rama remota utiliza un endpoint CDP proporcionado por la cuenta en lugar de inventar un método Java del SDK de Scrapeless.
Nota: Este ejemplo completo de Java requiere las dependencias fijadas, JDK, configuración de Maven y un destino permitido. La rama
localnecesita un entorno de ejecución de navegador; la ramaremotenecesitaSCRAPELESS_CDP_URL. Ninguna salida mostrada a continuación se presenta como una captura de ejecución en vivo.
java
import com.microsoft.playwright.*;
import com.microsoft.playwright.options.WaitUntilState;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.net.URI;
public class ArticleCollector {
private static String csv(String value) {
return "\"" + value.replace("\"", "\"\"") + "\"";
}
public static void main(String[] args) throws Exception {
if (args.length != 2) throw new IllegalArgumentException("mode and URL required");
String mode = args[0];
String target = args[1];
Document doc;
if (mode.equals("static")) {
doc = Jsoup.connect(target).get();
} else {
if (!mode.equals("local") && !mode.equals("remote"))
throw new IllegalArgumentException("Unsupported acquisition mode");
try (Playwright playwright = Playwright.create()) {
String endpoint = System.getenv("SCRAPELESS_CDP_URL");
if (mode.equals("remote") && (endpoint == null || endpoint.isBlank()))
throw new IllegalArgumentException("Dedicated CDP endpoint required");
Browser browser = mode.equals("remote")
? playwright.chromium().connectOverCDP(endpoint)
: playwright.chromium().launch();
try {
Page page = browser.newPage();
page.navigate(target, new Page.NavigateOptions()
.setWaitUntil(WaitUntilState.DOMCONTENTLOADED));
page.locator("main article[data-id] a[href]").first().waitFor();
doc = Jsoup.parse(page.content(), page.url());
} finally {
browser.close();
}
}
}
StringBuilder output = new StringBuilder("id,title,url\r\n");
int accepted = 0;
for (Element article : doc.select("main article[data-id]")) {
Element heading = article.selectFirst("h2");
Element link = article.selectFirst("a[href]");
String id = article.attr("data-id").strip();
if (id.isEmpty() || heading == null || link == null) continue;
String title = heading.text().strip();
String url = link.attr("abs:href");
URI resolved = URI.create(url);
if (title.isEmpty() || resolved.getHost() == null ||
!("https".equals(resolved.getScheme()) || "http".equals(resolved.getScheme())))
continue;
output.append(csv(id)).append(',').append(csv(title)).append(',')
.append(csv(url)).append("\r\n");
accepted++;
}
if (accepted == 0) throw new IllegalStateException("Content contract not satisfied");
Files.writeString(Path.of("articles.csv"), output, StandardCharsets.UTF_8);
System.out.println("Accepted article records: " + accepted);
}
}
Compila el proyecto y copia sus dependencias con Maven, luego ejecuta ArticleCollector usando un classpath que contenga target/classes y el directorio de dependencias. Selecciona static, local o remote y proporciona la URL de destino inspeccionada.
Nota: Estos comandos de shell POSIX requieren la cadena de herramientas de Java y las dependencias anteriores. Establece
TARGET_URLcomo la fuente permitida. La compilación y la recolección siguen siendo requisitos previos de ejecución para este ejemplo.
bash
mvn -q dependency:copy-dependencies compile
java -cp 'target/classes:target/dependency/*' ArticleCollector static "$TARGET_URL"
Usa un punto y coma como separador de classpath en un entorno Windows. Elige el modo local o remote solo después de completar su configuración de entorno de ejecución de navegador o de sesión dedicada.
El código usa abs:href para que un enlace relativo se interprete con respecto a la URL base del documento capturado. La resolución de URI relativos explica por qué una ruta por sí sola no es una identidad de origen completa. Conserva la URL de la página adquirida por separado de cada URL de artículo descubierta en el manifiesto de captura de tu aplicación.
Renderizar una página dinámica con Playwright Java
La ruta de navegador espera un elemento específico de la tarea antes de recopilar el HTML de la página. domcontentloaded es el hito de navegación; el localizador de artículos establece la condición separada de que los registros del ejemplo estén presentes.
No trates ninguna de las dos condiciones como prueba de que todos los registros han llegado. Un listado puede cargar más filas solo después de una acción explícita. Verifica si el primer lote está completo para la tarea solicitada antes de aceptarlo.
Los métodos de conexión del navegador Playwright distinguen su protocolo nativo de CDP. Una conexión CDP es para navegadores basados en Chromium y tiene capacidades diferentes de una conexión de protocolo nativo de Playwright.
Mantén los tiempos de espera y las condiciones de disponibilidad de la fuente en la configuración del proyecto al desarrollar un recolector real. Un marcador visible específico de la fuente es más útil que esperar a que el tráfico analítico no relacionado quede inactivo.
Comienza a hacer scraping con Scrapeless
Impulsa tu flujo de trabajo de automatización y web scraping con Scrapeless.
Regístrate hoy y obtén 5 USD de crédito gratis, sin necesidad de tarjeta de crédito.Reclama tu crédito gratuito ahora en el Panel de Scrapeless.
Dónde se detienen los scrapers locales de Java
Un analizador local de Java no puede suministrar contenido renderizado faltante, y un navegador local no elimina la necesidad de gestionar los recursos del navegador y el estado de adquisición. Esos límites determinan cuándo el flujo de trabajo necesita un navegador en la nube.
Scrapeless Agent Browser proporciona la capa de navegador remoto para este flujo de trabajo en Java. Obtén una conexión dedicada a través de la configuración de Agent Browser Playwright, luego pasa el endpoint de conexión completo a la rama remote.
La URL de conexión puede contener credenciales. Consérvala en el entorno de ejecución, no la registres en logs y cierra solo la sesión dedicada asignada para este trabajo. Conectarse a un navegador compartido y cerrarlo afectaría a otros trabajos que usan esa sesión.
La ruta en la nube cambia dónde se realiza la adquisición. Mantiene el mismo análisis de HTML y validación de registros en Java. Un documento de desafío o un estado de página incorrecto aún deberían incumplir el contrato de contenido en lugar de producir una exportación correcta.
Descubrir enlaces y paginación acotada
La paginación debe seguir el contrato de navegación inspeccionado de la fuente y un alcance de colección acotado. Descubre una URL de página siguiente o una interacción permitida a partir de la fuente real en lugar de adivinar un parámetro de número de página.
Conserva la identidad de la página actual, el siguiente enlace descubierto y el conjunto de páginas visitadas. Confirma que el enlace pertenezca al alcance de fuente aprobado antes de navegar. Detente cuando se alcance el presupuesto de páginas de la tarea, aparezca una URL repetida o la fuente establezca que no existe más página.
La ausencia de un enlace siguiente puede significar que el listado terminó o que la fuente no logró renderizar su navegación. Usa el contenido de la página y la evidencia de estado vacío para distinguir esos resultados. La clase de página única anterior deja deliberadamente esa decisión a la aplicación en lugar de implicar un bucle de paginación universal.
Exportar y validar los registros
El paso de exportación debe preservar la identidad de los registros aceptados y codificar correctamente el formato elegido. Las reglas de entrecomillado de campos CSV contemplan el manejo de delimitadores y comillas; el ejemplo duplica las comillas insertadas y pone cada campo entre comillas.
La sintaxis CSV es independiente de la validación del contenido. Vuelve a abrir la salida con el analizador previsto aguas abajo y revisa los campos obligatorios, los identificadores únicos y los enlaces de origen. Usa una política de importación de hojas de cálculo que mantenga el texto no confiable como datos cuando un libro de trabajo sea el consumidor.
El encabezado CSV describe el contrato: id, title y url. Este es un ejemplo de esquema normativo, no un conjunto de datos capturado. Una fuente sin registros coincidentes hace que el ejemplo se detenga; no etiqueta silenciosamente ese resultado como un listado vacío válido.
Solucionar problemas en el límite de adquisición
Los registros faltantes deben diagnosticarse en función del documento adquirido y el contrato de extracción. Un CSV vacío por sí solo no identifica la causa.
| Síntoma | Inspeccionar | Acción de ingeniería probable |
|---|---|---|
| El HTML estático carece de los registros requeridos | Respuesta sin procesar y preparación de la fuente | Seleccionar la ruta de navegador permitida |
| El navegador muestra contenido no relacionado | Página final y estado de la página | Corregir la URL inicial o la interacción |
| Algunos registros carecen de ID o títulos | Marcado de origen y campos requeridos | Actualizar o acotar el contrato |
| Los enlaces relativos se exportan de forma incorrecta | URL base capturada y atributos de enlace | Resolver los enlaces con el documento correcto |
| No se puede establecer la conexión remota | Tipo de endpoint y sesión dedicada | Corregir la configuración de cuenta y conexión |
El flujo de trabajo existente de Java centrado en Jsoup cubre el enfoque de adquisición orientado al analizador. Este artículo agrega un contrato compartido para navegador estático, navegador local y navegador en la nube sin reemplazar esa página publicada.
Conclusión
El web scraping en Java funciona mejor cuando la adquisición y la extracción son decisiones separadas. Usa Jsoup para el documento que realmente tienes, obtén HTML renderizado cuando la fuente lo requiera y valida el mismo contrato de registro antes de la exportación.
Completa la cadena de herramientas y los requisitos de sesión dedicada, prueba una sola página permitida y luego agrega paginación específica de la fuente con un alcance acotado.
¿Listo para conectar un recolector Java a un navegador en la nube?
Construye la ruta de navegador con Scrapeless y evalúa sus necesidades de recursos frente a los precios actuales. Comenta dudas sobre el flujo de trabajo en Java en Telegram.
Preguntas frecuentes
P: ¿Puede Jsoup ejecutar el JavaScript de un sitio web?
Jsoup analiza el HTML suministrado y no ejecuta el JavaScript de la página. Usa una ruta de adquisición mediante navegador cuando los registros requeridos solo existan después del renderizado.
P: ¿Se permite hacer web scraping en Java sobre cualquier página pública?
La visibilidad pública no establece el permiso para toda colección o uso. Revisa las condiciones de la fuente, las reglas de exclusión de robots, los requisitos aplicables y la autorización del proyecto antes de recopilar.
P: ¿Este flujo de trabajo en Java requiere un proxy independiente?
Un cliente de navegador estático o local necesita cualquier enrutamiento permitido que exija su fuente. La ruta en la nube usa la configuración asignada del Agent Browser; configura su salida según la configuración actual de la cuenta.
P: ¿Qué debe hacer el recolector con un documento de desafío o de acceso denegado?
El recolector debe rechazar el contenido inadecuado y preservar el motivo de la adquisición. Una conexión de navegador en la nube no reemplaza la verificación del contenido de origen.
P: ¿Por qué puede el mismo selector no devolver filas después de una actualización de la página?
La fuente puede haber cambiado el marcado, el comportamiento de renderizado o la identidad de la página. Reinspecciona esas observaciones y la URL final antes de cambiar el selector o aceptar un resultado vacío.
P: ¿Cuánta concurrencia debería usar un piloto en Java?
Usa un piloto acotado con un límite conservador por host, como tres workers para la política de este ejemplo. Las reglas de recolección de la fuente y el uso de recursos observado rigen la ampliación.
P: ¿Puede este recolector ejecutarse sin un agente de IA o junto con Selenium?
El flujo de trabajo en Java puede ejecutarse como código determinista sin un agente de IA. Un proyecto Selenium existente puede mantener su capa de adquisición mediante navegador y enviar el HTML capturado al mismo contrato de validación y exportación.
En Scrapeless, solo accedemos a datos disponibles públicamente y cumplimos estrictamente con las leyes, regulaciones y políticas de privacidad del sitio web aplicables. El contenido de este blog es sólo para fines de demostración y no implica ninguna actividad ilegal o infractora. No ofrecemos garantías y renunciamos a toda responsabilidad por el uso de la información de este blog o enlaces de terceros. Antes de realizar cualquier actividad de scraping, consulte a su asesor legal y revise los términos de servicio del sitio web de destino u obtenga los permisos necesarios.



