package parser;php
package parser;css
import java.io.BufferedReader;html
import java.io.BufferedWriter;java
import java.io.FileWriter;node
import java.io.IOException;web
import java.io.InputStream;算法
import java.io.InputStreamReader;apache
import java.net.MalformedURLException;api
import java.net.URL;瀏覽器
/**
* 基本能實現網頁抓取,不過要手動輸入URL 將整個html內容保存到指定文件
*
* @author chenguoyong
*
*/
public class ScrubSelectedWeb {
private final static String CRLF = System.getProperty("line.separator");
/**
* @param args
*/
public static void main(String[] args) {
try {
URL ur = new URL("http://10.249.187.199:8083/injs100/");
InputStream instr = ur.openStream();
String s, str;
BufferedReader in = new BufferedReader(new InputStreamReader(instr));
StringBuffer sb = new StringBuffer();
BufferedWriter out = new BufferedWriter(new FileWriter(
"D:/outPut.txt"));
while ((s = in.readLine()) != null) {
sb.append(s + CRLF);
}
System.out.println(sb);
str = new String(sb);
out.write(str);
out.close();
in.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
基本能實現網頁抓取,不過要手動輸入URL,此外沒有重構。只是一個簡單的思路。
1.htmlparser 使用
htmlparser是一個純的java寫的html解析的庫,htmlparser不依賴於其它的java庫,htmlparser主要用於改造 或提取html。htmlparser能超高速解析html,並且不會出錯。絕不誇張地說,htmlparser就是目前最好的html解 析和分析的工具。不管你是想抓取網頁數據仍是改造html的內容,用了htmlparser絕對會忍不住稱讚。因爲htmlparser 結構設計精良,因此擴展htmlparser 很是便利。
Constructor Summary |
Parser()
Parser(URLConnection connection)
Construct a parser using the provided URLConnection.
Method:
static Parser createParser(String html, String charset)
Creates the parser on an input string.
void visitAllNodesWith(NodeVisitor visitor)
Apply the given visitor to the current page.
getBody() |
|
TableTag[] |
|
getTitle() |
|
void |
|
void |
Constructor Summary |
|
NodeList() |
|
|
NodeList extractAllNodesThatMatch(NodeFilter filter)
Filter the list with the given filter non-recursively.
NodeList extractAllNodesThatMatch(NodeFilter filter, boolean recursive)
Filter the list with the given filter.
1. html代碼裏面全部的連接地址和連接名稱
package parser;
import org.htmlparser.Parser;
import org.htmlparser.Node;
import org.htmlparser.NodeFilter;
import org.htmlparser.Parser;
import org.htmlparser.filters.TagNameFilter;
import org.htmlparser.tags.LinkTag;
import org.htmlparser.tags.TableTag;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.ParserException;
import org.htmlparser.visitors.HtmlPage;
/**
* htmlparser取得一段html代碼裏面全部的連接地址和連接名稱
*
* @author chenguoyong
*
*/
public class Testhtmlparser {
/**
* @param args
*/
public static void main(String[] args) {
String htmlcode = "<HTML><HEAD><TITLE>AAA</TITLE></HEAD><BODY>"
+ "<a href='http://topic.csdn.net/u/20080522/14/0ff402ef-c382-499a-8213-ba6b2f550425.html'>鏈接1</a>"
+ "<a href='http://topic.csdn.net'>鏈接2</a></BODY></HTML>";
// 建立Parser對象根據傳給字符串和指定的編碼
Parser parser = Parser.createParser(htmlcode, "GBK");
// 建立HtmlPage對象HtmlPage(Parser parser)
HtmlPage page = new HtmlPage(parser);
try {
// HtmlPage extends visitor,Apply the given visitor to the current
// page.
parser.visitAllNodesWith(page);
} catch (ParserException e1) {
e1 = null;
}
// 全部的節點
NodeList nodelist = page.getBody();
// 創建一個節點filter用於過濾節點
NodeFilter filter = new TagNameFilter("A");
// 獲得全部過濾後,想要的節點
nodelist = nodelist.extractAllNodesThatMatch(filter, true);
for (int i = 0; i < nodelist.size(); i++) {
LinkTag link = (LinkTag) nodelist.elementAt(i);
// 連接地址
System.out.println(link.getAttribute("href") + "\n");
// 連接名稱
System.out.println(link.getStringText());
}
}
}
2. 使用HtmlParser抓去網頁內容
package parser;
import org.htmlparser.Parser;
import org.htmlparser.beans.StringBean;
import org.htmlparser.filters.NodeClassFilter;
import org.htmlparser.parserapplications.StringExtractor;
import org.htmlparser.tags.BodyTag;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.ParserException;
/**
* 使用HtmlParser抓去網頁內容: 要抓去頁面的內容最方便的方法就是使用StringBean. 裏面有幾個控制頁面內容的幾個參數.
* 在後面的代碼中會有說明. Htmlparser包中還有一個示例StringExtractor 裏面有個直接獲得內容的方法,
* 其中也是使用了StringBean . 另外直接解析Parser的每一個標籤也能夠的.
*
* @author chenguoyong
*
*/
public class GetContent {
public void getContentUsingStringBean(String url) {
StringBean sb = new StringBean();
sb.setLinks(true); // 是否顯示web頁面的鏈接(Links)
// 爲了取得頁面的整潔美觀通常設置上面兩項爲true , 若是要保持頁面的原有格式, 如代碼頁面的空格縮進 能夠設置爲false
sb.setCollapse(true); // 若是是true的話把一系列空白字符用一個字符替代.
sb.setReplaceNonBreakingSpaces(true);// If true regular space
sb
.setURL("http://www.blogjava.net/51AOP/archive/2006/07/19/59064.html");
System.out.println("The Content is :\n" + sb.getStrings());
}
public void getContentUsingStringExtractor(String url, boolean link) {
// StringExtractor內部機制和上面的同樣.作了一下包裝
StringExtractor se = new StringExtractor(url);
String text = null;
try {
text = se.extractStrings(link);
System.out.println("The content is :\n" + text);
} catch (ParserException e) {
e.printStackTrace();
}
}
public void getContentUsingParser(String url) {
NodeList nl;
try {
Parser p = new Parser(url);
nl = p.parse(new NodeClassFilter(BodyTag.class));
BodyTag bt = (BodyTag) nl.elementAt(0);
System.out.println(bt.toPlainTextString()); // 保留原來的內容格式. 包含js代碼
} catch (ParserException e) {
e.printStackTrace();
}
}
/**
* @param args
*/
public static void main(String[] args) {
String url = "http://www.blogjava.net/51AOP/archive/2006/07/19/59064.html";
//new GetContent().getContentUsingParser(url);
//--------------------------------------------------
new GetContent().getContentUsingStringBean(url);
}
}
3.將整個html內容保存到指定文件
package parser;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
/**
* 基本能實現網頁抓取,不過要手動輸入URL 將整個html內容保存到指定文件
*
* @author chenguoyong
*
*/
public class ScrubSelectedWeb {
private final static String CRLF = System.getProperty("line.separator");
/**
* @param args
*/
public static void main(String[] args) {
try {
URL ur = new URL("http://www.google.cn/");
InputStream instr = ur.openStream();
String s, str;
BufferedReader in = new BufferedReader(new InputStreamReader(instr));
StringBuffer sb = new StringBuffer();
BufferedWriter out = new BufferedWriter(new FileWriter(
"D:/outPut.txt"));
while ((s = in.readLine()) != null) {
sb.append(s + CRLF);
}
System.out.println(sb);
str = new String(sb);
out.write(str);
out.close();
in.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
4利用htmlparser提取網頁純文本的例子
package parser;
import org.htmlparser.Node;
import org.htmlparser.NodeFilter;
import org.htmlparser.Parser;
import org.htmlparser.filters.TagNameFilter;
import org.htmlparser.tags.TableTag;
import org.htmlparser.util.NodeList;
/**
* 標題:利用htmlparser提取網頁純文本的例子
*/
public class TestHTMLParser2 {
/**
* 讀取目標html內容
*
*/
public static void testHtml() {
try {
String sCurrentLine;
String sTotalString;
sCurrentLine = "";
sTotalString = "";
java.io.InputStream l_urlStream;
java.net.URL l_url = new java.net.URL(
"http://10.249.187.199:8083/injs100/");
java.net.HttpURLConnection l_connection = (java.net.HttpURLConnection) l_url
.openConnection();
l_connection.connect();
l_urlStream = l_connection.getInputStream();
java.io.BufferedReader l_reader = new java.io.BufferedReader(
new java.io.InputStreamReader(l_urlStream));
while ((sCurrentLine = l_reader.readLine()) != null) {
sTotalString += sCurrentLine + "\r\n";
}
String testText = extractText(sTotalString);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 抽取純文本信息
* @param inputHtml:html文本
* @return
* @throws Exception
*/
public static String extractText(String inputHtml) throws Exception {
StringBuffer text = new StringBuffer();
Parser parser = Parser.createParser(new String(inputHtml.getBytes(),
"GBK"), "GBK");
// 遍歷全部的節點
NodeList nodes = parser.extractAllNodesThatMatch(new NodeFilter() {
public boolean accept(Node node) {
return true;
}
});
System.out.println(nodes.size());
for (int i = 0; i < nodes.size(); i++) {
Node nodet = nodes.elementAt(i);
//字符串的表明性節點:節點的描述
text.append(new String(nodet.toPlainTextString().getBytes("GBK"))
+ "\r\n");
}
return text.toString();
}
/**
* 讀取文件的方式/utl 來分析內容. filePath也能夠是一個Url.
* @param resource :文件/Url
* @throws Exception
*/
public static void test5(String resource) throws Exception {
Parser myParser = new Parser(resource);
myParser.setEncoding("GBK");
String filterStr = "table";
NodeFilter filter = new TagNameFilter(filterStr);
NodeList nodeList = myParser.extractAllNodesThatMatch(filter);
/*for(int i=0;i<nodeList.size();i++)
{
TableTag tabletag = (TableTag) nodeList.elementAt(i);
//標籤名稱
System.out.println(tabletag.getTagName());
System.out.println(tabletag.getText());
}*/
TableTag tabletag = (TableTag) nodeList.elementAt(1);
}
public static void main(String[] args) throws Exception {
test5("http://10.249.187.199:8083/injs100/");
//testHtml();
}
}
5.html解析table
package parser;
import org.apache.log4j.Logger;
import org.htmlparser.NodeFilter;
import org.htmlparser.Parser;
import org.htmlparser.filters.NodeClassFilter;
import org.htmlparser.filters.OrFilter;
import org.htmlparser.filters.TagNameFilter;
import org.htmlparser.tags.TableColumn;
import org.htmlparser.tags.TableRow;
import org.htmlparser.tags.TableTag;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.ParserException;
import junit.framework.TestCase;
public class ParserTestCase extends TestCase {
private static final Logger logger = Logger.getLogger(ParserTestCase.class);
public ParserTestCase(String name) {
super(name);
}
/**
* 測試對<table>
* <tr>
* <td></td>
* </tr>
* </table>的解析
*/
public void testTable() {
Parser myParser;
NodeList nodeList = null;
myParser = Parser
.createParser(
"<body> "
+ "<table id=’table1′ >"
+ "<tr id='tro1'><td>1-11</td><td>1-12</td><td>1-13</td></tr>"
+ "<tr id='tro2'><td>1-21</td><td>1-22</td><td>1-23</td></tr>"
+ "<tr id='tro3'><td>1-31</td><td>1-32</td><td>1-33</td></tr></table>"
+ "<table id=’table2′ >"
+ "<tr id='tro4'><td>2-11</td><td>2-12</td><td>2-13</td></tr>"
+ "<tr id='tro5'><td>2-21</td><td>2-22</td><td>2-23</td></tr>"
+ "<tr id='tro6'><td>2-31</td><td>2-32</td><td>2-33</td></tr></table>"
+ "</body>", "GBK");
NodeFilter tableFilter = new NodeClassFilter(TableTag.class);
OrFilter lastFilter = new OrFilter();
lastFilter.setPredicates(new NodeFilter[] { tableFilter });
try {
nodeList = myParser.parse(lastFilter);
for (int i = 0; i <= nodeList.size(); i++) {
if (nodeList.elementAt(i) instanceof TableTag) {
TableTag tag = (TableTag) nodeList.elementAt(i);
TableRow[] rows = tag.getRows();
for (int j = 0; j < rows.length; j++) {
TableRow tr = (TableRow) rows[j];
System.out.println(tr.getAttribute("id"));
if (tr.getAttribute("id").equalsIgnoreCase("tro1")) {
TableColumn[] td = tr.getColumns();
for (int k = 0; k < td.length; k++) {
// logger.fatal("<td>" +
// td[k].toPlainTextString());
System.out.println("<td>"
+ td[k].toPlainTextString());
}
}
}
}
}
} catch (ParserException e) {
e.printStackTrace();
}
}
/**
* 獲得目標數據
*
* @param url:目標url
* @throws Exception
*/
public static void getDatabyUrl(String url) throws Exception {
Parser myParser = new Parser(url);
NodeList nodeList = null;
myParser.setEncoding("gb2312");
NodeFilter tableFilter = new NodeClassFilter(TableTag.class);
OrFilter lastFilter = new OrFilter();
lastFilter.setPredicates(new NodeFilter[] { tableFilter });
try {
nodeList = myParser.parse(lastFilter);
// 能夠從數據table的size:19-21開始到結束
for (int i = 15; i <= nodeList.size(); i++) {
if (nodeList.elementAt(i) instanceof TableTag) {
TableTag tag = (TableTag) nodeList.elementAt(i);
TableRow[] rows = tag.getRows();
for (int j = 0; j < rows.length; j++) {
TableRow tr = (TableRow) rows[j];
if (tr.getAttribute("id") != null
&& tr.getAttribute("id").equalsIgnoreCase(
"tr02")) {
TableColumn[] td = tr.getColumns();
// 對不起,沒有你要查詢的記錄!
if (td.length == 1) {
System.out.println("對不起,沒有你要查詢的記錄");
} else {
for (int k = 0; k < td.length; k++) {
System.out.println("<td>內容:"
+ td[k].toPlainTextString().trim());
}
}
}
}
}
}
} catch (ParserException e) {
e.printStackTrace();
}
}
/**
* 測試已經得出有數據時table:22個,沒有數據時table:19個
*
* @param args
*/
public static void main(String[] args) {
try {
// getDatabyUrl("http://gd.12530.com/user/querytonebytype.do?field=tonecode&condition=619505000000008942&type=1006&pkValue=619505000000008942");
getDatabyUrl("http://gd.12530.com/user/querytonebytype.do?field=tonecode&condition=619272000000001712&type=1006&pkValue=619272000000001712");
} catch (Exception e) {
e.printStackTrace();
}
}
}
6.html解析經常使用
package com.jscud.test;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import org.htmlparser.Node;
import org.htmlparser.NodeFilter;
import org.htmlparser.Parser;
import org.htmlparser.filters.NodeClassFilter;
import org.htmlparser.filters.OrFilter;
import org.htmlparser.nodes.TextNode;
import org.htmlparser.tags.LinkTag;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.ParserException;
import org.htmlparser.visitors.HtmlPage;
import org.htmlparser.visitors.TextExtractingVisitor;
import com.jscud.util.LogMan; //一個日誌記錄類
/**
* 演示了Html Parse的應用.
*
* @author scud http://www.jscud.com (http://www.jscud.com/)
*/
public class ParseHtmlTest
{
public static void main(String[] args) throws Exception
{
String aFile = "e:/jscud/temp/test.htm";
String content = readTextFile(aFile, "GBK");
test1(content);
System.out.println("====================================");
test2(content);
System.out.println("====================================");
test3(content);
System.out.println("====================================");
test4(content);
System.out.println("====================================");
test5(aFile);
System.out.println("====================================");
//訪問外部資源,相對慢
test5("http://www.jscud.com (http://www.jscud.com/)");
System.out.println("====================================");
}
/**
* 讀取文件的方式來分析內容.
* filePath也能夠是一個Url.
*
* @param resource 文件/Url
*/
public static void test5(String resource) throws Exception
{
Parser myParser = new Parser(resource);
//設置編碼
myParser.setEncoding("GBK");
HtmlPage visitor = new HtmlPage(myParser);
myParser.visitAllNodesWith(visitor);
String textInPage = visitor.getTitle();
System.out.println(textInPage);
}
/**
* 按頁面方式處理.對一個標準的Html頁面,推薦使用此種方式.
*/
public static void test4(String content) throws Exception
{
Parser myParser;
myParser = Parser.createParser(content, "GBK");
HtmlPage visitor = new HtmlPage(myParser);
myParser.visitAllNodesWith(visitor);
String textInPage = visitor.getTitle();
System.out.println(textInPage);
}
/**
* 利用Visitor模式解析html頁面.
*
* 小優勢:翻譯了<>等符號
* 缺點:好多空格,沒法提取link
*
*/
public static void test3(String content) throws Exception
{
Parser myParser;
myParser = Parser.createParser(content, "GBK");
TextExtractingVisitor visitor = new TextExtractingVisitor();
myParser.visitAllNodesWith(visitor);
String textInPage = visitor.getExtractedText();
System.out.println(textInPage);
}
/**
* 獲得普通文本和連接的內容.
*
* 使用了過濾條件.
*/
public static void test2(String content) throws ParserException
{
Parser myParser;
NodeList nodeList = null;
myParser = Parser.createParser(content, "GBK");
NodeFilter textFilter = new NodeClassFilter(TextNode.class);
NodeFilter linkFilter = new NodeClassFilter(LinkTag.class);
//暫時不處理 meta
//NodeFilter metaFilter = new NodeClassFilter(MetaTag.class);
OrFilter lastFilter = new OrFilter();
lastFilter.setPredicates(new NodeFilter[] { textFilter, linkFilter });
nodeList = myParser.parse(lastFilter);
Node[] nodes = nodeList.toNodeArray();
for (int i = 0; i < nodes.length; i++)
{
Node anode = (Node) nodes[i];
String line = "";
if (anode instanceof TextNode)
{
TextNode textnode = (TextNode) anode;
//line = textnode.toPlainTextString().trim();
line = textnode.getText();
}
else if (anode instanceof LinkTag)
{
LinkTag linknode = (LinkTag) anode;
line = linknode.getLink();
//@todo ("") 過濾jsp標籤:能夠本身實現這個函數
//line = StringFunc.replace(line, "<%.*%>", "");
}
if (isTrimEmpty(line))
continue;
System.out.println(line);
}
}
/**
* 解析普通文本節點.
*
* @param content
* @throws ParserException
*/
public static void test1(String content) throws ParserException
{
Parser myParser;
Node[] nodes = null;
myParser = Parser.createParser(content, null);
nodes = myParser.extractAllNodesThatAre(TextNode.class); //exception could be thrown here
for (int i = 0; i < nodes.length; i++)
{
TextNode textnode = (TextNode) nodes[i];
String line = textnode.toPlainTextString().trim();
if (line.equals(""))
continue;
System.out.println(line);
}
}
/**
* 讀取一個文件到字符串裏.
*
* @param sFileName 文件名
* @param sEncode String
* @return 文件內容
*/
public static String readTextFile(String sFileName, String sEncode)
{
StringBuffer sbStr = new StringBuffer();
try
{
File ff = new File(sFileName);
InputStreamReader read = new InputStreamReader(new FileInputStream(ff),
sEncode);
BufferedReader ins = new BufferedReader(read);
String dataLine = "";
while (null != (dataLine = ins.readLine()))
{
sbStr.append(dataLine);
sbStr.append("\r\n");
}
ins.close();
}
catch (Exception e)
{
LogMan.error("read Text File Error", e);
}
return sbStr.toString();
}
/**
* 去掉左右空格後字符串是否爲空
* @param astr String
* @return boolean
*/
public static boolean isTrimEmpty(String astr)
{
if ((null == astr) || (astr.length() == 0))
{
return true;
}
if (isBlank(astr.trim()))
{
return true;
}
return false;
}
/**
* 字符串是否爲空:null或者長度爲0.
* @param astr 源字符串.
* @return boolean
*/
public static boolean isBlank(String astr)
{
if ((null == astr) || (astr.length() == 0))
{
return true;
}
else
{
return false;
}
}
}
2.使用 HttpClient 和 HtmlParser 實現簡易爬蟲
本小結簡單的介紹一下 HttpClinet 和 HtmlParser 兩個開源的項目,以及他們的網站和提供下載的地址。
HttpClient 簡介
HTTP 協議是如今的因特網最重要的協議之一。除了 WEB 瀏覽器以外, WEB 服務,基於網絡的應用程序以及日益增加的網絡計算不斷擴展着 HTTP 協議的角色,使得愈來愈多的應用程序須要 HTTP 協議的支持。雖然 JAVA 類庫 .net 包提供了基本功能, 來使用 HTTP 協議訪問網絡資源,可是其靈活性和功能遠不能知足不少應用程序的須要。而 Jakarta Commons HttpClient 組件尋求提供更爲靈活,更加高效的 HTTP 協議支持,簡化基於 HTTP 協議的應用程序的建立。 HttpClient 提供了不少的特性,支持最新的 HTTP 標準,能夠訪問這裏瞭解更多關於 HttpClinet 的詳細信息。目前有不少的開源項目都用到了 HttpClient 提供的 HTTP功能,登錄網址能夠查看這些項目。本文中使用 HttpClinet 提供的類庫來訪問和下載 Internet上面的網頁,在後續部分會詳細介紹到其提供的兩種請求網絡資源的方法: Get 請求和 Post 請求。Apatche 提供免費的 HTTPClien t源碼和 JAR 包下載,能夠登錄這裏 下載最新的HttpClient 組件。筆者使用的是 HttpClient3.1。
HtmlParser 簡介
當今的 Internet 上面有數億記的網頁,愈來愈多應用程序將這些網頁做爲分析和處理的數據對象。這些網頁多爲半結構化的文本,有着大量的標籤和嵌套的結構。當咱們本身開發一 些處理網頁的應用程序時,會想到要開發一個單獨的網頁解析器,這一部分的工做一定須要付出至關的精力和時間。事實上,作爲 JAVA 應用程序開發者, HtmlParser 爲其提供了強大而靈活易用的開源類庫,大大節省了寫一個網頁解析器的開銷。 HtmlParser 是 http://sourceforge.net 上活躍的一個開源項目,它提供了線性和嵌套兩種方式來解析網頁,主要用於 html 網頁的轉換(Transformation) 以及網頁內容的抽取 (Extraction)。HtmlParser 有以下一些易於使用的特性:過濾器 (Filters),訪問者模式 (Visitors),處理自定義標籤以及易於使用的 JavaBeans。正如 HtmlParser 首頁所說:它是一個快速,健壯以及嚴格測試過的組件;以它設計的簡潔,程序運行的速度以及處理 Internet 上真實網頁的能力吸引着愈來愈多的開發者。 本文中就是利用HtmlParser 裏提取網頁裏的連接,實現簡易爬蟲裏的關鍵部分。HtmlParser 最新的版本是HtmlParser1.6,能夠登錄這裏下載其源碼、 API 參考文檔以及 JAR 包。
簡單強大的 StringBean
若是你想要網頁中去掉全部的標籤後剩下的文本,那就是用 StringBean 吧。如下簡單的代碼能夠幫你解決這樣的問題:
清單5
StringBean sb = new StringBean();
sb.setLinks(false);//設置結果中去點連接
sb.setURL(url);//設置你所須要濾掉網頁標籤的頁面 url
System.out.println(sb.getStrings());//打印結果
HtmlParser 提供了強大的類庫來處理網頁,因爲本文旨在簡單的介紹,所以只是將與筆者後續爬蟲部分有關的關鍵類庫進行了示例說明。感興趣的讀者能夠專門來研究一下 HtmlParser 更爲強大的類庫。
簡易爬蟲的實現
HttpClient 提供了便利的 HTTP 協議訪問,使得咱們能夠很容易的獲得某個網頁的源碼並保存在本地;HtmlParser 提供瞭如此簡便靈巧的類庫,能夠從網頁中便捷的提取出指向其餘網頁的超連接。筆者結合這兩個開源包,構建了一個簡易的網絡爬蟲。
爬蟲 (Crawler) 原理
學過數據結構的讀者都知道有向圖這種數據結構。以下圖所示,若是將網頁當作是圖中的某一個節點,而將網頁中指向其餘網頁的連接當作是這個節點指向其餘節 點的邊,那麼咱們很容易將整個 Internet 上的網頁建模成一個有向圖。理論上,經過遍歷算法遍歷該圖,能夠訪問到Internet 上的幾乎全部的網頁。最簡單的遍歷就是寬度優先以及深度優先。如下筆者實現的簡易爬蟲就是使用了寬度優先的爬行策略。
圖 2. 網頁關係的建模圖
簡易爬蟲實現流程
在看簡易爬蟲的實現代碼以前,先介紹一下簡易爬蟲爬取網頁的流程。
圖 3. 爬蟲流程圖
各個類的源碼以及說明
對應上面的流程圖,簡易爬蟲由下面幾個類組成,各個類職責以下:
Crawler.java:爬蟲的主方法入口所在的類,實現爬取的主要流程。
LinkDb.java:用來保存已經訪問的 url 和待爬取的 url 的類,提供url出對入隊操做。
Queue.java: 實現了一個簡單的隊列,在 LinkDb.java 中使用了此類。
FileDownloader.java:用來下載 url 所指向的網頁。
HtmlParserTool.java: 用來抽取出網頁中的連接。
LinkFilter.java:一個接口,實現其 accept() 方法用來對抽取的連接進行過濾。
下面是各個類的源碼,代碼中的註釋有比較詳細的說明。
3.Htmlparser彙總說明
關鍵字: htmlparser
須要作一個垂直搜索引擎,比較了nekohtml和htmlparser 的功能,儘管nekohtml在容錯性、性能等方面的口碑好像比htmlparser好(htmlunit也用的是nekohtml),但感受 nekohtml的測試用例和文檔都比htmlparser都少,並且htmlparser基本上可以知足垂直搜索引擎頁面處理分析的需求,所以先研究一 下htmlparser的使用,有空再研究nekohtml和mozilla html parser的使用。
html的功能仍是官方說得最爲清楚,
引用
HTML Parser is a Java library used to parse HTML in either a linear or nested fashion. Primarily used for transformation or extraction, it features filters, visitors, custom tags and easy to use JavaBeans. It is a fast, robust and well tested package.
The two fundamental use-cases that are handled by the parser are extraction and transformation (the syntheses use-case, where HTML pages are created from scratch, is better handled by other tools closer to the source of data). While prior versions concentrated on data extraction from web pages, Version 1.4 of the HTMLParser has substantial improvements in the area of transforming web pages, with simplified tag creation and editing, and verbatim toHtml() method output.
研究的重點仍是extraction的使用,有空再研究transformation的使用。
一、htmlparser對html頁面處理的數據結構
如圖所示,HtmlParser採用了經典的Composite模式,經過RemarkNode、TextNode、TagNode、AbstractNode和Tag來描述HTML頁面各元素。
* org.htmlparser.Node:
Node接口定義了進行樹形結構節點操做的各類典型操做方法,
包括:
節點到html文本、text文本的方法:toPlainTextString、toHtml
典型樹形結構遍歷的方法:getParent、getChildren、getFirstChild、getLastChild、getPreviousSibling、getNextSibling、getText
獲取節點對應的樹形結構結構的頂級節點Page對象方法:getPage
獲取節點起始位置的方法:getStartPosition、getEndPosition
Visitor方法遍歷節點時候方法:accept (NodeVisitor visitor)
Filter方法:collectInto (NodeList list, NodeFilter filter)
Object方法:toString、clone
* org.htmlparser.nodes.AbstractNode:
AbstractNode是造成HTML樹形結構抽象基類,實現了Node接口。
在htmlparser中,Node分紅三類:
RemarkNode:表明Html中的註釋
TagNode:標籤節點。
TextNode:文本節點
這三類節點都繼承AbstractNode。
* org.htmlparser.nodes.TagNode:
TagNode包含了對HTML處理的核心的各個類,是全部TAG的基類,其中有分爲包含其餘TAG的複合節點ComositeTag和不包含其餘TAG的葉子節點Tag。
複合節點CompositeTag:
AppletTag,BodyTag,Bullet,BulletList,DefinitionList,DefinitionListBullet,Div,FormTag,FrameSetTag,HeadingTag,
HeadTag,Html,LabelTag,LinkTag,ObjectTag,ParagraphTag,ScriptTag,SelectTag,Span,StyleTag,TableColumn,
TableHeader,TableRow,TableTag,TextareaTag,TitleTag
葉子節點TAG:
BaseHrefTag,DoctypeTag,FrameTag,ImageTag,InputTag,JspTag,MetaTag,ProcessingInstructionTag,
二、htmlparser對html頁面處理的算法
主要是以下幾種方式
l採用Visitor方式訪問Html
1.三、htmlparser關鍵包結構說明
2.
3. htmlparser其實核心代碼並很少,好好研究一下其代碼,彌補文檔不足的問題。同時htmlparser的代碼註釋和單元測試用例仍是很齊全的,也有助於瞭解htmlparser的用法。
4.
5.
6.3.一、org.htmlparser
7.
8. 定義了htmlparser的一些基礎類。其中最爲重要的是Parser類。
9.
10. Parser 是htmlparser的最核心的類,其構造函數提供了以下:Parser.createParser (String html, String charset)、 Parser ()、Parser (Lexer lexer, ParserFeedback fb)、 Parser (URLConnection connection, ParserFeedback fb)、Parser (String resource, ParserFeedback feedback)、 Parser (String resource)
11.
12. 各構造函數的具體用法及含義能夠查看其代碼,很容易理解。
13.
14. Parser經常使用的幾個方法:
15.
16. * elements獲取元素
17.
18. Parser parser = new Parser (」http://www.google.com」);
19. for (NodeIterator i = parser.elements (); i.hasMoreElements (); )
20. processMyNodes (i.nextNode ());
21.
22. * parse (NodeFilter filter):經過NodeFilter方式獲取
23. * visitAllNodesWith (NodeVisitor visitor):經過Nodevisitor方式
24. * extractAllNodesThatMatch (NodeFilter filter):經過NodeFilter方式
25.
26.3.二、org.htmlparser.beans
27.
28. 對Visitor和Filter的方法進行了封裝,定義了針對一些經常使用html元素操做的bean,簡化對經常使用元素的提取操做。
29.
30. 包括:FilterBean、HTMLLinkBean、HTMLTextBean、LinkBean、StringBean、BeanyBaby等。
31.3.三、org.htmlparser.nodes
32.
33. 定義了基礎的node,包括:AbstractNode、RemarkNode、TagNode、TextNode等。
34.3.四、org.htmlparser.tags
35.
36. 定義了htmlparser的各類tag。
37.3.五、org.htmlparser.filters
38.
39. 定義了htmlparser所提供的各類filter,主要經過extractAllNodesThatMatch (NodeFilter filter)來對html頁面指定類型的元素進行過濾,包括:AndFilter、 CssSelectorNodeFilter、 HasAttributeFilter、HasChildFilter、 HasParentFilter、HasSiblingFilter、 IsEqualFilter、LinkRegexFilter、 LinkStringFilter、NodeClassFilter、 NotFilter、OrFilter、RegexFilter、 StringFilter、TagNameFilter、XorFilter
40.3.六、org.htmlparser.visitors
41.
42. 定義了htmlparser所提供的各類visitor,主要經過visitAllNodesWith (NodeVisitor visitor)來對 html頁面元素進行遍歷,包括:HtmlPage、LinkFindingVisitor、NodeVisitor、 ObjectFindingVisitor、StringFindingVisitor、TagFindingVisitor、 TextExtractingVisitor、UrlModifyingVisitor
43.
44.
45.3.七、org.htmlparser.parserapplications
46.
47. 定義了一些實用的工具,包括LinkExtractor、SiteCapturer、StringExtractor、WikiCapturer,這幾個類也能夠做爲htmlparser使用樣例。
48.3.八、org.htmlparser.tests
49.
50. 對各類功能的單元測試用例,也能夠做爲htmlparser使用的樣例。
51.
52.
53.四、htmlparser的使用樣例
54.
55.
56.
57.import java.net.URL;
58.
59.import junit.framework.TestCase;
60.
61.import org.apache.log4j.Logger;
62.import org.htmlparser.Node;
63.import org.htmlparser.NodeFilter;
64.import org.htmlparser.Parser;
65.import org.htmlparser.Tag;
66.import org.htmlparser.beans.LinkBean;
67.import org.htmlparser.filters.NodeClassFilter;
68.import org.htmlparser.filters.OrFilter;
69.import org.htmlparser.filters.TagNameFilter;
70.import org.htmlparser.tags.HeadTag;
71.import org.htmlparser.tags.ImageTag;
72.import org.htmlparser.tags.InputTag;
73.import org.htmlparser.tags.LinkTag;
74.import org.htmlparser.tags.OptionTag;
75.import org.htmlparser.tags.SelectTag;
76.import org.htmlparser.tags.TableColumn;
77.import org.htmlparser.tags.TableRow;
78.import org.htmlparser.tags.TableTag;
79.import org.htmlparser.tags.TitleTag;
80.import org.htmlparser.util.NodeIterator;
81.import org.htmlparser.util.NodeList;
82.import org.htmlparser.util.ParserException;
83.import org.htmlparser.visitors.HtmlPage;
84.import org.htmlparser.visitors.NodeVisitor;
85.import org.htmlparser.visitors.ObjectFindingVisitor;
86.
87.public class ParserTestCase extends TestCase {
88.
89. private static final Logger logger = Logger.getLogger(ParserTestCase.class);
90.
91. public ParserTestCase(String name) {
92. super(name);
93. }
94. /*
95. * 測試ObjectFindVisitor的用法
96. */
97. public void testImageVisitor() {
98. try {
99. ImageTag imgLink;
100. ObjectFindingVisitor visitor = new ObjectFindingVisitor(
101. ImageTag.class);
102. Parser parser = new Parser();
103. parser.setURL(」http://www.google.com」);
104. parser.setEncoding(parser.getEncoding());
105. parser.visitAllNodesWith(visitor);
106. Node[] nodes = visitor.getTags();
107. for (int i = 0; i < nodes.length; i++) {
108. imgLink = (ImageTag) nodes[i];
109. logger.fatal(」testImageVisitor() ImageURL = 「
110. + imgLink.getImageURL());
111. logger.fatal(」testImageVisitor() ImageLocation = 「
112. + imgLink.extractImageLocn());
113. logger.fatal(」testImageVisitor() SRC = 「
114. + imgLink.getAttribute(」SRC」));
115. }
116. }
117. catch (Exception e) {
118. e.printStackTrace();
119. }
120. }
121. /*
122. * 測試TagNameFilter用法
123. */
124. public void testNodeFilter() {
125. try {
126. NodeFilter filter = new TagNameFilter(」IMG」);
127. Parser parser = new Parser();
128. parser.setURL(」http://www.google.com」);
129. parser.setEncoding(parser.getEncoding());
130. NodeList list = parser.extractAllNodesThatMatch(filter);
131. for (int i = 0; i < list.size(); i++) {
132. logger.fatal(」testNodeFilter() 」 + list.elementAt(i).toHtml());
133. }
134. } catch (Exception e) {
135. e.printStackTrace();
136. }
137.
138. }
139. /*
140. * 測試NodeClassFilter用法
141. */
142. public void testLinkTag() {
143. try {
144.
145. NodeFilter filter = new NodeClassFilter(LinkTag.class);
146. Parser parser = new Parser();
147. parser.setURL(」http://www.google.com」);
148. parser.setEncoding(parser.getEncoding());
149. NodeList list = parser.extractAllNodesThatMatch(filter);
150. for (int i = 0; i < list.size(); i++) {
151. LinkTag node = (LinkTag) list.elementAt(i);
152. logger.fatal(」testLinkTag() Link is :」 + node.extractLink());
153. }
154. } catch (Exception e) {
155. e.printStackTrace();
156. }
157.
158. }
159. /*
160. * 測試<link href=」 text=’text/css’ rel=’stylesheet’ />用法
161. */
162. public void testLinkCSS() {
163. try {
164.
165. Parser parser = new Parser();
166. parser
167. .setInputHTML(」<head><title>Link Test</title>」
168. + 「<link href=’/test01/css.css’ text=’text/css’ rel=’stylesheet’ />」
169. + 「<link href=’/test02/css.css’ text=’text/css’ rel=’stylesheet’ />」
170. + 「</head>」 + 「<body>」);
171. parser.setEncoding(parser.getEncoding());
172. NodeList nodeList = null;
173.
174. for (NodeIterator e = parser.elements(); e.hasMoreNodes();) {
175. Node node = e.nextNode();
176. logger
177. .fatal(」testLinkCSS()」 + node.getText()
178. + node.getClass());
179.
180. }
181. } catch (Exception e) {
182. e.printStackTrace();
183. }
184. }
185. /*
186. * 測試OrFilter的用法
187. */
188. public void testOrFilter() {
189. NodeFilter inputFilter = new NodeClassFilter(InputTag.class);
190. NodeFilter selectFilter = new NodeClassFilter(SelectTag.class);
191. Parser myParser;
192. NodeList nodeList = null;
193.
194. try {
195. Parser parser = new Parser();
196. parser
197. .setInputHTML(」<head><title>OrFilter Test</title>」
198. + 「<link href=’/test01/css.css’ text=’text/css’ rel=’stylesheet’ />」
199. + 「<link href=’/test02/css.css’ text=’text/css’ rel=’stylesheet’ />」
200. + 「</head>」
201. + 「<body>」
202. + 「<input type=’text’ value=’text1′ name=’text1′/>」
203. + 「<input type=’text’ value=’text2′ name=’text2′/>」
204. + 「<select><option id=’1′>1</option><option id=’2′>2</option><option id=’3′></option></select>」
205. + 「<a href=’http://www.yeeach.com’>yeeach.com</a>」
206. + 「</body>」);
207.
208. parser.setEncoding(parser.getEncoding());
209. OrFilter lastFilter = new OrFilter();
210. lastFilter.setPredicates(new NodeFilter[] { selectFilter,
211. inputFilter });
212. nodeList = parser.parse(lastFilter);
213. for (int i = 0; i <= nodeList.size(); i++) {
214. if (nodeList.elementAt(i) instanceof InputTag) {
215. InputTag tag = (InputTag) nodeList.elementAt(i);
216. logger.fatal(」OrFilter tag name is :」 + tag.getTagName()
217. + 」 ,tag value is:」 + tag.getAttribute(」value」));
218. }
219. if (nodeList.elementAt(i) instanceof SelectTag) {
220. SelectTag tag = (SelectTag) nodeList.elementAt(i);
221. NodeList list = tag.getChildren();
222.
223. for (int j = 0; j < list.size(); j++) {
224. OptionTag option = (OptionTag) list.elementAt(j);
225. logger
226. .fatal(」OrFilter Option」
227. + option.getOptionText());
228. }
229.
230. }
231. }
232.
233. } catch (ParserException e) {
234. e.printStackTrace();
235. }
236. }
237. /*
238. * 測試對<table><tr><td></td></tr></table>的解析
239. */
240. public void testTable() {
241. Parser myParser;
242. NodeList nodeList = null;
243. myParser = Parser.createParser(」<body> 」 + 「<table id=’table1′ >」
244. + 「<tr><td>1-11</td><td>1-12</td><td>1-13</td>」
245. + 「<tr><td>1-21</td><td>1-22</td><td>1-23</td>」
246. + 「<tr><td>1-31</td><td>1-32</td><td>1-33</td></table>」
247. + 「<table id=’table2′ >」
248. + 「<tr><td>2-11</td><td>2-12</td><td>2-13</td>」
249. + 「<tr><td>2-21</td><td>2-22</td><td>2-23</td>」
250. + 「<tr><td>2-31</td><td>2-32</td><td>2-33</td></table>」
251. + 「</body>」, 「GBK」);
252. NodeFilter tableFilter = new NodeClassFilter(TableTag.class);
253. OrFilter lastFilter = new OrFilter();
254. lastFilter.setPredicates(new NodeFilter[] { tableFilter });
255. try {
256. nodeList = myParser.parse(lastFilter);
257. for (int i = 0; i <= nodeList.size(); i++) {
258. if (nodeList.elementAt(i) instanceof TableTag) {
259. TableTag tag = (TableTag) nodeList.elementAt(i);
260. TableRow[] rows = tag.getRows();
261.
262. for (int j = 0; j < rows.length; j++) {
263. TableRow tr = (TableRow) rows[j];
264. TableColumn[] td = tr.getColumns();
265. for (int k = 0; k < td.length; k++) {
266. logger.fatal(」<td>」 + td[k].toPlainTextString());
267. }
268.
269. }
270.
271. }
272. }
273.
274. } catch (ParserException e) {
275. e.printStackTrace();
276. }
277. }
278. /*
279. * 測試NodeVisitor的用法,遍歷全部節點
280. */
281. public void testVisitorAll() {
282. try {
283. Parser parser = new Parser();
284. parser.setURL(」http://www.google.com」);
285. parser.setEncoding(parser.getEncoding());
286. NodeVisitor visitor = new NodeVisitor() {
287. public void visitTag(Tag tag) {
288. logger.fatal(」testVisitorAll() Tag name is :」
289. + tag.getTagName() + 」 \n Class is :」
290. + tag.getClass());
291. }
292.
293. };
294.
295. parser.visitAllNodesWith(visitor);
296. } catch (ParserException e) {
297. e.printStackTrace();
298. }
299. }
300. /*
301. * 測試對指定Tag的NodeVisitor的用法
302. */
303. public void testTagVisitor() {
304. try {
305.
306. Parser parser = new Parser(
307. 「<head><title>dddd</title>」
308. + 「<link href=’/test01/css.css’ text=’text/css’ rel=’stylesheet’ />」
309. + 「<link href=’/test02/css.css’ text=’text/css’ rel=’stylesheet’ />」
310. + 「</head>」 + 「<body>」
311. + 「<a href=’http://www.yeeach.com’>yeeach.com</a>」
312. + 「</body>」);
313. NodeVisitor visitor = new NodeVisitor() {
314. public void visitTag(Tag tag) {
315. if (tag instanceof HeadTag) {
316. logger.fatal(」visitTag() HeadTag : Tag name is :」
317. + tag.getTagName() + 」 \n Class is :」
318. + tag.getClass() + 「\n Text is :」
319. + tag.getText());
320. } else if (tag instanceof TitleTag) {
321. logger.fatal(」visitTag() TitleTag : Tag name is :」
322. + tag.getTagName() + 」 \n Class is :」
323. + tag.getClass() + 「\n Text is :」
324. + tag.getText());
325.
326.
327. } else if (tag instanceof LinkTag) {
328. logger.fatal(」visitTag() LinkTag : Tag name is :」
329. + tag.getTagName() + 」 \n Class is :」
330. + tag.getClass() + 「\n Text is :」
331. + tag.getText() + 」 \n getAttribute is :」
332. + tag.getAttribute(」href」));
333. } else {
334. logger.fatal(」visitTag() : Tag name is :」
335. + tag.getTagName() + 」 \n Class is :」
336. + tag.getClass() + 「\n Text is :」
337. + tag.getText());
338. }
339.
340. }
341.
342. };
343.
344. parser.visitAllNodesWith(visitor);
345. } catch (Exception e) {
346. e.printStackTrace();
347. }
348. }
349. /*
350. * 測試HtmlPage的用法
351. */
352. public void testHtmlPage() {
353. String inputHTML = 「<html>」 + 「<head>」
354. + 「<title>Welcome to the HTMLParser website</title>」
355. + 「</head>」 + 「<body>」 + 「Welcome to HTMLParser」
356. + 「<table id=’table1′ >」
357. + 「<tr><td>1-11</td><td>1-12</td><td>1-13</td>」
358. + 「<tr><td>1-21</td><td>1-22</td><td>1-23</td>」
359. + 「<tr><td>1-31</td><td>1-32</td><td>1-33</td></table>」
360. + 「<table id=’table2′ >」
361. + 「<tr><td>2-11</td><td>2-12</td><td>2-13</td>」
362. + 「<tr><td>2-21</td><td>2-22</td><td>2-23</td>」
363. + 「<tr><td>2-31</td><td>2-32</td><td>2-33</td></table>」
364. + 「</body>」 + 「</html>」;
365. Parser parser = new Parser();
366. try {
367. parser.setInputHTML(inputHTML);
368. parser.setEncoding(parser.getURL());
369. HtmlPage page = new HtmlPage(parser);
370. parser.visitAllNodesWith(page);
371. logger.fatal(」testHtmlPage -title is :」 + page.getTitle());
372. NodeList list = page.getBody();
373.
374. for (NodeIterator iterator = list.elements(); iterator
375. .hasMoreNodes();) {
376. Node node = iterator.nextNode();
377. logger.fatal(」testHtmlPage -node is :」 + node.toHtml());
378. }
379.
380. } catch (ParserException e) {
381. // TODO Auto-generated catch block
382. e.printStackTrace();
383. }
384. }
385. /*
386. * 測試LinkBean的用法
387. */
388. public void testLinkBean() {
389. Parser parser = new Parser();
390.
391. LinkBean linkBean = new LinkBean();
392. linkBean.setURL(」http://www.google.com」);
393. URL[] urls = linkBean.getLinks();
394.
395. for (int i = 0; i < urls.length; i++) {
396. URL url = urls[i];
397. logger.fatal(」testLinkBean() -url is :」 + url);
398. }
399.
400. }
401.
402.}
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
/**
* 基本能實現網頁抓取,不過要手動輸入URL 將整個html內容保存到指定文件
*
*@author chenguoyong
*
*/
public class ScrubSelectedWeb {
privatefinal static String CRLF = System.getProperty("line.separator");
/**
* @param args
*/
publicstatic void main(String[] args) {
try{
URLur = newURL("http://10.249.187.199:8083/injs100/");
InputStreaminstr = ur.openStream();
Strings, str;
BufferedReaderin = new BufferedReader(new InputStreamReader(instr));
StringBuffersb = new StringBuffer();
BufferedWriterout = new BufferedWriter(new FileWriter(
"D:/outPut.txt"));
while((s = in.readLine()) != null) {
sb.append(s+ CRLF);
}
System.out.println(sb);
str= new String(sb);
out.write(str);
out.close();
in.close();
}catch (MalformedURLException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}
}
}
基本能實現網頁抓取,不過要手動輸入URL,此外沒有重構。只是一個簡單的思路。
1.htmlparser 使用
htmlparser是一個純的java寫的html解析的庫,htmlparser不依賴於其它的java庫,htmlparser主要用於改造 或提取html。htmlparser能超高速解析html,並且不會出錯。絕不誇張地說,htmlparser就是目前最好的html解 析和分析的工具。不管你是想抓取網頁數據仍是改造html的內容,用了htmlparser絕對會忍不住稱讚。因爲htmlparser 結構設計精良,因此擴展htmlparser 很是便利。
Htmlparser中文論壇. http://bbs.hexiao.cn/thread.php?fid=6
Constructor Summary |
Parser()
Parser(URLConnection connection)
Construct a parserusing the provided URLConnection.
Method:
static Parser createParser(String html,String charset)
Creates the parseron an input string.
void visitAllNodesWith(NodeVisitor visitor)
Apply the givenvisitor to the current page.
getBody() |
|
TableTag[] |
|
getTitle() |
|
void |
|
void |
Constructor Summary |
|
NodeList() |
|
|
NodeList extractAllNodesThatMatch(NodeFilter filter)
Filter the listwith the given filter non-recursively.
NodeList extractAllNodesThatMatch(NodeFilter filter,boolean recursive)
Filter the listwith the given filter.
1.html代碼裏面全部的連接地址和連接名稱
package parser;
import org.htmlparser.Parser;
import org.htmlparser.Node;
import org.htmlparser.NodeFilter;
import org.htmlparser.Parser;
importorg.htmlparser.filters.TagNameFilter;
import org.htmlparser.tags.LinkTag;
import org.htmlparser.tags.TableTag;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.ParserException;
import org.htmlparser.visitors.HtmlPage;
/**
*htmlparser取得一段html代碼裏面全部的連接地址和連接名稱
*
*@author chenguoyong
*
*/
public class Testhtmlparser {
/**
* @param args
*/
publicstatic void main(String[] args) {
Stringhtmlcode ="<HTML><HEAD><TITLE>AAA</TITLE></HEAD><BODY>"
+"<a href='http://topic.csdn.net/u/20080522/14/0ff402ef-c382-499a-8213-ba6b2f550425.html'>鏈接1</a>"
+"<a href='http://topic.csdn.net'>鏈接2</a></BODY></HTML>";
//建立Parser對象根據傳給字符串和指定的編碼
Parserparser = Parser.createParser(htmlcode, "GBK");
//建立HtmlPage對象HtmlPage(Parser parser)
HtmlPagepage = new HtmlPage(parser);
try{
//HtmlPage extends visitor,Apply the given visitor to the current
//page.
parser.visitAllNodesWith(page);
}catch (ParserException e1) {
e1= null;
}
//全部的節點
NodeListnodelist = page.getBody();
//創建一個節點filter用於過濾節點
NodeFilterfilter = new TagNameFilter("A");
//獲得全部過濾後,想要的節點
nodelist= nodelist.extractAllNodesThatMatch(filter, true);
for(int i = 0; i < nodelist.size(); i++) {
LinkTaglink = (LinkTag) nodelist.elementAt(i);
//連接地址
System.out.println(link.getAttribute("href")+ "\n");
//連接名稱
System.out.println(link.getStringText());
}
}
}
結果以下:
http://topic.csdn.net/u/20080522/14/0ff402ef-c382-499a-8213-ba6b2f550425.html
鏈接1
鏈接2
2. 使用HtmlParser抓去網頁內容
package parser;
import org.htmlparser.Parser;
import org.htmlparser.beans.StringBean;
importorg.htmlparser.filters.NodeClassFilter;
importorg.htmlparser.parserapplications.StringExtractor;
import org.htmlparser.tags.BodyTag;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.ParserException;
/**
* 使用HtmlParser抓去網頁內容: 要抓去頁面的內容最方便的方法就是使用StringBean. 裏面有幾個控制頁面內容的幾個參數.
* 在後面的代碼中會有說明. Htmlparser包中還有一個示例StringExtractor 裏面有個直接獲得內容的方法,
* 其中也是使用了StringBean . 另外直接解析Parser的每一個標籤也能夠的.
*
*@author chenguoyong
*
*/
public class GetContent {
publicvoid getContentUsingStringBean(String url) {
StringBeansb = new StringBean();
sb.setLinks(true);// 是否顯示web頁面的鏈接(Links)
//爲了取得頁面的整潔美觀通常設置上面兩項爲true , 若是要保持頁面的原有格式, 如代碼頁面的空格縮進 能夠設置爲false
sb.setCollapse(true);// 若是是true的話把一系列空白字符用一個字符替代.
sb.setReplaceNonBreakingSpaces(true);//If true regular space
sb
.setURL("http://www.blogjava.net/51AOP/archive/2006/07/19/59064.html");
System.out.println("TheContent is :\n" + sb.getStrings());
}
publicvoid getContentUsingStringExtractor(String url, boolean link) {
//StringExtractor內部機制和上面的同樣.作了一下包裝
StringExtractorse = new StringExtractor(url);
Stringtext = null;
try{
text= se.extractStrings(link);
System.out.println("Thecontent is :\n" + text);
}catch (ParserException e) {
e.printStackTrace();
}
}
publicvoid getContentUsingParser(String url) {
NodeListnl;
try{
Parserp = new Parser(url);
nl= p.parse(new NodeClassFilter(BodyTag.class));
BodyTagbt = (BodyTag) nl.elementAt(0);
System.out.println(bt.toPlainTextString());// 保留原來的內容格式. 包含js代碼
}catch (ParserException e) {
e.printStackTrace();
}
}
/**
* @param args
*/
publicstatic void main(String[] args) {
Stringurl = "http://www.blogjava.net/51AOP/archive/2006/07/19/59064.html";
//newGetContent().getContentUsingParser(url);
//--------------------------------------------------
newGetContent().getContentUsingStringBean(url);
}
}
3.將整個html內容保存到指定文件
package parser;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
/**
* 基本能實現網頁抓取,不過要手動輸入URL 將整個html內容保存到指定文件
*
*@author chenguoyong
*
*/
public class ScrubSelectedWeb {
privatefinal static String CRLF = System.getProperty("line.separator");
/**
* @param args
*/
publicstatic void main(String[] args) {
try{
URLur = newURL("http://www.google.cn/");
InputStreaminstr = ur.openStream();
Strings, str;
BufferedReaderin = new BufferedReader(new InputStreamReader(instr));
StringBuffersb = new StringBuffer();
BufferedWriterout = new BufferedWriter(new FileWriter(
"D:/outPut.txt"));
while((s = in.readLine()) != null) {
sb.append(s+ CRLF);
}
System.out.println(sb);
str= new String(sb);
out.write(str);
out.close();
in.close();
}catch (MalformedURLException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}
}
}
4利用htmlparser提取網頁純文本的例子
package parser;
import org.htmlparser.Node;
import org.htmlparser.NodeFilter;
import org.htmlparser.Parser;
importorg.htmlparser.filters.TagNameFilter;
import org.htmlparser.tags.TableTag;
import org.htmlparser.util.NodeList;
/**
* 標題:利用htmlparser提取網頁純文本的例子
*/
public class TestHTMLParser2 {
/**
* 讀取目標html內容
*
*/
publicstatic void testHtml() {
try{
StringsCurrentLine;
StringsTotalString;
sCurrentLine= "";
sTotalString= "";
java.io.InputStreaml_urlStream;
java.net.URLl_url = new java.net.URL(
"http://10.249.187.199:8083/injs100/");
java.net.HttpURLConnectionl_connection = (java.net.HttpURLConnection) l_url
.openConnection();
l_connection.connect();
l_urlStream= l_connection.getInputStream();
java.io.BufferedReaderl_reader = new java.io.BufferedReader(
newjava.io.InputStreamReader(l_urlStream));
while((sCurrentLine = l_reader.readLine()) != null) {
sTotalString+= sCurrentLine + "\r\n";
}
StringtestText = extractText(sTotalString);
}catch (Exception e) {
e.printStackTrace();
}
}
/**
* 抽取純文本信息
* @param inputHtml:html文本
* @return
* @throws Exception
*/
publicstatic String extractText(String inputHtml) throws Exception {
StringBuffertext = new StringBuffer();
Parserparser = Parser.createParser(new String(inputHtml.getBytes(),
"GBK"),"GBK");
//遍歷全部的節點
NodeListnodes = parser.extractAllNodesThatMatch(new NodeFilter() {
publicboolean accept(Node node) {
returntrue;
}
});
System.out.println(nodes.size());
for(int i = 0; i < nodes.size(); i++) {
Nodenodet = nodes.elementAt(i);
//字符串的表明性節點:節點的描述
text.append(newString(nodet.toPlainTextString().getBytes("GBK"))
+"\r\n");
}
returntext.toString();
}
/**
* 讀取文件的方式/utl 來分析內容.filePath也能夠是一個Url.
* @param resource :文件/Url
* @throws Exception
*/
publicstatic void test5(String resource) throws Exception {
ParsermyParser = new Parser(resource);
myParser.setEncoding("GBK");
StringfilterStr = "table";
NodeFilterfilter = new TagNameFilter(filterStr);
NodeListnodeList = myParser.extractAllNodesThatMatch(filter);
/*for(inti=0;i<nodeList.size();i++)
{
TableTagtabletag = (TableTag) nodeList.elementAt(i);
//標籤名稱
System.out.println(tabletag.getTagName());
System.out.println(tabletag.getText());
}*/
TableTagtabletag = (TableTag) nodeList.elementAt(1);
}
publicstatic void main(String[] args) throws Exception {
test5("http://10.249.187.199:8083/injs100/");
//testHtml();
}
}
5.html解析table
package parser;
import org.apache.log4j.Logger;
import org.htmlparser.NodeFilter;
import org.htmlparser.Parser;
importorg.htmlparser.filters.NodeClassFilter;
import org.htmlparser.filters.OrFilter;
importorg.htmlparser.filters.TagNameFilter;
import org.htmlparser.tags.TableColumn;
import org.htmlparser.tags.TableRow;
import org.htmlparser.tags.TableTag;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.ParserException;
import junit.framework.TestCase;
public class ParserTestCase extendsTestCase {
privatestatic final Logger logger = Logger.getLogger(ParserTestCase.class);
publicParserTestCase(String name) {
super(name);
}
/**
* 測試對<table>
* <tr>
* <td></td>
* </tr>
* </table>的解析
*/
publicvoid testTable() {
ParsermyParser;
NodeListnodeList = null;
myParser= Parser
.createParser(
"<body>"
+"<table id=’table1′ >"
+"<tr id='tro1'><td>1-11</td><td>1-12</td><td>1-13</td></tr>"
+"<trid='tro2'><td>1-21</td><td>1-22</td><td>1-23</td></tr>"
+"<trid='tro3'><td>1-31</td><td>1-32</td><td>1-33</td></tr></table>"
+"<table id=’table2′ >"
+"<tr id='tro4'><td>2-11</td><td>2-12</td><td>2-13</td></tr>"
+"<trid='tro5'><td>2-21</td><td>2-22</td><td>2-23</td></tr>"
+"<trid='tro6'><td>2-31</td><td>2-32</td><td>2-33</td></tr></table>"
+"</body>", "GBK");
NodeFiltertableFilter = new NodeClassFilter(TableTag.class);
OrFilterlastFilter = new OrFilter();
lastFilter.setPredicates(newNodeFilter[] { tableFilter });
try{
nodeList= myParser.parse(lastFilter);
for(int i = 0; i <= nodeList.size(); i++) {
if(nodeList.elementAt(i) instanceof TableTag) {
TableTagtag = (TableTag) nodeList.elementAt(i);
TableRow[]rows = tag.getRows();
for(int j = 0; j < rows.length; j++) {
TableRowtr = (TableRow) rows[j];
System.out.println(tr.getAttribute("id"));
if(tr.getAttribute("id").equalsIgnoreCase("tro1")) {
TableColumn[]td = tr.getColumns();
for(int k = 0; k < td.length; k++) {
//logger.fatal("<td>" +
//td[k].toPlainTextString());
System.out.println("<td>"
+td[k].toPlainTextString());
}
}
}
}
}
}catch (ParserException e) {
e.printStackTrace();
}
}
/**
* 獲得目標數據
*
* @param url:目標url
* @throws Exception
*/
publicstatic void getDatabyUrl(String url) throws Exception {
ParsermyParser = new Parser(url);
NodeListnodeList = null;
myParser.setEncoding("gb2312");
NodeFiltertableFilter = new NodeClassFilter(TableTag.class);
OrFilterlastFilter = new OrFilter();
lastFilter.setPredicates(newNodeFilter[] { tableFilter });
try{
nodeList= myParser.parse(lastFilter);
//能夠從數據table的size:19-21開始到結束
for(int i = 15; i <= nodeList.size(); i++) {
if(nodeList.elementAt(i) instanceof TableTag) {
TableTagtag = (TableTag) nodeList.elementAt(i);
TableRow[]rows = tag.getRows();
for(int j = 0; j < rows.length; j++) {
TableRowtr = (TableRow) rows[j];
if(tr.getAttribute("id") != null
&&tr.getAttribute("id").equalsIgnoreCase(
"tr02")){
TableColumn[]td = tr.getColumns();
//對不起,沒有你要查詢的記錄!
if(td.length == 1) {
System.out.println("對不起,沒有你要查詢的記錄");
}else {
for(int k = 0; k < td.length; k++) {
System.out.println("<td>內容:"
+td[k].toPlainTextString().trim());
}
}
}
}
}
}
}catch (ParserException e) {
e.printStackTrace();
}
}
/**
* 測試已經得出有數據時table:22個,沒有數據時table:19個
*
* @param args
*/
publicstatic void main(String[] args) {
try{
//getDatabyUrl("http://gd.12530.com/user/querytonebytype.do?field=tonecode&condition=619505000000008942&type=1006&pkValue=619505000000008942");
getDatabyUrl("http://gd.12530.com/user/querytonebytype.do?field=tonecode&condition=619272000000001712&type=1006&pkValue=619272000000001712");
}catch (Exception e) {
e.printStackTrace();
}
}
}
6.html解析經常使用
package com.jscud.test;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import org.htmlparser.Node;
import org.htmlparser.NodeFilter;
import org.htmlparser.Parser;
import org.htmlparser.filters.NodeClassFilter;
import org.htmlparser.filters.OrFilter;
import org.htmlparser.nodes.TextNode;
import org.htmlparser.tags.LinkTag;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.ParserException;
import org.htmlparser.visitors.HtmlPage;
import org.htmlparser.visitors.TextExtractingVisitor;
import com.jscud.util.LogMan; //一個日誌記錄類
/**
* 演示了Html Parse的應用.
*
* @author scud http://www.jscud.com (http://www.jscud.com/)
*/
public class ParseHtmlTest
{
public static void main(String[] args) throws Exception
{
String aFile = "e:/jscud/temp/test.htm";
String content = readTextFile(aFile, "GBK");
test1(content);
System.out.println("====================================");
test2(content);
System.out.println("====================================");
test3(content);
System.out.println("====================================");
test4(content);
System.out.println("====================================");
test5(aFile);
System.out.println("====================================");
//訪問外部資源,相對慢
test5("http://www.jscud.com (http://www.jscud.com/)");
System.out.println("====================================");
}
/**
* 讀取文件的方式來分析內容.
* filePath也能夠是一個Url.
*
* @param resource 文件/Url
*/
public static void test5(String resource) throws Exception
{
Parser myParser = new Parser(resource);
//設置編碼
myParser.setEncoding("GBK");
HtmlPage visitor = new HtmlPage(myParser);
myParser.visitAllNodesWith(visitor);
String textInPage = visitor.getTitle();
System.out.println(textInPage);
}
/**
* 按頁面方式處理.對一個標準的Html頁面,推薦使用此種方式.
*/
public static void test4(String content) throws Exception
{
Parser myParser;
myParser = Parser.createParser(content, "GBK");
HtmlPage visitor = new HtmlPage(myParser);
myParser.visitAllNodesWith(visitor);
String textInPage = visitor.getTitle();
System.out.println(textInPage);
}
/**
* 利用Visitor模式解析html頁面.
*
* 小優勢:翻譯了<>等符號
* 缺點:好多空格,沒法提取link
*
*/
public static void test3(String content) throws Exception
{
Parser myParser;
myParser = Parser.createParser(content, "GBK");
TextExtractingVisitor visitor = new TextExtractingVisitor();
myParser.visitAllNodesWith(visitor);
String textInPage = visitor.getExtractedText();
System.out.println(textInPage);
}
/**
* 獲得普通文本和連接的內容.
*
* 使用了過濾條件.
*/
public static void test2(String content) throws ParserException
{
Parser myParser;
NodeList nodeList = null;
myParser = Parser.createParser(content, "GBK");
NodeFilter textFilter = new NodeClassFilter(TextNode.class);
NodeFilter linkFilter = new NodeClassFilter(LinkTag.class);
//暫時不處理 meta
//NodeFilter metaFilter = new NodeClassFilter(MetaTag.class);
OrFilter lastFilter = new OrFilter();
lastFilter.setPredicates(new NodeFilter[] { textFilter, linkFilter });
nodeList = myParser.parse(lastFilter);
Node[] nodes = nodeList.toNodeArray();
for (int i = 0; i < nodes.length; i++)
{
Node anode = (Node) nodes[i];
String line = "";
if (anode instanceof TextNode)
{
TextNode textnode = (TextNode) anode;
//line = textnode.toPlainTextString().trim();
line = textnode.getText();
}
else if (anode instanceof LinkTag)
{
LinkTag linknode = (LinkTag) anode;
line = linknode.getLink();
//@todo ("") 過濾jsp標籤:能夠本身實現這個函數
//line = StringFunc.replace(line, "<%.*%>", "");
}
if (isTrimEmpty(line))
continue;
System.out.println(line);
}
}
/**
* 解析普通文本節點.
*
* @param content
* @throws ParserException
*/
public static void test1(String content) throws ParserException
{
Parser myParser;
Node[] nodes = null;
myParser = Parser.createParser(content, null);
nodes = myParser.extractAllNodesThatAre(TextNode.class); //exception could bethrown here
for (int i = 0; i < nodes.length; i++)
{
TextNode textnode = (TextNode) nodes[i];
String line = textnode.toPlainTextString().trim();
if (line.equals(""))
continue;
System.out.println(line);
}
}
/**
* 讀取一個文件到字符串裏.
*
* @param sFileName 文件名
* @param sEncode String
* @return 文件內容
*/
public static String readTextFile(String sFileName, String sEncode)
{
StringBuffer sbStr = new StringBuffer();
try
{
File ff = new File(sFileName);
InputStreamReader read = new InputStreamReader(new FileInputStream(ff),
sEncode);
BufferedReader ins = new BufferedReader(read);
String dataLine = "";
while (null != (dataLine = ins.readLine()))
{
sbStr.append(dataLine);
sbStr.append("\r\n");
}
ins.close();
}
catch (Exception e)
{
LogMan.error("read Text File Error", e);
}
return sbStr.toString();
}
/**
* 去掉左右空格後字符串是否爲空
* @param astr String
* @return boolean
*/
public static boolean isTrimEmpty(String astr)
{
if ((null == astr) || (astr.length() == 0))
{
return true;
}
if (isBlank(astr.trim()))
{
return true;
}
return false;
}
/**
* 字符串是否爲空:null或者長度爲0.
* @param astr 源字符串.
* @return boolean
*/
public static boolean isBlank(String astr)
{
if ((null == astr) || (astr.length() == 0))
{
return true;
}
else
{
return false;
}
}
}
2.使用 HttpClient 和 HtmlParser 實現簡易爬蟲
本小結簡單的介紹一下HttpClinet 和 HtmlParser 兩個開源的項目,以及他們的網站和提供下載的地址。
HttpClient 簡介
HTTP 協議是如今的因特網最重要的協議之一。除了 WEB 瀏覽器以外, WEB 服務,基於網絡的應用程序以及日益增加的網絡計算不斷擴展着 HTTP 協議的角色,使得愈來愈多的應用程序須要 HTTP 協議的支持。雖然 JAVA 類庫 .net 包提供了基本功能, 來使用 HTTP 協議訪問網絡資源,可是其靈活性和功能遠不能知足不少應用程序的須要。而 Jakarta Commons HttpClient 組件尋求提供更爲靈活,更加高效的 HTTP 協議支持,簡化基於 HTTP協議的應用程序的建立。HttpClient 提供了不少的特性,支持最新的HTTP 標準,能夠訪問這裏瞭解更多關於 HttpClinet 的詳細信息。目前有不少的開源項目都用到了 HttpClient 提供的 HTTP功能,登錄網址能夠查看這些項目。本文中使用 HttpClinet 提供的類庫來訪問和下載 Internet上面的網頁,在後續部分會詳細介紹到其提供的兩種請求網絡資源的方法: Get 請求和 Post 請求。Apatche 提供免費的 HTTPClien t源碼和 JAR 包下載,能夠登錄這裏 下載最新的HttpClient 組件。筆者使用的是 HttpClient3.1。
HtmlParser 簡介
當今的 Internet 上面有數億記的網頁,愈來愈多應用程序將這些網頁做爲分析和處理的數據對象。這些網頁多爲半結構化的文本,有着大量的標籤和嵌套的結構。當咱們本身開發一些處理網頁的應用程序時,會想到要開發一個單獨的網頁解析器,這一部分的工做一定須要付出至關的精力和時間。事實上,作爲 JAVA 應用程序開發者,HtmlParser 爲其提供了強大而靈活易用的開源類庫,大大節省了寫一個網頁解析器的開銷。 HtmlParser 是 http://sourceforge.net 上活躍的一個開源項目,它提供了線性和嵌套兩種方式來解析網頁,主要用於 html 網頁的轉換(Transformation)以及網頁內容的抽取(Extraction)。HtmlParser 有以下一些易於使用的特性:過濾器 (Filters),訪問者模式 (Visitors),處理自定義標籤以及易於使用的 JavaBeans。正如 HtmlParser 首頁所說:它是一個快速,健壯以及嚴格測試過的組件;以它設計的簡潔,程序運行的速度以及處理 Internet 上真實網頁的能力吸引着愈來愈多的開發者。本文中就是利用HtmlParser 裏提取網頁裏的連接,實現簡易爬蟲裏的關鍵部分。HtmlParser 最新的版本是HtmlParser1.6,能夠登錄這裏下載其源碼、 API 參考文檔以及 JAR 包。
簡單強大的 StringBean
若是你想要網頁中去掉全部的標籤後剩下的文本,那就是用 StringBean 吧。如下簡單的代碼能夠幫你解決這樣的問題:
清單5
StringBeansb = new StringBean();
sb.setLinks(false);//設置結果中去點連接
sb.setURL(url);//設置你所須要濾掉網頁標籤的頁面 url
System.out.println(sb.getStrings());//打印結果
HtmlParser 提供了強大的類庫來處理網頁,因爲本文旨在簡單的介紹,所以只是將與筆者後續爬蟲部分有關的關鍵類庫進行了示例說明。感興趣的讀者能夠專門來研究一下 HtmlParser 更爲強大的類庫。
簡易爬蟲的實現
HttpClient 提供了便利的 HTTP 協議訪問,使得咱們能夠很容易的獲得某個網頁的源碼並保存在本地;HtmlParser提供瞭如此簡便靈巧的類庫,能夠從網頁中便捷的提取出指向其餘網頁的超連接。筆者結合這兩個開源包,構建了一個簡易的網絡爬蟲。
爬蟲 (Crawler) 原理
學過數據結構的讀者都知道有向圖這種數據結構。以下圖所示,若是將網頁當作是圖中的某一個節點,而將網頁中指向其餘網頁的連接當作是這個節點指向其餘節點的邊,那麼咱們很容易將整個 Internet 上的網頁建模成一個有向圖。理論上,經過遍歷算法遍歷該圖,能夠訪問到Internet上的幾乎全部的網頁。最簡單的遍歷就是寬度優先以及深度優先。如下筆者實現的簡易爬蟲就是使用了寬度優先的爬行策略。
圖 2. 網頁關係的建模圖
簡易爬蟲實現流程
在看簡易爬蟲的實現代碼以前,先介紹一下簡易爬蟲爬取網頁的流程。
圖 3. 爬蟲流程圖
各個類的源碼以及說明
對應上面的流程圖,簡易爬蟲由下面幾個類組成,各個類職責以下:
Crawler.java:爬蟲的主方法入口所在的類,實現爬取的主要流程。
LinkDb.java:用來保存已經訪問的 url 和待爬取的 url 的類,提供url出對入隊操做。
Queue.java: 實現了一個簡單的隊列,在 LinkDb.java 中使用了此類。
FileDownloader.java:用來下載 url 所指向的網頁。
HtmlParserTool.java: 用來抽取出網頁中的連接。
LinkFilter.java:一個接口,實現其 accept() 方法用來對抽取的連接進行過濾。
下面是各個類的源碼,代碼中的註釋有比較詳細的說明。
3.Htmlparser彙總說明
關鍵字: htmlparser
須要作一個垂直搜索引擎,比較了nekohtml和htmlparser 的功能,儘管nekohtml在容錯性、性能等方面的口碑好像比htmlparser好(htmlunit也用的是nekohtml),但感受 nekohtml的測試用例和文檔都比htmlparser都少,並且htmlparser基本上可以知足垂直搜索引擎頁面處理分析的需求,所以先研究一下htmlparser的使用,有空再研究nekohtml和mozilla html parser的使用。
html的功能仍是官方說得最爲清楚,
引用
HTML Parser is a Javalibrary used to parse HTML in either a linear or nested fashion. Primarily usedfor transformation or extraction, it features filters, visitors, custom tagsand easy to use JavaBeans. It is a fast, robust and well tested package.
The two fundamental use-cases that are handled by the parserare extraction and transformation (the syntheses use-case, where HTML pages arecreated from scratch, is better handled by other tools closer to the source ofdata). While prior versions concentrated on data extraction from web pages,Version 1.4 of the HTMLParser has substantial improvements in the area oftransforming web pages, with simplified tag creation and editing, and verbatimtoHtml() method output.
研究的重點仍是extraction的使用,有空再研究transformation的使用。
一、htmlparser對html頁面處理的數據結構
如圖所示,HtmlParser採用了經典的Composite模式,經過RemarkNode、TextNode、TagNode、AbstractNode和Tag來描述HTML頁面各元素。
* org.htmlparser.Node:
Node接口定義了進行樹形結構節點操做的各類典型操做方法,
包括:
節點到html文本、text文本的方法:toPlainTextString、toHtml
典型樹形結構遍歷的方法:getParent、getChildren、getFirstChild、getLastChild、getPreviousSibling、getNextSibling、getText
獲取節點對應的樹形結構結構的頂級節點Page對象方法:getPage
獲取節點起始位置的方法:getStartPosition、getEndPosition
Visitor方法遍歷節點時候方法:accept (NodeVisitor visitor)
Filter方法:collectInto (NodeList list, NodeFilter filter)
Object方法:toString、clone
* org.htmlparser.nodes.AbstractNode:
AbstractNode是造成HTML樹形結構抽象基類,實現了Node接口。
在htmlparser中,Node分紅三類:
RemarkNode:表明Html中的註釋
TagNode:標籤節點。
TextNode:文本節點
這三類節點都繼承AbstractNode。
* org.htmlparser.nodes.TagNode:
TagNode包含了對HTML處理的核心的各個類,是全部TAG的基類,其中有分爲包含其餘TAG的複合節點ComositeTag和不包含其餘TAG的葉子節點Tag。
複合節點CompositeTag:
AppletTag,BodyTag,Bullet,BulletList,DefinitionList,DefinitionListBullet,Div,FormTag,FrameSetTag,HeadingTag,
HeadTag,Html,LabelTag,LinkTag,ObjectTag,ParagraphTag,ScriptTag,SelectTag,Span,StyleTag,TableColumn,
TableHeader,TableRow,TableTag,TextareaTag,TitleTag
葉子節點TAG:
BaseHrefTag,DoctypeTag,FrameTag,ImageTag,InputTag,JspTag,MetaTag,ProcessingInstructionTag,
二、htmlparser對html頁面處理的算法
主要是以下幾種方式
l 採用Visitor方式訪問Html
- 三、htmlparser關鍵包結構說明
- htmlparser其實核心代碼並很少,好好研究一下其代碼,彌補文檔不足的問題。同時htmlparser的代碼註釋和單元測試用例仍是很齊全的,也有助於瞭解htmlparser的用法。
- 3.一、org.htmlparser
- 定義了htmlparser的一些基礎類。其中最爲重要的是Parser類。
- Parser 是htmlparser的最核心的類,其構造函數提供了以下:Parser.createParser (String html, String charset)、 Parser ()、Parser (Lexer lexer, ParserFeedback fb)、 Parser (URLConnection connection, ParserFeedback fb)、Parser (String resource, ParserFeedback feedback)、 Parser (String resource)
- 各構造函數的具體用法及含義能夠查看其代碼,很容易理解。
- Parser經常使用的幾個方法:
- * elements獲取元素
- Parser parser = new Parser (」http://www.google.com」);
- for (NodeIterator i = parser.elements (); i.hasMoreElements (); )
- processMyNodes (i.nextNode ());
- * parse (NodeFilter filter):經過NodeFilter方式獲取
- * visitAllNodesWith (NodeVisitor visitor):經過Nodevisitor方式
- * extractAllNodesThatMatch (NodeFilter filter):經過NodeFilter方式
- 3.二、org.htmlparser.beans
- 對Visitor和Filter的方法進行了封裝,定義了針對一些經常使用html元素操做的bean,簡化對經常使用元素的提取操做。
- 包括:FilterBean、HTMLLinkBean、HTMLTextBean、LinkBean、StringBean、BeanyBaby等。
- 3.三、org.htmlparser.nodes
- 定義了基礎的node,包括:AbstractNode、RemarkNode、TagNode、TextNode等。
- 3.四、org.htmlparser.tags
- 定義了htmlparser的各類tag。
- 3.五、org.htmlparser.filters
- 定義了htmlparser所提供的各類filter,主要經過extractAllNodesThatMatch (NodeFilter filter)來對html頁面指定類型的元素進行過濾,包括:AndFilter、 CssSelectorNodeFilter、 HasAttributeFilter、HasChildFilter、 HasParentFilter、HasSiblingFilter、 IsEqualFilter、LinkRegexFilter、 LinkStringFilter、NodeClassFilter、 NotFilter、OrFilter、RegexFilter、 StringFilter、TagNameFilter、XorFilter
- 3.六、org.htmlparser.visitors
- 定義了htmlparser所提供的各類visitor,主要經過visitAllNodesWith (NodeVisitor visitor)來對 html頁面元素進行遍歷,包括:HtmlPage、LinkFindingVisitor、NodeVisitor、 ObjectFindingVisitor、StringFindingVisitor、TagFindingVisitor、 TextExtractingVisitor、UrlModifyingVisitor
- 3.七、org.htmlparser.parserapplications
- 定義了一些實用的工具,包括LinkExtractor、SiteCapturer、StringExtractor、WikiCapturer,這幾個類也能夠做爲htmlparser使用樣例。
- 3.八、org.htmlparser.tests
- 對各類功能的單元測試用例,也能夠做爲htmlparser使用的樣例。
- 四、htmlparser的使用樣例
- import java.net.URL;
- import junit.framework.TestCase;
- import org.apache.log4j.Logger;
- import org.htmlparser.Node;
- import org.htmlparser.NodeFilter;
- import org.htmlparser.Parser;
- import org.htmlparser.Tag;
- import org.htmlparser.beans.LinkBean;
- import org.htmlparser.filters.NodeClassFilter;
- import org.htmlparser.filters.OrFilter;
- import org.htmlparser.filters.TagNameFilter;
- import org.htmlparser.tags.HeadTag;
- import org.htmlparser.tags.ImageTag;
- import org.htmlparser.tags.InputTag;
- import org.htmlparser.tags.LinkTag;
- import org.htmlparser.tags.OptionTag;
- import org.htmlparser.tags.SelectTag;
- import org.htmlparser.tags.TableColumn;
- import org.htmlparser.tags.TableRow;
- import org.htmlparser.tags.TableTag;
- import org.htmlparser.tags.TitleTag;
- import org.htmlparser.util.NodeIterator;
- import org.htmlparser.util.NodeList;
- import org.htmlparser.util.ParserException;
- import org.htmlparser.visitors.HtmlPage;
- import org.htmlparser.visitors.NodeVisitor;
- import org.htmlparser.visitors.ObjectFindingVisitor;
- public class ParserTestCase extends TestCase {
- private static final Logger logger = Logger.getLogger(ParserTestCase.class);
- public ParserTestCase(String name) {
- super(name);
- }
- /*
- * 測試ObjectFindVisitor的用法
- */
- public void testImageVisitor() {
- try {
- ImageTag imgLink;
- ObjectFindingVisitor visitor = new ObjectFindingVisitor(
- ImageTag.class);
- Parser parser = new Parser();
- parser.setURL(」http://www.google.com」);
- parser.setEncoding(parser.getEncoding());
- parser.visitAllNodesWith(visitor);
- Node[] nodes = visitor.getTags();
- for (int i = 0; i < nodes.length; i++) {
- imgLink = (ImageTag) nodes[i];
- logger.fatal(」testImageVisitor() ImageURL = 「
- + imgLink.getImageURL());
- logger.fatal(」testImageVisitor() ImageLocation = 「
- + imgLink.extractImageLocn());
- logger.fatal(」testImageVisitor() SRC = 「
- + imgLink.getAttribute(」SRC」));
- }
- }
- catch (Exception e) {
- e.printStackTrace();
- }
- }
- /*
- * 測試TagNameFilter用法
- */
- public void testNodeFilter() {
- try {
- NodeFilter filter = new TagNameFilter(」IMG」);
- Parser parser = new Parser();
- parser.setURL(」http://www.google.com」);
- parser.setEncoding(parser.getEncoding());
- NodeList list = parser.extractAllNodesThatMatch(filter);
- for (int i = 0; i < list.size(); i++) {
- logger.fatal(」testNodeFilter() 」 + list.elementAt(i).toHtml());
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- /*
- * 測試NodeClassFilter用法
- */
- public void testLinkTag() {
- try {
- NodeFilter filter = new NodeClassFilter(LinkTag.class);
- Parser parser = new Parser();
- parser.setURL(」http://www.google.com」);
- parser.setEncoding(parser.getEncoding());
- NodeList list = parser.extractAllNodesThatMatch(filter);
- for (int i = 0; i < list.size(); i++) {
- LinkTag node = (LinkTag) list.elementAt(i);
- logger.fatal(」testLinkTag() Link is :」 + node.extractLink());
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- /*
- * 測試<link href=」 text=’text/css’ rel=’stylesheet’ />用法
- */
- public void testLinkCSS() {
- try {
- Parser parser = new Parser();
- parser
- .setInputHTML(」<head><title>Link Test</title>」
- + 「<link href=’/test01/css.css’ text=’text/css’ rel=’stylesheet’ />」
- + 「<link href=’/test02/css.css’ text=’text/css’ rel=’stylesheet’ />」
- + 「</head>」 + 「<body>」);
- parser.setEncoding(parser.getEncoding());
- NodeList nodeList = null;
- for (NodeIterator e = parser.elements(); e.hasMoreNodes();) {
- Node node = e.nextNode();
- logger
- .fatal(」testLinkCSS()」 + node.getText()
- + node.getClass());
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- /*
- * 測試OrFilter的用法
- */
- public void testOrFilter() {
- NodeFilter inputFilter = new NodeClassFilter(InputTag.class);
- NodeFilter selectFilter = new NodeClassFilter(SelectTag.class);
- Parser myParser;
- NodeList nodeList = null;
- try {
- Parser parser = new Parser();
- parser
- .setInputHTML(」<head><title>OrFilter Test</title>」
- + 「<link href=’/test01/css.css’ text=’text/css’ rel=’stylesheet’ />」
- + 「<link href=’/test02/css.css’ text=’text/css’ rel=’stylesheet’ />」
- + 「</head>」
- + 「<body>」
- + 「<input type=’text’ value=’text1′ name=’text1′/>」
- + 「<input type=’text’ value=’text2′ name=’text2′/>」
- + 「<select><option id=’1′>1</option><option id=’2′>2</option><option id=’3′></option></select>」
- + 「<a href=’http://www.yeeach.com’>yeeach.com</a>」
- + 「</body>」);
- parser.setEncoding(parser.getEncoding());
- OrFilter lastFilter = new OrFilter();
- lastFilter.setPredicates(new NodeFilter[] { selectFilter,
- inputFilter });
- nodeList = parser.parse(lastFilter);
- for (int i = 0; i <= nodeList.size(); i++) {
- if (nodeList.elementAt(i) instanceof InputTag) {
- InputTag tag = (InputTag) nodeList.elementAt(i);
- logger.fatal(」OrFilter tag name is :」 + tag.getTagName()
- + 」 ,tag value is:」 + tag.getAttribute(」value」));
- }
- if (nodeList.elementAt(i) instanceof SelectTag) {
- SelectTag tag = (SelectTag) nodeList.elementAt(i);
- NodeList list = tag.getChildren();
- for (int j = 0; j < list.size(); j++) {
- OptionTag option = (OptionTag) list.elementAt(j);
- logger
- .fatal(」OrFilter Option」
- + option.getOptionText());
- }
- }
- }
- } catch (ParserException e) {
- e.printStackTrace();
- }
- }
- /*
- * 測試對<table><tr><td></td></tr></table>的解析
- */
- public void testTable() {
- Parser myParser;
- NodeList nodeList = null;
- myParser = Parser.createParser(」<body> 」 + 「<table id=’table1′ >」
- + 「<tr><td>1-11</td><td>1-12</td><td>1-13</td>」
- + 「<tr><td>1-21</td><td>1-22</td><td>1-23</td>」
- + 「<tr><td>1-31</td><td>1-32</td><td>1-33</td></table>」
- + 「<table id=’table2′ >」
- + 「<tr><td>2-11</td><td>2-12</td><td>2-13</td>」
- + 「<tr><td>2-21</td><td>2-22</td><td>2-23</td>」
- + 「<tr><td>2-31</td><td>2-32</td><td>2-33</td></table>」
- + 「</body>」, 「GBK」);
- NodeFilter tableFilter = new NodeClassFilter(TableTag.class);
- OrFilter lastFilter = new OrFilter();
- lastFilter.setPredicates(new NodeFilter[] { tableFilter });
- try {
- nodeList = myParser.parse(lastFilter);
- for (int i = 0; i <= nodeList.size(); i++) {
- if (nodeList.elementAt(i) instanceof TableTag) {
- TableTag tag = (TableTag) nodeList.elementAt(i);
- TableRow[] rows = tag.getRows();
- for (int j = 0; j < rows.length; j++) {
- TableRow tr = (TableRow) rows[j];
- TableColumn[] td = tr.getColumns();
- for (int k = 0; k < td.length; k++) {
- logger.fatal(」<td>」 + td[k].toPlainTextString());
- }
- }
- }
- }
- } catch (ParserException e) {
- e.printStackTrace();
- }
- }
- /*
- * 測試NodeVisitor的用法,遍歷全部節點
- */
- public void testVisitorAll() {
- try {
- Parser parser = new Parser();
- parser.setURL(」http://www.google.com」);
- parser.setEncoding(parser.getEncoding());
- NodeVisitor visitor = new NodeVisitor() {
- public void visitTag(Tag tag) {
- logger.fatal(」testVisitorAll() Tag name is :」
- + tag.getTagName() + 」 \n Class is :」
- + tag.getClass());
- }
- };
- parser.visitAllNodesWith(visitor);
- } catch (ParserException e) {
- e.printStackTrace();
- }
- }
- /*
- * 測試對指定Tag的NodeVisitor的用法
- */
- public void testTagVisitor() {
- try {
- Parser parser = new Parser(
- 「<head><title>dddd</title>」
- + 「<link href=’/test01/css.css’ text=’text/css’ rel=’stylesheet’ />」
- + 「<link href=’/test02/css.css’ text=’text/css’ rel=’stylesheet’ />」
- + 「</head>」 + 「<body>」
- + 「<a href=’http://www.yeeach.com’>yeeach.com</a>」
- + 「</body>」);
- NodeVisitor visitor = new NodeVisitor() {
- public void visitTag(Tag tag) {
- if (tag instanceof HeadTag) {
- logger.fatal(」visitTag() HeadTag : Tag name is :」
- + tag.getTagName() + 」 \n Class is :」
- + tag.getClass() + 「\n Text is :」
- + tag.getText());
- } else if (tag instanceof TitleTag) {
- logger.fatal(」visitTag() TitleTag : Tag name is :」
- + tag.getTagName() + 」 \n Class is :」
- + tag.getClass() + 「\n Text is :」
- + tag.getText());
- } else if (tag instanceof LinkTag) {
- logger.fatal(」visitTag() LinkTag : Tag name is :」
- + tag.getTagName() + 」 \n Class is :」
- + tag.getClass() + 「\n Text is :」
- + tag.getText() + 」 \n getAttribute is :」
- + tag.getAttribute(」href」));
- } else {
- logger.fatal(」visitTag() : Tag name is :」
- + tag.getTagName() + 」 \n Class is :」
- + tag.getClass() + 「\n Text is :」
- + tag.getText());
- }
- }
- };
- parser.visitAllNodesWith(visitor);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- /*
- * 測試HtmlPage的用法
- */
- public void testHtmlPage() {
- String inputHTML = 「<html>」 + 「<head>」
- + 「<title>Welcome to the HTMLParser website</title>」
- + 「</head>」 + 「<body>」 + 「Welcome to HTMLParser」
- + 「<table id=’table1′ >」
- + 「<tr><td>1-11</td><td>1-12</td><td>1-13</td>」
- + 「<tr><td>1-21</td><td>1-22</td><td>1-23</td>」
- + 「<tr><td>1-31</td><td>1-32</td><td>1-33</td></table>」
- + 「<table id=’table2′ >」
- + 「<tr><td>2-11</td><td>2-12</td><td>2-13</td>」
- + 「<tr><td>2-21</td><td>2-22</td><td>2-23</td>」
- + 「<tr><td>2-31</td><td>2-32</td><td>2-33</td></table>」
- + 「</body>」 + 「</html>」;
- Parser parser = new Parser();
- try {
- parser.setInputHTML(inputHTML);
- parser.setEncoding(parser.getURL());
- HtmlPage page = new HtmlPage(parser);
- parser.visitAllNodesWith(page);
- logger.fatal(」testHtmlPage -title is :」 + page.getTitle());
- NodeList list = page.getBody();
- for (NodeIterator iterator = list.elements(); iterator
- .hasMoreNodes();) {
- Node node = iterator.nextNode();
- logger.fatal(」testHtmlPage -node is :」 + node.toHtml());
- }
- } catch (ParserException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- /*
- * 測試LinkBean的用法
- */
- public void testLinkBean() {
- Parser parser = new Parser();
- LinkBean linkBean = new LinkBean();
- linkBean.setURL(」http://www.google.com」);
- URL[] urls = linkBean.getLinks();
- for (int i = 0; i < urls.length; i++) {
- URL url = urls[i];
- logger.fatal(」testLinkBean() -url is :」 + url);
- }
- }
- }