Использование Java JSoup для анализа кода HTML

1- Что такое Jsoup?

Jsoup это  Java HTML Parser. Сказать по-другому,  Jsoup это библиотека использованная для анализа документа HTML. Jsoup предоставляет API для получения и манипулирования данными из URL или из файлов HTML. Использует методы похожие на DOM, CSS , JQuery чтобы получить данные и манипулировать ими.
Посмотрим пример с  Jsoup:
HelloJsoup.java
import java.io.IOException;  
import org.jsoup.Jsoup;  
import org.jsoup.nodes.Document;

public class HelloJsoup {  

   public static void main( String[] args ) throws IOException{  
       Document doc = Jsoup.connect("http://eclipse.org").get();  
       String title = doc.title();  
       System.out.println("Title : " + title);  
   }  

}

2- Библиотека Jsoup

Вы можете использовать Maven или скачать библиотеку Jsoup файла формата jar.

С maven:

<!-- http://mvnrepository.com/artifact/org.jsoup/jsoup -->

<dependency>
   <groupId>org.jsoup</groupId>
   <artifactId>jsoup</artifactId>
   <version>1.8.3</version>
</dependency>

Или можете скачать:

3- Быстро создать Maven project

OK, мы быстро создадим Maven project чтобы протестировать примеры:
Создать project JsoupTutorial:
Конвертировать в  Maven Project. Нажмите на правую кнопку мыши на project, выберите:
  • Configure/Convert to Maven Project
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <groupId>org.o7planning</groupId>
   <artifactId>JsoupTutorial</artifactId>
   <version>0.0.1-SNAPSHOT</version>

   <dependencies>

       <!-- http://mvnrepository.com/artifact/org.jsoup/jsoup -->
       <dependency>
           <groupId>org.jsoup</groupId>
           <artifactId>jsoup</artifactId>
           <version>1.8.3</version>
       </dependency>

   </dependencies>

   <build>
       <sourceDirectory>src</sourceDirectory>
       <plugins>
           <plugin>
               <artifactId>maven-compiler-plugin</artifactId>
               <version>3.3</version>
               <configuration>
                   <source>1.8</source>
                   <target>1.8</target>
               </configuration>
           </plugin>
       </plugins>
   </build>
</project>

4- Jsoup API

Jsoup включает много классов, но есть 3 самых важных класса, включает:
  • org.jsoup.Jsoup
  • org.jsoup.nodes.Document
  • org.jsoup.nodes.Element
     
  • Jsoup.java
Method Description
static Connection connect(String url) create and returns connection of URL.
static Document parse(File in, String charsetName) parses the specified charset file into document.
static Document parse(File in, String charsetName, String baseUri) parses the specified charset and baseUri file into Document.
static Document parse(String html) parses the given html code into document.
static Document parse(String html, String baseUri) parses the given html code with baseUri into Document.
static Document parse(URL url, int timeoutMillis) parses the given URL into Document.
static String clean(String bodyHtml, Whitelist whitelist) returns safe HTML from input HTML, by parsing input HTML and filtering it through a white-list of permitted tags and attributes.
  • Document.java
Methods Description
Element body()
Accessor to the document's body element.
Charset charset()
Returns the charset used in this document.
void charset(Charset charset)
Sets the charset used in this document.
Document clone()
Create a stand-alone, deep copy of this node, and all of its children.
Element createElement(String tagName)
Create a new Element, with this document's base uri.
static Document createShell(String baseUri)
Create a valid, empty shell of a document, suitable for adding more elements to.
Element head()
Accessor to the document's head element.
String location()
Get the URL this Document was parsed from.
String nodeName()
Get the node name of this node.
Document normalise()
Normalise the document.
String outerHtml()
Get the outer HTML of this node.
Document.OutputSettings outputSettings()
Get the document's current output settings.
Document outputSettings(Document.OutputSettings outputSettings)
Set the document's output settings.
Document.QuirksMode quirksMode()  
Document quirksMode(Document.QuirksMode quirksMode)   
Element text(String text)
Set the text of the body of this document.
String title()
Get the string contents of the document's title element.
void title(String title)
Set the document's title element.
boolean updateMetaCharsetElement()
Returns whether the element with charset information in this document is updated on changes through Document.charset(Charset) or not.
void updateMetaCharsetElement(boolean update)
Sets whether the element with charset information in this document is updated on changes through Document.charset(Charset) or not.
  • Element.java

5- Манипулирование документом

5.1- Создать Document из URL

GetDocumentFromURL.java
package org.o7planning.tutorial.jsoup.document;

import java.io.IOException;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;

public class GetDocumentFromURL {

  public static void main(String[] args) throws IOException {
      Document doc = Jsoup.connect("http://eclipse.org").get();
      String title = doc.title();
      System.out.println("Title : " + title);
  }

}
Запуск примера:

5.2- Создать Document из File

GetDocumentFromFile.java
package org.o7planning.tutorial.jsoup.document;

import java.io.File;
import java.io.IOException;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;

public class GetDocumentFromFile {

   public static void main(String[] args) throws IOException {
       File htmlFile = new File("C:/index.html");
       Document doc = Jsoup.parse(htmlFile, "UTF-8");
       String title = doc.title();
       System.out.println("Title : " + title);
   }

}

5.3- Создать  Document из String

GetDocumentFromString.java
package org.o7planning.tutorial.jsoup.document;

import java.io.IOException;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;

public class GetDocumentFromString {

  public static void main(String[] args) throws IOException {
      String htmlString = "<html><head><title>Simple Page</title></head>"
                         + "<body>Hello</body></html>";
      Document doc = Jsoup.parse(htmlString);
      String title = doc.title();
      System.out.println("Title : " + title);
      System.out.println("Content:\n");
      System.out.println(doc.toString());
  }

}
Запуск примера:

5.4- Парсинг фрагмента HTML

Полный документ  HTML включает  Header и  Body, иногда вам нужно сделать парсинг фрагмента HTML. И вы можете получить полный дркумент HTML включая header & body. Посмотрим пример:
ParsingBodyFragment.java
package org.o7planning.tutorial.jsoup.document;

import java.io.IOException;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;

public class ParsingBodyFragment {

  public static void main(String[] args) throws IOException {
      String htmlFragment = "<h1>Hi you!</h1><p>What is this?</p>";
      Document doc = Jsoup.parseBodyFragment(htmlFragment);
      String fullHtml = doc.html();
      System.out.println(fullHtml);
  }

}
Запуск примера:

6- Методы DOM

Jsoup имеет некоторые методы почти похожие с методами в моделе DOM (Модель парсинга документа XML)
Methods Description
Element getElementById(String id) Find an element by ID, including or under this element.
Elements getElementsByTag(String tag) Finds elements, including and recursively under this element, with the specified tag name.
Elements getElementsByClass(String className) Find elements that have this class, including or under this element.
Elements getElementsByAttribute(String key) Find elements that have a named attribute set. Case insensitive.
Elements siblingElements() Get sibling elements.
Element firstElementSibling() Gets the first element sibling of this element.
Element lastElementSibling() Gets the last element sibling of this element.
  ......
Методы получения данных на Element.
Method Description
String attr(String key) Get an attribute's value by its key.
void attr(String key, String value) Set an attribute. If the attribute already exists, it is replaced.
String id() Return The id attribute, if present, or an empty string if not.
String className() Gets the literal value of this element's "class" attribute, which may include multiple class names, space separated. (E.g. on <div class="header gray"> returns, " header gray")
Set<String> classNames() Get all of the element's class names. E.g. on element <div class="header gray">, returns a set of two elements "header", "gray". Note that modifications to this set are not pushed to the backing class attribute; use the classNames(java.util.Set) method to persist them.
String text() Gets the combined text of this element and all its children.
void text(String value) Set the text of this element.
String html() Retrieves the element's inner HTML. E.g. on a <div><p>a</p></div>, would return <p>a</p>. (Whereas Node.outerHtml() would return <div><p>a</p></div>.)
void html(String value) Set this element's inner HTML. Clears the existing HTML first.
Tag tag() Get the Tag for this element
String tagName() Get the name of the tag for this element. E.g. div
  ......
Методы манипулирования HTML:
Methods Description
Element append(String html) Add inner HTML to this element. The supplied HTML will be parsed, and each node appended to the end of the children.
Element prepend(String html) Add inner HTML into this element. The supplied HTML will be parsed, and each node prepended to the start of the element's children.
Element appendText(String text) Create and append a new TextNode to this element.
Element prependText(String text) Create and prepend a new TextNode to this element.
Element appendElement(String tagName) Create a new element by tag name, and add it as the last child.
Element prependElement(String tagName) Create a new element by tag name, and add it as the first child.
Element html(String value) Set this element's inner HTML. Clears the existing HTML first.
  ......
Например, использовать методы DOM, сделать парсинг документа HTML написать информацию тега  form.
register.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Register</title>
</head>
<body>
   <form id="registerForm" action="doRegister" method="post">
       <table>
           <tr>
               <td>User Name</td>
               <td><input type="text" name="userName" value="Tom" /></td>
           </tr>
           <tr>
               <td>Password</td>
               <td><input type="password" name="password" value="Tom001" /></td>
           </tr>
           <tr>
               <td>Email</td>
               <td><input type="email" name="email" value="theEmail@gmail.com" /></td>
           </tr>
           <tr>
               <td colspan="2"><input type="submit" name="submit" value="Submit" /></td>
           </tr>
       </table>
   </form>
</body>
</html>
ReadHtmlForm.java
package org.o7planning.tutorial.jsoup.dom;

import java.io.File;
import java.io.IOException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

public class ReadHtmlForm {
   
   public static void main(String[] args) throws IOException {
       
       Document doc = Jsoup.parse(new File("files/register.html"), "utf-8");
       
       Element form = doc.getElementById("registerForm");
       
       System.out.println("Form action = "+ form.attr("action"));

       Elements inputElements = form.getElementsByTag("input");
       
       for (Element inputElement : inputElements) {
           String key = inputElement.attr("name");
           String value = inputElement.attr("value");
           
           System.out.println(key + " =  " + value);
       }
   }
   
}
Запуск примера:
GetAllLinks.java
package org.o7planning.tutorial.jsoup.dom;

import java.io.IOException;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

public class GetAllLinks {

   public static void main(String[] args) throws IOException {

       Document doc = Jsoup.connect("http://o7planning.org").get();

       // Elements extends ArrayList<Element>.
       Elements aElements = doc.getElementsByTag("a");

       for (Element aElement : aElements) {
           String href = aElement.attr("href");
           String text = aElement.text();
           System.out.println(text);
           System.out.println("\t" + href);
       }
   }

}
Running example:

7- Методы индентичные Css, jQuery

Вы хотите найти или воспользоваться элементами используя синтаксисом похожим на CSS илиjQuery?
JSoup предоставляет вам некоторые методы для того, чтобы сделать это:
  • Element.select(String selector)
  • Elements.select(String selector)
Например:
Connection conn = Jsoup.connect("http://o7planning.org");
        
Document doc = conn.get();

// a with href
Elements links = doc.select("a[href]");

// img with src ending .png
Elements pngs = doc.select("img[src$=.png]");

// div with class=masthead
Element masthead = doc.select("div.masthead").first();

// direct a after h3
Elements resultLinks = doc.select("h3.r > a");
Элементы JSoup поддерживают синтаксис похожий на CSS (или JQuery) помогающий вам найти соответствующие элементы. Такие поддержки очень сильны. Методы выбора есть наготове в классе Document, Element или  Elements.

Обзор Selector (Селектор).

Селектор Описание
tagname Искать элементы по тегу. Например: a
ns|tag Искать элементы по тегу в пространстве имент (namespace), например fb|name значит найти элементы <fb:name>
#id Искать элементы по ID, например #logo
.class: Искать элементы по названию класса, например .masthead
[attribute] Элементы с атрибутами, например [href]
[^attr] Элементы с атрибутами с приставкой, например [^data-] искать элементы с атрибутами начинающимися на data-
[attr=value] Элементы со значениями атрибута, например [width=500] (Можно использовать ковычки)
[attr^=value], [attr$=value], [attr*=value] Элементы со значениями атрибута, начинающиеся, заканчивающиеся, или содержащие значение, например [href*=/path/]
[attr~=regex] Элементы со значениями совпадающими с регулярным выражением, например img[src~=(?i)\.(png|jpe?g)]
* Все элементы, например *

Комбинации Selector 

Selector Описание
el#id Элементы с ID, например div#logo
el.class Элементы с классом, например div.masthead
el[attr] Элементы с атрибутом, например a[href]
Kết hợp bất kỳ например a[href].highlight
ancestor child (Родительский элемент - наследованный элемент) Подэлементы родительского элемента, например . .body p ищет элемент p везде под блоком с классом "body"
parent > child Прямые элементы наследники родительского элемента, например div.content > p найти элементы p которые являются прямыми наследниками div имеющие class ='content'; и body > * найти прямые подэлементы тега body
siblingA + siblingB Найти элементы братья B сразу перед элементом A, например div.head + div
siblingA ~ siblingX Найти элементы братья X перед элементом A, например h1 ~ p
el, el, el Группа с разными Selector, ищет элементы подходящие к одному из Selector; например div.masthead, div.logo

Pseudo selectors

Selector Описание
:lt(n) Поиск элементов с родственным индексом (местоположение в дереве DOM связь с родтельским элементом) меньше n; например td:lt(3)
:gt(n) Поиск элементов с родственным индексом больше n, например div p:gt(2)
:eq(n) Поиск элементов с родственным индексом равным n; e.g. form input:eq(1)
:has(seletor) Поиск элементов содержащих элементы совпадающие с selector; например div:has(p)
:not(selector) Поиск элементов несовпадающих с selector; например div:not(.logo)
:contains(text) Поиск элементов содержащих данный текст. Поиск не отличая заглавные или строчные буквы, например p:contains(jsoup)
:containsOwn(text) Поиск элементов которые напрямую содержат данный текст
:matches(regex) Поиск элементов где текст не совпадает с определенным обычным выражением; например div:matches((?i)login)
:matchesOwn(regex) Поиск элементов где текст совпадает с определенным обычным выражением.
Примечение: Способ индекса pseudo начинается с 0, первый элемент имеет индекс 0, второй элемент имеет индекс 1,..
QueryLinks.java
package org.o7planning.tutorial.jsoup.selector;

import java.io.IOException;
import java.util.Iterator;

import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

public class QueryLinks {

    public static void main(String[] args) throws IOException {
        Connection conn = Jsoup.connect("http://o7planning.org");
        
        Document doc = conn.get();
        
        // Query <a> elements, href contain /document/
        String cssQuery = "a[href*=/document/]";
        Elements elements=    doc.select(cssQuery);
        
        Iterator<Element> iterator = elements.iterator();
        
        while(iterator.hasNext())  {
            Element e = iterator.next();
            System.out.println(e.attr("href"));
        }
        
    }

}
Результаты запуска примера:
document.html
<html>
<head>
 <title>Jsoup Example</title>
</head>
<body>
 <h1>Java Tutorial For Beginners</h1>
 <br>
 <div id="content">
   Content ....
 </div>

 <div class="related-container">
    <h3>Related Documents</h3>
    <a href="http://o7planning.org/web/fe/default/en/document/649342/guide-to-installing-and-configuring-eclipse">
       Guide to Installing and Configuring Eclipse
    </a>
    <a href="http://o7planning.org/web/fe/default/en/document/649326/guide-to-installing-and-configuring-java">
       Guide to Installing and Configuring Java  
    </a>
    <a href="http://o7planning.org/web/fe/default/en/document/245310/jdk-javadoc-in-chm-format">
       Jdk Javadoc in chm format
    </a>
   
 </div>

</body>
</html>
SelectorDemo1.java
package org.o7planning.tutorial.jsoup.selector;

import java.io.File;
import java.io.IOException;
import java.util.Iterator;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

public class SelectorDemo1 {

    public static void main(String[] args) throws IOException {
        File htmlFile = new File("document.html");
        Document doc = Jsoup.parse(htmlFile, "UTF-8");

        // First <div> element has class ="related-container"
        Element div = doc.select("div.related-container").first();

        // List the <h3>, the direct child elements of the current element.
        Elements h3Elements = div.select("> h3");

        // Get first <h3> element
        Element h3 = h3Elements.first();

        System.out.println(h3.text());

        // List <a> elements, is a descendant of the current element
        Elements aElements = div.select("a");

       
        // Query the current element list.
        // The element that href contains 'installing'.
        Elements aEclipses = aElements.select("[href*=Installing]");

        Iterator<Element> iterator = aEclipses.iterator();

        while (iterator.hasNext()) {
            Element a = iterator.next();
            System.out.println("Document: "+ a.text());
        }
    }

}
Результаты запуска примера: