Parsování HTML v Javě s knihovnou Jsoup

Java Pro pokročilé Parsování HTML v Javě s knihovnou Jsoup

V tomto tutoriálu se seznámíme s knihovnou Jsoup, která se používá pro načítání, vyhledávání a manipulaci s HTML soubory. Pro práci je nutné si stáhnout (http://jsoup.org/download) .jar knihovnu a přidat ji k našemu projektu. Pro Eclipse je postup následující: pravým tlačítkem na projekt -> Build Path -> Configure Build Path -> záložka Libraries -> Add External JARs... -> vyberete knihovnu, kterou chcete přidat a potvrdíte. Z důvodu úspory místa nebudu u příkladů uvádět importy. Kompletní zdrojové kódy jsou ke stažení v .zip přiloženému k tomuto tutoriálu.

Document

public class Jsoup01 {

        public static void main(String[] args) throws IOException {
                String urlString = "http://www.seznam.cz/";
                Document doc = Jsoup.connect(urlString).get();

                System.out.println(doc.title());
                System.out.println(doc.text());
                System.out.println("=============================");

                Elements links = doc.select("a");
                for (Element link : links) {
                        System.out.println("Link: " + link);
                        System.out.println("Text: " + link.text());
                }
        }
}
Document doc = Jsoup.connect(urlString).get();

Jako parametr si vezme řetězec představující url adresu a vytvoří Jsoup Document (pošle HTTP GET request).

System.out.println(doc.title());
System.out.println(doc.text());

Získá a zobrazí titulek a text dokumentu.

Elements links = doc.select("a");

Objekt Elements představuje seznam objektů Element. Element představuje html element a skládá se z názvu tagu, atributů a potomků. Jednoduše řečeno výše uvedená část kódu vyhledá všechny tagy <a> a uloží je do seznamu.

for (Element link : links) {
        System.out.println("Link: " + link);
        System.out.println("Text: " + link.text());
}

Prochází všechny elementy v seznamu links a vypisuje je. Všimněte si, že link.text() vypíše text html elementu, kdežto link vypíše celý html element.

Connection

public class Jsoup02 {

        public static void main(String[] args) {
                String urlString = "http://forum.objectivismonline.com/?showforum=42";

                Connection con01 = Jsoup.connect(urlString);
                Document doc01 = null;
                try {
                        doc01 = con01.get();
                        System.out.println(doc01.text());
                } catch (IOException e) {
                        System.out.println("Exception: " + e);
                }

                Connection con02 = Jsoup.connect(urlString)
                                .userAgent("Mozilla")
                                .timeout(10000);
                Document doc02 = null;
                try {
                        doc02 = con02.get();
                        System.out.println(doc02.text());
                } catch (IOException e) {
                        System.out.println("Exception: " + e);
                }
        }
}
Connection con01 = Jsoup.connect(urlString);

Connection představuje rozhraní pro získání obsahu z web a naparsování tohoto obsahu do objektu typu Document.

doc01 = con01.get();

Metoda get() pošle request na server jako GET a naparsuje výsledek (vrátí objekt typu Document). Tato metoda může vyhodit několik výjimek např. MalformedURLEx­ception v případě chybné url. Také může dojít k výjimce HttpStatusException v případě, že na náš request jsme nedostali OK HTTP odpověď. Server, na který posíláme náš request, zjistí kdo jsme z user-agent header a v tomto případě se mu to co zjistí nelíbí a neodpoví nám tak, jak bychom chtěli.

Více k http naleznete na wiki.

Connection con02 = Jsoup.connect(urlString)
                .userAgent("Mozilla")
                .timeout(10000);

Connection umožňuje retězit metody, čehož jsme tady využili. Nejdříve nastavíme url, pak user-agent header a nakonec timeout v milisekundách.

doc02 = con02.get();
System.out.println(doc02.text());

Jako výsledek by se nám měl zobrazit celý text požadované stránky.

Načítání ze souboru a z řetězce

Nejdříve si vytvoříme jednoduchý HTML dokument (my_page.html)

<html>
<head>
  <title>My Page</title>
</head>
<body>
  <h1>Nadpis h1</h1>
  <div class="prvni">
    <h2>Nadpis h2</h2>
    <p>Toto je 1. odstavec <a href="http://www.devbook.cz">a toto je odkaz</a>.</p>
    <p>Toto je 2. odstavec</p>
    <p>Toto je 3. odstavec</p>
  </div>
  <div class="druhy">
    <h2>Nadpis h2</h2>
    <p>Toto je 4. odstavec</p>
    <p>Toto je 5. odstavec</p>
    <p>Toto je 6. odstavec</p>
  </div>
</body>
</html>

A následně ho načteme.

public class Jsoup03 {

        public static void main(String[] args) throws IOException {
                // načtení html ze souboru
                Document doc = null;
                File input = new File("my_page.txt");
                if (input.exists()) {
                        doc = Jsoup.parse(input, "UTF-8");
                }
                System.out.println("doc:\n" + doc);

                // načtení html z řetězce - úplné html
                String html01 = "<htm><head></head>"
                                + "<body><h2>Nadpis</h2>"
                                + "<p>Toto je první odstavec</p>"
                                + "<p>Toto je druhý odstavec</p>"
                                + "</body></html>";
                Document doc01 = Jsoup.parse(html01);
                System.out.println("\ndoc01:\n" + doc01);

                // načtení html z řetězce - neúplné html
                String html02 = "<head><body><head>"
                                + "<h2>Nadpis</h2>"
                                + "<p>Toto je první odstavec"
                                + "<p>Toto je druhý odstavec</p></body>";
                Document doc02 = Jsoup.parse(html02);
                System.out.println("\ndoc02:\n" + doc02);
                System.out.println("\ndoc02.html():\n" + doc02.html());

                // výpis html bez entit a výpis textu
                System.out.println("\ndoc02.html() - StringEscapeUtils:\n" + StringEscapeUtils.unescapeHtml4(doc02.html()));
                System.out.println("\ndoc02.text():\n" + doc02.text());
        }
}
doc = Jsoup.parse(input, "UTF-8");

Načte soubor a vytvoří z něj org.jsoup.nodes­.Document.

System.out.println("doc:\n" + doc);

Vypíše celý Document jako html.

Document doc01 = Jsoup.parse(html01);

Jako vstup můžeme metodě parse() předat též obyčejný řetězec a Jsoup se z něho pokusí udělat html dokument.

Document doc02 = Jsoup.parse(html02);

Zde jsme předali řetězec s neúplným html a Jsoup se s tím docela vypořádal. Když se podíváte do výpisu, zjistíte, že Jsoup správně doplnil chybějící html tagy. Také si ale pravděpodobně všimnete, že české znaky jsou nahrazeny entitami.

StringEscapeUtils.unescapeHtml4(doc02.html())

Pokud chceme stránky stáhnout a následně v nich vyhledávat, tak nám text plný html entit příliš nepomůže. Existuje však knihovna org.apache.com­mons.lang3.Strin­gEscapeUtils, pomocí jejíž metody unescapeHtml4 bude výstup vypadat tak, jak potřebujeme.

doc02.text()

Vypíše text bez html tagů.

Vyhledávání

public class Jsoup04 {

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

                // vyhledání a výpis všech odstavců (elementů p)
                Elements elem = doc.select("p");
                for (Element el : elem) {
                        System.out.println(el);
                }
                System.out.println();

                // výpis prvního odstavce
                Element firstParagraphElement = doc.select("p").first();
                System.out.println(firstParagraphElement);
                System.out.println(firstParagraphElement.text());

                List<Node> nodes = firstParagraphElement.childNodes();
                for (int i = 0; i < nodes.size(); i++) {
                        System.out.println("Node number " + (i + 1) + ": " + nodes.get(i));
                }
                System.out.println("Child number: " + firstParagraphElement.child(0));
                System.out.println();

                // vyhledání všech p v divu označeném třídou 'druhy'
                Element secondDivElements = doc.select("div.druhy").first();
                Elements paragraphElements = secondDivElements.select("p");
                for (Element par : paragraphElements) {
                        System.out.println(par);
                }
        }
}

V tomto příkladu jsme opět použili soubor my_page.txt

Elements elem = doc.select("p");
for (Element el : elem) {
        System.out.println(el);
}

Vyhledání a výpis všech odstavců.

Element firstParagraphElement = doc.select("p").first();

Získání prvního odstavce (elementu p).

List<Node> nodes = firstParagraphElement.childNodes();
for (int i = 0; i < nodes.size(); i++) {
        System.out.println("Node number " + (i + 1) + ": " + nodes.get(i));
}

Node je základní abstraktní třída, ze které dědí např. Element, Document, ..... Co to je to vlastně childNode daného elementu zjistíte nejlépe z výpisu.

firstParagraphElement.child(0)

Získáme potomka elementu firstParagrap­hElement na pozici nula (prvního potomka).

Element secondDivElements = doc.select("div.druhy").first();
Elements paragraphElements = secondDivElements.select("p");
for (Element par : paragraphElements) {
        System.out.println(par);
}

Vyhledávat lze též do hloubky. Zde nejdříve vyhledáme první element <div class="druhy"> a následně v tomto elementu vyhledáme všechny odstavce a ty zobrazíme.


 

Stáhnout

Staženo 163x (2.25 kB)
Aplikace je včetně zdrojových kódů v jazyce java

 

  Aktivity (1)

Článek pro vás napsal vita
Avatar
vita

Jak se ti líbí článek?
Celkem (3 hlasů) :
55555


 



 

 

Komentáře

Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zatím nikdo nevložil komentář - buď první!