Analisando HTML em Java com Jsoup

Analisando HTML em Java com Jsoup

1. Visão geral

Jsoup é uma biblioteca Java de código aberto usada principalmente para extrair dados de HTML. Também permite que você manipule e produza HTML. Possui uma linha de desenvolvimento constante, ótima documentação e uma API fluente e flexível. O Jsoup também pode ser usado para analisar e criar XML.

Neste tutorial, usaremosSpring Blog para ilustrar um exercício de raspagem que demonstra vários recursos do jsoup:

  • Carregando: buscando e analisando o HTML em umDocument

  • Filtragem: selecionar os dados desejados emElementse percorrê-los

  • Extraindo: obtendo atributos, texto e HTML de nós

  • Modificando: adicionando / editando / removendo nós e editando seus atributos

2. Dependência do Maven

Para usar a biblioteca jsoup em seu projeto, adicione a dependência ao seupom.xml:


    org.jsoup
    jsoup
    1.10.2

Você pode encontrar a versão mais recente dejsoup no repositório Maven Central.

3. Jsoup em um relance

Jsoup carrega a página HTML e constrói a árvore DOM correspondente. Essa árvore funciona da mesma maneira que o DOM em um navegador, oferecendo métodos semelhantes ao jQuery e JavaScript vanilla para selecionar, percorrer, manipular texto / HTML / atributos e adicionar / remover elementos.

Se você estiver confortável com seletores do lado do cliente e travessia / manipulação de DOM, você achará o jsoup muito familiar. Verifique como é fácil imprimir os parágrafos de uma página:

Document doc = Jsoup.connect("http://example.com").get();
doc.select("p").forEach(System.out::println);

Lembre-se de que o jsoup interpreta apenas o HTML - não interpreta o JavaScript. Portanto, as alterações no DOM que normalmente ocorreriam após o carregamento da página em um navegador habilitado para JavaScript não serão vistas no jsoup.

4. Carregando

A fase de carregamento compreende a busca e análise do HTML emDocument. O Jsoup garante a análise de qualquer HTML, dos mais inválidos aos totalmente validados, como faria um navegador moderno. Isso pode ser obtido carregando umString, umInputStream, umFile ou um URL.

Vamos carregar umDocument do URL do Spring Blog:

String blogUrl = "https://spring.io/blog";
Document doc = Jsoup.connect(blogUrl).get();

Observe o métodoget, ele representa uma chamada HTTP GET. Você também pode fazer um HTTP POST com o métodopost (ou você pode usar ummethod que recebe o tipo de método HTTP como um parâmetro).

Se você precisar detectar códigos de status anormais (por exemplo, 404), você deve capturar a exceçãoHttpStatusException:

try {
   Document doc404 = Jsoup.connect("https://spring.io/will-not-be-found").get();
} catch (HttpStatusException ex) {
   //...
}

Às vezes, a conexão precisa ser um pouco mais personalizada. Jsoup.connect(…) retorna umConnection que permite definir, entre outras coisas, o agente do usuário, referenciador, tempo limite de conexão, cookies, dados de postagem e cabeçalhos:

Connection connection = Jsoup.connect(blogUrl);
connection.userAgent("Mozilla");
connection.timeout(5000);
connection.cookie("cookiename", "val234");
connection.cookie("cookiename", "val234");
connection.referrer("http://google.com");
connection.header("headersecurity", "xyz123");
Document docCustomConn = connection.get();

Como a conexão segue uma interface fluente, você pode encadear esses métodos antes de chamar o método HTTP desejado:

Document docCustomConn = Jsoup.connect(blogUrl)
  .userAgent("Mozilla")
  .timeout(5000)
  .cookie("cookiename", "val234")
  .cookie("anothercookie", "ilovejsoup")
  .referrer("http://google.com")
  .header("headersecurity", "xyz123")
  .get();

Você pode aprender mais sobre as configurações deConnection porbrowsing the corresponding Javadoc.

5. Filtragem

Agora que temos o HTML convertido emDocument, é hora de navegar e encontrar o que estamos procurando. É aqui que a semelhança com o jQuery / JavaScript é mais evidente, pois seus seletores e métodos de deslocamento são semelhantes.

5.1. Selecionando

O métodoDocumentselect recebe umString representando o seletor, usando a mesma sintaxe do seletoras in a CSS or JavaScript, e recupera a lista de correspondência deElements. Esta lista pode estar vazia, mas nãonull.

Vamos dar uma olhada em algumas seleções usando o métodoselect:

Elements links = doc.select("a");
Elements sections = doc.select("section");
Elements logo = doc.select(".spring-logo--container");
Elements pagination = doc.select("#pagination_control");
Elements divsDescendant = doc.select("header div");
Elements divsDirect = doc.select("header > div");

Você também pode usar métodos mais explícitos inspirados no DOM do navegador em vez doselect genérico:

Element pag = doc.getElementById("pagination_control");
Elements desktopOnly = doc.getElementsByClass("desktopOnly");

ComoElement é uma superclasse deDocument, você pode aprender mais sobre como trabalhar com os métodos de seleção nos JavadocsDocumenteElement.

5.2. Atravessando

Traversing means navigating across the DOM tree. Jsoup fornece métodos que operam emDocument, em um conjunto deElements, ou em umElement específico, permitindo que você navegue até os pais, irmãos ou filhos de um nó .

Além disso, você pode pular para o primeiro, o último e o enésimo (usando um índice baseado em 0)Element em um conjunto deElements:

Element firstSection = sections.first();
Element lastSection = sections.last();
Element secondSection = sections.get(2);
Elements allParents = firstSection.parents();
Element parent = firstSection.parent();
Elements children = firstSection.children();
Elements siblings = firstSection.siblingElements();

Você também pode percorrer as seleções. Na verdade, qualquer coisa do tipoElements pode ser iterado:

sections.forEach(el -> System.out.println("section: " + el));

Você pode fazer uma seleção restrita a uma seleção anterior (sub-seleção):

Elements sectionParagraphs = firstSection.select(".paragraph");

6. Extraindo

Agora sabemos como alcançar elementos específicos, então é hora de obter seu conteúdo - ou seja, seus atributos, HTML ou texto filho.

Dê uma olhada neste exemplo que seleciona o primeiro artigo do blog e obtém sua data, seu primeiro texto de seção e, finalmente, seu HTML interno e externo:

Element firstArticle = doc.select("article").first();
Element timeElement = firstArticle.select("time").first();
String dateTimeOfFirstArticle = timeElement.attr("datetime");
Element sectionDiv = firstArticle.select("section div").first();
String sectionDivText = sectionDiv.text();
String articleHtml = firstArticle.html();
String outerHtml = firstArticle.outerHtml();

Aqui estão algumas dicas a serem lembradas ao escolher e usar os seletores:

  • Confie no recurso "Visualizar fonte" do seu navegador e não apenas no DOM da página, pois pode ter sido alterado (selecionar no console do navegador pode gerar resultados diferentes dos que o jsoup)

  • Know your selectors, pois há muitos deles e é sempre bom tê-los visto antes; masterizar seletores leva tempo

  • Use a playground for selectors para experimentá-los (cole um exemplo de HTML lá)

  • Seja menos dependente das alterações na página: procure os seletores menores e menos comprometedores (por exemplo, prefira id. Sediada)

7. Modificando

A modificação abrange atributos de configuração, texto e HTML de elementos, além de anexar e remover elementos. Isso é feito na árvore DOM gerada anteriormente pelo jsoup - oDocument.

7.1. Definição de atributos e texto interno / HTML

Como no jQuery, os métodos para definir atributos, texto e HTML têm os mesmos nomes, mas também recebem o valor a ser definido:

  • attr() - define os valores de um atributo (cria o atributo se ele não existir)

  • text() - define o texto interno do elemento, substituindo o conteúdo

  • html() - define o elemento HTML interno, substituindo o conteúdo

Vejamos um exemplo rápido desses métodos:

timeElement.attr("datetime", "2016-12-16 15:19:54.3");
sectionDiv.text("foo bar");
firstArticle.select("h2").html("
");

7.2. Criando e acrescentando elementos

Para adicionar um novo elemento, você precisa criá-lo primeiro instanciandoElement. Depois que oElement foi construído, você pode anexá-lo a outroElement usando o métodoappendChild. OElement recém-criado e anexado será inserido no final do elemento ondeappendChild é chamado:

Element link = new Element(Tag.valueOf("a"), "")
  .text("Checkout this amazing website!")
  .attr("href", "http://example.com")
  .attr("target", "_blank");
firstArticle.appendChild(link);

7.3. Removendo elementos

Para remover elementos, você precisa selecioná-los primeiro e executar o métodoremove.

Por exemplo, vamos remover todas as tags<li> que contêm a classe “navbar-link” deDocument,e todas as imagens do primeiro artigo:

doc.select("li.navbar-link").remove();
firstArticle.select("img").remove();

7.4. Converter o documento modificado em HTML

Finalmente, como estávamos alterandoDocument, podemos querer verificar nosso trabalho.

Para fazer isso, podemos explorar a árvore DOMDocument selecionando, percorrendo e extraindo usando os métodos apresentados, ou podemos simplesmente extrair seu HTML comoString usando o métodohtml():

String docHtml = doc.html();

A saída deString é um HTML organizado.

8. Conclusão

Jsoup é uma ótima biblioteca para raspar qualquer página. Se você estiver usando Java e não precisar de scraping com base no navegador, é uma biblioteca a ser considerada. É familiar e fácil de usar, pois faz uso do conhecimento que você pode ter no desenvolvimento de front-end e segue boas práticas e padrões de design.

Você pode aprender mais sobre como extrair páginas da web com jsoup estudandojsoup APIe lendojsoup cookbook.

O código-fonte usado neste tutorial pode ser encontrado emGitHub project.