www.www.zaachi.com » Blog/Java » Java: Html parser

Html parser je program, který dokáže analyzovat HTML kód a dokáže jej rozebrat na jednotlivé části, tagy, a text.
Naprogramovat kvalitní HTML parser může být problém. Parser musí projít HTML dokument, tento dokument analyzovat a rozebrat. Určitě si dokážete představit jak je takový algoritmus složitý.
V javě existuje pro tuto problematiku již hotové řešení v podobě HTMLEditorKit.ParserCallback, který se nachází v javax.swing.text.
Použití ParserCallback si ukážeme nejlépe na příkladu.
Naprogramujeme si třídu ParseHtml, která bude dědit HTMLEditorKit.ParserCallback adokáže analyzovat HTML kód a informace přehledně vypsat. Dokáže vypsat:
Metody pro všechny tyto operace jsou již v ParserCallback implementovány, takže je stačí použít.
Jako první vytvoříme konstruktor, který bude obsahovat dva vstupní parametry. Url adresu, kterou chceme parsovat a kódování, ve kterém bude html dokument načten.
V konstruktoru vytvoříme public proměnné a pro URL adresu provedeme jednouduchou kontrolu:
public class ParseHtml extends HTMLEditorKit.ParserCallback {
public String url = null;
public String charset = null;
/**
*
* @param url
* @param charset
* konstruktor tridy HtmlToText
*/
public ParseHtml(String url, String charset) {
//jednoducha kontrola url adresy, jestli je ve tvaru s HTTP://
if (this.check_url(url.trim()) == 0) {
System.out.println("Url adresa neni ve spravnem tvaru. Prosim zadejte adresu ve tvaru http://");
return;
}
//nastaveni promennych
this.url = url;
this.charset = charset;
}
/**
*
* @param url
* @return
* jednoducha kontrola url adresy
*/
public int check_url(String url) {
if (url.startsWith("http://") == false)
return 0;
return 1;
}
}
Tím máme hotový základ, který pouze vytvoří proměnné a provede jednoducou kontrolu.
Co musíme uděla nyní je připojit se k dané URL adrese. Z url adresy si tedy vytvoříme proměnnou typu URL a nezbývá než vytvořit BufferedReader. Pro tuto operaci si vytvoříme novou metodu, jejíž volání přidáme do konstruktoru:
/**
* zacatek parsovani. Vytvori bufferdreader a spusti parser
*/
private void run_url() {
try {
//vytvoreni nove URL
URL url_id = new URL(this.url);
//Vytvoreni BufferedReaderu
BufferedReader htmlPage = new BufferedReader(new InputStreamReader(
url_id.openStream(), this.charset));
//spusteni parsovani
this.parse(htmlPage);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Pokud je URL adresa otevřena voláme metodu parse, do které předáme jako parametr BufferedReader. Metoda parser vypadá následovně:
/**
*
* @param htmlText
* @throws IOException
* vytvori novy ParserDelegator a vola metodu pro parsovani
*/
public void parse(Reader htmlText) throws IOException {
ParserDelegator delegator = new ParserDelegator();
delegator.parse(htmlText, this, Boolean.TRUE);
}
Vytvoříme nový ParserDelegator a začneme parsovat. Pro přístupu k jednotlivým informacím o HTML dokumentu nám slouží impmentované metody.
První z několika metod je handleText. Slouží pro odchycení textu, který se nachází mimo HTML značky. Vstupní parametry jsou zde pouze dva. Text a jeho pozice v dokumentu.
Použití může být obdobné tomuto:
/**
* @param text
* @param pos
* handleText odchiti veskery text, ktery vytvari obsah html stranky
*/
public void handleText(char[] text, int pos) {
System.out.println("Text: " + String.valueOf(text));
}
Metoda handleComment umožňuje přístup k html komentářům. Vstupní parametry jsou obdobné jako u textu, a to text komentáře a pozice v dokumentu.
Opět jednoduché použití:
/**
* @param coment
* @param pos
* handleComent odchiti html poznamky
*/
public void handleComment(char[] coment, int pos) {
System.out.println("Komentar: " + String.valueOf(coment));
}
Určitě užitečná a zajímavá metoda je handleStartTag, která dokáže informovat o začátku nového tagu a navíc dokáže odchytit i atributy, které jsou v tagu umístěny:
/**
* @param tag
* @param atr
* @param pos
* handleStartTag odchyti zacatek noveho tagu, vcetne jeho atributu
*/
public void handleStartTag(HTML.Tag tag, MutableAttributeSet atr, int pos) {
System.out.println("Zacatek tagu: "" + tag + """);
System.out.println("Tag obsahuje atributy: "" + atr + """);
}
K metodě handleStartTag musí existovat i metoda handleEndTag, která na rozdíl od první metody dokáže zjistit ukončení tagu. Vstupní parametry jsou v tomto případě pouze dva a to HTML.Tag a pozice v dokumentu:
/**
* @param tag
* @param atr
* @param pos
* handleEndTag odchyti konec tagu
*/
public void handleEndTag(HTML.Tag tag, int pos) {
System.out.println("Konec tagu: "" + tag + """);
}
Metoda handleStartTag informuje pouze o přítomnosti tagu, který je párový. Neinformuje o tagu jako je například BR, IMG, HR a podobně, které párové nejsou.
Pro tuto potřebu je zde metoda handleSimpleTag. Metoda obsahuje stejně jako handleStartTag tři parametry:
/**
* @param tag
* @param atr
* @param pos
* handleSimpleTag odchyti jednoduche html tagy jako BR, IMG, apod.
*/
public void handleSimpleTag(HTML.Tag tag, MutableAttributeSet atr, int pos) {
System.out.println("Zacatek jednoducheho tagu: "" + tag + """);
System.out.println("Tag obsahuje atributy: "" + atr + """);
}
Pokud při parsování nastane jakýkoli problém, dokáže nás o tom informovat metoda handleError. Jako parametry jsou String ve tvaru chyby a pozice v dokumentu:
/**
* @param str
* @param pos
* handleError odchyti chby v HTML
*/
public void handleError(String str, int pos) {
//System.out.println("Parse error: " + str);
}
Výstup třídy nás dokáže podrobně informovat o celé struktuře html dokumentu:
Zacatek tagu: "h3" Tag obsahuje atributy: "class=title s_win_title " Zacatek tagu: "span" Tag obsahuje atributy: "class=ico " Zacatek jednoducheho tagu: "img" Tag obsahuje atributy: "alt=Stream.cz - zábavná videa height=16 src=/favicons/194.png width=16 " Konec tagu: "span" Zacatek tagu: "span" Tag obsahuje atributy: "class=text " Zacatek tagu: "a" Tag obsahuje atributy: "href=http://www.stream.cz title=Stream.cz - zábavná videa | Aktualizováno v 13:05 " Text: Stream.cz - zábavná videa Konec tagu: "a" Konec tagu: "span"
Protože známe atributy, nebyl by problém zjistit například veškeré url adresy, které daná HTML stránka obsahuje:
public void handleStartTag(HTML.Tag tag, MutableAttributeSet a, int pos)
{
if( String.valueOf( tag ) == "a"){
if( String.valueOf( a ).startsWith("href=http://") )
System.out.println( String.valueOf( a ).substring(5) );
}
}
nebo podobným způsobem hodnoty jiných atributů.
Nakonec kód celé třídy pro parsování:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.html.HTML;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.parser.ParserDelegator;
public class ParseHtml extends HTMLEditorKit.ParserCallback {
public String url = null;
public String charset = null;
/**
*
* @param url
* @param charset
* konstruktor tridy HtmlToText
*/
public ParseHtml(String url, String charset) {
//jednoducha kontrola url adresy, jestli je ve tvaru s HTTP://
if (this.check_url(url.trim()) == 0) {
System.out.println("Url adresa neni ve spravnem tvaru. Prosim zadejte adresu ve tvaru http://");
return;
}
//nastaveni promennych
this.url = url;
this.charset = charset;
//spusteni parseru
run_url();
}
/**
* zacatek parsovani. Vytvori bufferdreader a spusti parser
*/
private void run_url() {
try {
//vytvoreni nove URL
URL url_id = new URL(this.url);
//Vytvoreni BufferedReaderu
BufferedReader htmlPage = new BufferedReader(new InputStreamReader(
url_id.openStream(), this.charset));
//spusteni parsovani
this.parse(htmlPage);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
*
* @param url
* @return
* jednoducha kontrola url adresy
*/
public int check_url(String url) {
if (url.startsWith("http://") == false)
return 0;
return 1;
}
/**
*
* @param htmlText
* @throws IOException
* vytvori novy ParserDelegator a vola metodu pro parsovani
*/
public void parse(Reader htmlText) throws IOException {
ParserDelegator delegator = new ParserDelegator();
delegator.parse(htmlText, this, Boolean.TRUE);
}
/**
* @param text
* @param pos
* handleText odchiti veskery text, ktery vytvari obsah html stranky
*/
public void handleText(char[] text, int pos) {
System.out.println("Text: " + String.valueOf(text));
}
/**
* @param coment
* @param pos
* handleComent odchiti html poznamky
*/
public void handleComment(char[] coment, int pos) {
System.out.println("Komentar: " + String.valueOf(coment));
}
/**
* @param tag
* @param atr
* @param pos
* handleStartTag odchyti zacatek noveho tagu, vcetne jeho atributu
*/
public void handleStartTag(HTML.Tag tag, MutableAttributeSet atr, int pos) {
System.out.println("Zacatek tagu: "" + tag + """);
System.out.println("Tag obsahuje atributy: "" + atr + """);
}
/**
* @param tag
* @param atr
* @param pos
* handleEndTag odchyti konec tagu
*/
public void handleEndTag(HTML.Tag tag, int pos) {
System.out.println("Konec tagu: "" + tag + """);
}
/**
* @param tag
* @param atr
* @param pos
* handleSimpleTag odchyti jednoduche html tagy jako BR, IMG, apod.
*/
public void handleSimpleTag(HTML.Tag tag, MutableAttributeSet atr, int pos) {
System.out.println("Zacatek jednoducheho tagu: "" + tag + """);
System.out.println("Tag obsahuje atributy: "" + atr + """);
}
/**
* @param str
* @param pos
* handleError odchyti chby v HTML
*/
public void handleError(String str, int pos) {
//System.out.println("Parse error: " + str);
}
/**
* @author Zachar Jiří
* @param args
*/
public static void main(String[] args) {
String charset = "UTF-8";
String url = null;
if (args.length > 0) {
url = String.valueOf(args[0]);
}
if (args.length > 1) {
charset = String.valueOf(args[1]);
}
new ParseHtml(url, charset);
}
}

Autor: Zaachi
Publikováno: 3.3.2008 15:40:59
HTML & JavaScript: roztahovací Select [IE bug]
Vývoj aplikací pro iPhone: XML parser with NSXMLParser
Java a základy GUI
Java a základy GUI #2