JSoup: Análise de HTML em Java
Mihai Maxim em Jan 31 2023

Apresentação do JSoup
O Web scraping pode ser considerado como uma caça ao tesouro digital. Percorre-se um sítio Web e extrai-se toda a informação de que se necessita. É uma técnica que é utilizada para todo o tipo de coisas, como encontrar os preços mais baratos, analisar o sentimento dos clientes ou recolher dados para investigação.
O Java é considerado uma óptima linguagem de programação para a recolha de dados da Web porque tem uma grande variedade de bibliotecas e estruturas que podem ajudar no processo. Uma das bibliotecas mais conhecidas para a recolha de dados da Web em Java é a JSoup. A JSoup permite-lhe navegar e pesquisar no HTML de um sítio Web e extrair todos os dados de que necessita.
Combinando Java com JSoup, é possível criar aplicativos incríveis de raspagem da web que podem extrair dados de sites de forma rápida e fácil. Neste artigo, vou mostrar-lhe as noções básicas de web scraping com o JSoup.
Configurar um projeto JSoup
Nesta secção, vamos criar um novo projeto Java com o Maven e configurá-lo para ser executado a partir da linha de comandos utilizando o plug-in exec-maven. Isso permitirá que você empacote e execute facilmente seu projeto em um servidor, permitindo a automação e a escalabilidade do processo de extração de dados. Depois disso, instalaremos a biblioteca JSoup.
Criar um projeto Maven
O Maven é uma ferramenta de automatização de construção para projectos Java. Gere dependências, compilações e documentação, facilitando a gestão de projectos Java complexos. Com o Maven, pode gerir e organizar facilmente o processo de construção, as dependências e a documentação do seu projeto. Também permite uma fácil integração com ferramentas e estruturas.
A instalação do Maven é um processo simples que pode ser efectuado em poucos passos.
Primeiro, transfira a versão mais recente do Maven do sítio Web oficial(https://maven.apache.org/download.cgi).
Quando a transferência estiver concluída, extraia o conteúdo do arquivo para um diretório à sua escolha.
De seguida, é necessário configurar as variáveis de ambiente.
No Windows, defina a variável JAVA_HOME para a localização do seu JDK e adicione a pasta bin da instalação do Maven à variável PATH.
No Linux/macOS, terá de adicionar as seguintes linhas ao seu ficheiro ~/.bashrc ou ~/.bash_profile:
export JAVA_HOME=caminho/para/o/jdk
export PATH=$PATH:caminho/para/maven/bin
Confirme a instalação do Maven executando mvn --version num terminal.
Com o Maven instalado, pode agora criar um novo projeto Java Maven:
mvn archetype:generate -DgroupId=com.project.scraper
-DartifactId=jsoup-scraper-project
-DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
Isto cria uma nova pasta chamada "jsoup-scraper-project" que contém o conteúdo do projeto.
O ponto de entrada para a aplicação (a classe principal) estará no pacote "com.project.scraper".
Executar o projeto a partir da linha de comandos
Para executar um projeto Java Maven a partir da linha de comandos, vamos utilizar o exec-maven-plugin.
To install the plugin, you need to add it to the project's pom.xml file. This can be done by adding the following code snippet to the <build><plugins> section of the pom.xml file:
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>com.project.scraper.App</mainClass>
</configuration>
</plugin>
</plugins>
</build>
Certifique-se de que seleciona o caminho correto para a classe principal do projeto.
Utilize mvn package exec:java no terminal (no diretório do projeto) para executar o projeto.
Instalar a biblioteca JSoup
Para instalar a biblioteca JSoup, adicione a seguinte dependência ao ficheiro pom.xml do seu projeto:
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.14.3</version>
</dependency>
Visite https://mvnrepository.com/artifact/org.jsoup/jsoup para verificar a versão mais recente.
Analisando HTML em Java com JSoup
Nesta secção, vamos explorar o Web site https://www.scrapethissite.com/pages/forms/ e ver como podemos extrair as informações sobre as equipas de hóquei. Ao examinar um Web site do mundo real, compreenderá os conceitos e as técnicas utilizadas na recolha de dados da Web com o JSoup e como pode aplicá-los aos seus próprios projectos.
Obtenção do HTML
Para obter o HTML do sítio Web, é necessário efetuar um pedido HTTP ao mesmo. No JSoup, o método connect() é utilizado para criar uma ligação a um URL especificado. Devolve um objeto Connection, que pode ser utilizado para configurar o pedido e obter a resposta do servidor.
Vejamos como podemos utilizar o método connect() para obter o HTML do nosso URL e depois escrevê-lo num ficheiro HTML local (hockey.html):
package com.project.scraper;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import java.io.*;
import java.io.IOException;
public class App
{
public static void main( String[] args )
{
String RAW_HTML;
try {
Document document = Jsoup.connect("https://www.scrapethissite.com/pages/forms/")
.get();
RAW_HTML = document.html();
FileWriter writer = new FileWriter("hockey.html");
writer.write(RAW_HTML);
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Agora podemos abrir o ficheiro e examinar a estrutura do HTML com as Ferramentas de desenvolvimento:

Os dados de que precisamos estão presentes numa tabela HTML na página. Agora que acedemos à página, podemos extrair o conteúdo da tabela utilizando selectores.
Escrever selectores
Os seletores no JSoup têm semelhanças com os seletores no JavaScript. Ambos têm uma sintaxe semelhante e permitem selecionar elementos de um documento HTML com base no seu nome de etiqueta, classe, id e propriedades CSS.
Eis alguns dos principais selectores que pode utilizar com o JSoup:
- getElementsByTag(): Seleciona elementos com base no seu nome de etiqueta.
- getElementsByClass(): Seleciona elementos com base no nome da sua classe.
- getElementById(): Seleciona um elemento com base no seu id.
- select(): Seleciona elementos com base num seletor CSS (semelhante a querySelectorAll)
Agora vamos utilizar alguns deles para extrair todos os nomes das equipas:
try {
Document document = Jsoup.connect("https://www.scrapethissite.com/pages/forms/")
.get();
Elements rows = document.getElementsByTag("tr");
for(Element row : rows) {
Elements teamName = row.getElementsByClass("name");
if(teamName.text().compareTo("") != 0)
System.out.println(teamName.text());
}
} catch (IOException e) {
e.printStackTrace();
}
// Prints the team names:
Boston Bruins
Buffalo Sabres
Calgary Flames
Chicago Blackhawks
Detroit Red Wings
Edmonton Oilers
Hartford Whalers
...
Fizemos uma iteração em cada linha e, para cada uma delas, imprimimos o nome da equipa utilizando o seletor de classe 'name'.
O último exemplo realça a flexibilidade e a capacidade de aplicar métodos de seleção várias vezes nos elementos que foram extraídos. Isto é particularmente útil quando se lida com documentos HTML complexos e grandes.
Aqui está outra versão que utiliza fluxos Java e o método select() para imprimir todos os nomes das equipas:
try {
Document document = Jsoup.connect("https://www.scrapethissite.com/pages/forms/")
.get();
Elements teamNamesElements = document.select("table .team .name");
String[] teamNames = teamNamesElements.stream()
.map(element -> element.text())
.toArray(String[]::new);
for (String teamName : teamNames) {
System.out.println(teamName);
}
} catch (IOException e) {
e.printStackTrace();
}
// Also prints the team names:
Boston Bruins
Buffalo Sabres
Calgary Flames
...
Agora vamos imprimir todos os cabeçalhos e linhas da tabela:
try {
Document document = Jsoup.connect("https://www.scrapethissite.com/pages/forms/")
.get();
Elements tableHeadersElements = document.select("table th");
Elements tableRowsElements = document.select("table .team");
String[] tableHeaders =
tableHeadersElements.stream()
.map(element -> element.text())
.toArray(String[]::new);
String[][] tableRows =
tableRowsElements.stream()
.map(
table_row -> table_row
.select("td")
.stream()
.map(row_element -> row_element.text())
.toArray(String[]::new)
)
.toArray(String[][]::new);
for (int i = 0; i < tableHeaders.length; i++) {
System.out.print(tableHeaders[i] + " ");
}
for (int i = 0; i < tableRows.length; i++) {
for (int j = 0; j < tableRows[i].length; j++) {
System.out.print(tableRows[i][j] + " ");
}
System.out.println();
}
} catch (IOException e) {
e.printStackTrace();
}
// Prints
Team Name Year Wins Losses OT Losses Win ...
Boston Bruins 1990 44 24 0.55 299 264 35
Buffalo Sabres 1990 31 30 0.388 292 278 14
Calgary Flames 1990 46 26 0.575 344 263 81
Chicago Blackhawks 1990 49 23 0.613 284 211 73
Detroit Red Wings 1990 34 38 0.425 273 298 -25
...
Repare que utilizámos streams para armazenar as rowS. Aqui está uma forma mais simples de o fazer, utilizando loops for:
String[][] tableRows = new String[tableRowsElements.size()][];
for (int i = 0; i < tableRowsElements.size(); i++) {
Element table_row = tableRowsElements.get(i);
Elements tableDataElements = table_row.select("td");
String[] rowData = new String[tableDataElements.size()];
for (int j = 0; j < tableDataElements.size(); j++) {
Element row_element = tableDataElements.get(j);
String text = row_element.text();
rowData[j] = text;
}
tableRows[i] = rowData;
}
Manuseamento da paginação
Ao extrair dados de um sítio Web, é comum que as informações estejam divididas em várias páginas. Para extrair todos os dados relevantes, é necessário fazer pedidos a cada página do sítio Web e extrair as informações de cada uma delas. Podemos facilmente implementar esta funcionalidade no nosso projeto.

Tudo o que temos de fazer é alterar o parâmetro de consulta page_num no URL e efetuar outro pedido HTTP com o método connect().
int pageLimit = 25;
String [] tableHeaders = new String[0];
Vector<String[][]> rowsGroups = new Vector<String [][]>();
for (int currentPage=1; currentPage<pageLimit; currentPage++) {
try {
Document document = Jsoup.connect("https://www.scrapethissite.com/pages/forms/?page_num=" + currentPage)
.get();
if(currentPage == 1) {
Elements tableHeadersElements = document.select("table th");
tableHeaders = tableHeadersElements.stream()
.map(element -> element.text())
.toArray(String[]::new);
}
Elements tableRowsElements = document.select("table .team");
String[][] tableRows = new String[tableRowsElements.size()][];
for (int i = 0; i < tableRowsElements.size(); i++) {
Element table_row = tableRowsElements.get(i);
Elements tableDataElements = table_row.select("td");
String[] rowData = new String[tableDataElements.size()];
for (int j = 0; j < tableDataElements.size(); j++) {
Element row_element = tableDataElements.get(j);
String text = row_element.text();
rowData[j] = text;
}
tableRows[i] = rowData;
}
rowsGroups.add(tableRows);
} catch (IOException e) {
e.printStackTrace();
}
// do something with the headers and the the table rows groups
}
Uma vez que as tabelas de cada página têm os mesmos cabeçalhos, deve certificar-se de que não as extrai várias vezes.
O código completo
Aqui está o código completo que extrai todas as tabelas do sítio Web https://www.scrapethissite.com/pages/forms/. Também incluí uma função que guarda os dados em .CSV:
package com.project.scraper;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.*;
import java.io.IOException;
import java.util.Vector;
public class App
{
public static void main( String[] args )
{
int pageLimit = 25;
String [] tableHeaders = new String[0];
Vector<String[][]> rowsGroups = new Vector<String [][]>();
for (int currentPage=1; currentPage<pageLimit; currentPage++) {
try {
Document document = Jsoup.connect("https://www.scrapethissite.com/pages/forms/?page_num=" + currentPage)
.get();
if(currentPage == 1) {
Elements tableHeadersElements = document.select("table th");
tableHeaders = tableHeadersElements.stream()
.map(element -> element.text())
.toArray(String[]::new);
}
Elements tableRowsElements = document.select("table .team");
String[][] tableRows = new String[tableRowsElements.size()][];
for (int i = 0; i < tableRowsElements.size(); i++) {
Element table_row = tableRowsElements.get(i);
Elements tableDataElements = table_row.select("td");
String[] rowData = new String[tableDataElements.size()];
for (int j = 0; j < tableDataElements.size(); j++) {
Element row_element = tableDataElements.get(j);
String text = row_element.text();
rowData[j] = text;
}
tableRows[i] = rowData;
}
rowsGroups.add(tableRows);
} catch (IOException e) {
e.printStackTrace();
}
}
writeFullTableToCSV(rowsGroups, tableHeaders, "full_table.csv");
}
public static void writeFullTableToCSV(Vector<String[][]> rowsGroups, String[] headers, String fileName) {
File file = new File(fileName);
try {
FileWriter writer = new FileWriter(file);
// write the headers first
for (int i = 0; i < headers.length; i++) {
writer.append(headers[i]);
if (i != headers.length - 1) {
writer.append(",");
}
}
writer.append("\n");
// write all the rows groups
for (String [][] rowsGroup : rowsGroups) {
for (String[] row : rowsGroup) {
for (int i = 0; i < row.length; i++) {
writer.append(row[i]);
if (i != row.length - 1) {
writer.append(",");
}
}
writer.append("\n");
}
}
writer.flush();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Concluir
Neste artigo, abordamos como instalar o Maven e criar um novo projeto Java Maven, além de como executar o projeto a partir da linha de comando. Também discutimos como instalar a biblioteca JSoup, adicionando a dependência ao arquivo pom.xml do projeto. Por fim, vimos um exemplo de como usar o JSoup para analisar HTML e extrair dados de um site. Ao seguir as etapas descritas no artigo, você deve ter uma base sólida para configurar um projeto JSoup e começar a extrair dados de sites. O JSoup oferece uma vasta gama de opções e possibilidades para a recolha de dados da Web e encorajo-o a explorá-las e a aplicá-las aos seus próprios projectos.
Como já viu, os dados são frequentemente partilhados em várias páginas Web. Fazer pedidos rápidos ao mesmo domínio pode levar a que o seu IP seja banido. Com o nosso produto, WebScrapingAPI, nunca terá de se preocupar com este tipo de problemas. A nossa API garante-lhe que pode fazer tantos pedidos quantos precisar. E a melhor parte é que pode experimentá-la gratuitamente.
Notícias e actualizações
Mantenha-se atualizado com os mais recentes guias e notícias sobre raspagem da Web, subscrevendo a nossa newsletter.
We care about the protection of your data. Read our <l>Privacy Policy</l>.Privacy Policy.

Artigos relacionados

Explore o poder transformador da recolha de dados da Web no sector financeiro. Desde dados de produtos a análises de sentimentos, este guia oferece informações sobre os vários tipos de dados da Web disponíveis para decisões de investimento.


Descubra como extrair e organizar eficientemente dados para raspagem da Web e análise de dados através de análise de dados, bibliotecas de análise de HTML e metadados schema.org.


Os selectores XPath são melhores do que os selectores CSS para a recolha de dados da Web? Conheça os pontos fortes e as limitações de cada método e faça a escolha certa para o seu projeto!
