jhengfei
          愛JAVA,愛生活
          Tidy 是 W3C 用來解析網頁的一個軟件包,可以方便地將 HTML 文檔轉換為符合 XML 標準的文檔,由于 XML 可以方便地使用 XSLT 技術對內容進行抽取,所以使用 Tidy 配合 XSLT 可以方便地將各種網頁的內容抽取出來,保存成我們需要的格式。
          通過 JTidy 可以方便地將標準的 HTML 網頁轉換為 XML 的 DOM 對象,然后,通過 XPaht 和 XSLT 將需要的內容抽取出來。
          ?
          使用 JTidy 抽取網頁內容的代碼如下:
          ?
          package com.tsinghua;
          import java.io.File;
          import java.io.FileInputStream;
          import java.io.FileOutputStream;
          import java.io.IOException;
          import java.io.InputStreamReader;
          import java.io.OutputStreamWriter;
          import java.util.logging.Level;
          import java.util.logging.Logger;
          import javax.xml.parsers.DocumentBuilder;
          import javax.xml.parsers.DocumentBuilderFactory;
          import javax.xml.parsers.ParserConfigurationException;
          import javax.xml.transform.Result;
          import javax.xml.transform.Source;
          import javax.xml.transform.Templates;
          import javax.xml.transform.Transformer;
          import javax.xml.transform.TransformerConfigurationException;
          import javax.xml.transform.TransformerException;
          import javax.xml.transform.TransformerFactory;
          import javax.xml.transform.dom.DOMSource;
          import javax.xml.transform.stream.StreamResult;
          import javax.xml.transform.stream.StreamSource;
          import org.w3c.dom.Document;
          import org.w3c.dom.Element;
          import org.w3c.dom.Node;
          import org.w3c.dom.NodeList;
          import org.w3c.tidy.Configuration;
          import org.w3c.tidy.Tidy;
          import org.xml.sax.SAXException;
          public class HTMLParserByW3CDOM {
          ?private Templates template;
          ?/*
          ? * 解析網頁
          ? * XSLTFileName?用于解析網頁的樣式表文件名
          ? * HTMLFileName 待解析的網頁文件名
          ? * OutputFileName 輸出文件名
          ? */
          ?public void parser(String HTMLFileName, String OutputFileName)
          ?{
          ??if( this.template != null){
          ???Document doc =? this.HTMLToXML( HTMLFileName );?// 解析網頁,返回 W3c Document 文檔對象
          ???Transformer(doc, OutputFileName);????// 使用樣式表轉換 Document 為最終結果
          ??}
          ?}
          ?
          ?/**
          ? * 解析網頁,轉換為 W3C Document 文檔對象
          ? * @param fileName?HTML 網頁的文件名
          ? * @return???utf-8 W3C Document 文檔對象
          ? */
          ?private Document HTMLToXML(String fileName) {
          ??Logger log = Logger.getLogger("HTMLToXML");
          ??Document doc = null;
          ??try{
          ???FileInputStream in = new FileInputStream( fileName );?// 打開文件,轉換為 UTF-8 編碼?
          ???InputStreamReader isr = new InputStreamReader(in, "GB2312");?// 源文件編碼為 gb2312
          ???
          ???File tmpNewFile = File.createTempFile("GB2312",".html");?// 轉換后的文件,設定編碼為 utf-8
          ???FileOutputStream out = new FileOutputStream( tmpNewFile );?// 需要將文件轉換為字符流
          ???OutputStreamWriter osw = new OutputStreamWriter( out , "UTF-8");// 指定目標編碼為 utf-8
          ???osw.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
          ???
          ???char[] buffer = new char[10240];??????// 文件緩沖區
          ???int len = 0;???????????// 使用字符讀取方式,循環讀取源文件內容
          ???while( (len = isr.read(buffer)) !=-1 )?????// 轉換后寫入目標文件中
          ???{
          ????osw.write( buffer, 0, len);
          ???}
          ???osw.close();???????????// 轉換完成
          ???isr.close();
          ???out.close();
          ???in.close();
          ???
          ???if( log.isLoggable( Level.INFO)){
          ????log.info("HTML 文檔轉 UTF-8 編碼完成!");
          ???}
          ???
          ???//??設置 tidy ,準備轉換
          ???Tidy tidy = new Tidy();
          ???tidy.setXmlOut(true);????// 輸出格式 xml
          ???tidy.setDropFontTags(true);???// 刪除字體節點
          ???tidy.setDropEmptyParas(true);??// 刪除空段落
          ???tidy.setFixComments(true);???// 修復注釋
          ???tidy.setFixBackslash(true);???// 修復反斜桿
          ???tidy.setMakeClean(true);???// 刪除混亂的表示
          ???tidy.setQuoteNbsp(false);???// 將空格輸出為 &nbsp;
          ???tidy.setQuoteMarks(false);???// 將雙引號輸出為 &quot;
          ???tidy.setQuoteAmpersand(true);??// 將 &amp; 輸出為 &
          ???tidy.setShowWarnings(false);??// 不顯示警告信息
          ???tidy.setCharEncoding(Configuration.UTF8);?// 文件編碼為 UTF8
          ???
          ???
          ???FileInputStream src = new FileInputStream( tmpNewFile );?//
          ???doc = tidy.parseDOM( src ,null );?// 通過 JTidy 將 HTML 網頁解析為
          ???src.close();???????????// W3C 的 Document 對象
          ???tmpNewFile.delete();?????????// 刪除臨時文件
          ???
          ???NodeList list = doc.getChildNodes();?????// 頁面中 DOCTYPE 中可能問題
          ???for(int i=0; i<list.getLength(); i++)?????// 刪除 DOCTYPE 元素
          ???{
          ????Node node = list.item(i);
          ????if( node.getNodeType() == Node.DOCUMENT_TYPE_NODE)?// 查找類型定義節點
          ????{
          ?????node.getParentNode().removeChild( node );
          ?????if( log.isLoggable( Level.INFO)){
          ??????log.info("已經將文檔定義節點刪除!" );
          ?????}
          ????}
          ???}
          ???
          ???list = doc.getElementsByTagName("script");????// 腳本中的注釋有時有問題
          ???for(int i=0; i<list.getLength(); i++){?????// 清理 script 元素
          ????Element script = (Element) list.item(i);
          ????if( script.getFirstChild() != null){
          ?????if( log.isLoggable( Level.FINEST)){
          ??????log.finest("刪除腳本元素: " + script.getFirstChild().getNodeValue());
          ?????}
          ?????script.removeChild( script.getFirstChild());
          ????}
          ???}
          ???
          ???list = doc.getElementsByTagName("span");????// sina 中 span 元素有時有問題
          ???for(int i=0; i<list.getLength(); i++){?????// 清理 span 元素
          ????Element span = (Element) list.item(i);
          ????span.getParentNode().removeChild( span );
          ????if( log.isLoggable( Level.FINEST)){
          ?????log.finest("刪除 span 元素: " );
          ????}
          ????
          ???}
          ???
          ???list = doc.getElementsByTagName("sohuadcode");???// 清除 sohuadcode 元素
          ???for(int i=0; i<list.getLength(); i++){
          ????Element sohuadcode = (Element) list.item(i);
          ????sohuadcode.getParentNode().removeChild( sohuadcode );
          ???}
          ???
          ???if( log.isLoggable( Level.INFO)){
          ????log.info("HTML 文檔解析 DOM 完成.");
          ???}
          ??}
          ??catch(Exception e)
          ??{
          ???log.severe(e.getMessage());
          ???e.printStackTrace();
          ??}finally
          ??{
          ???
          ??}
          ??return doc;
          ?}
          ?
          ?/**
          ? * 解析轉換的樣式表,保存為模板
          ? * @param xsltFileName??樣式表文件名
          ? * @return?????樣式表模板對象
          ? */
          ?public Templates setXSLT(String xsltFileName)
          ?{
          ??Logger log = Logger.getLogger( "setXSLT" );
          ??File xsltFile = new File( xsltFileName );
          ??StreamSource xsltSource = new StreamSource( xsltFile );??// 使用 JAXP 標準方法建立樣式表的模板對象
          ??TransformerFactory tff = TransformerFactory.newInstance();?// 可以重復利用這個模板
          ??Templates template = null;
          ??try {
          ???template = tff.newTemplates( xsltSource );
          ???if( log.isLoggable( Level.INFO)){
          ????log.info("樣式表文件 " + xsltFileName + " 解析完成");
          ???}
          ??} catch (TransformerConfigurationException e) {
          ???log.severe( e.getMessage() );
          ??}
          ??this.template = template;
          ??return template;
          ?}
          ?
          ?/**
          ? * 使用樣式表轉換文檔對象,得到最終的結果
          ? * @param doc???文檔對象
          ? * @param outFileName?保存轉換結果的文件名
          ? */
          ?private void Transformer(Document doc , String outFileName )
          ?{
          ??Logger log = Logger.getLogger( "Transformer" );
          ??try {
          ???Source source = new DOMSource( doc );
          ???
          ???File outFile = new File( outFileName );
          ???Result result = new StreamResult( outFile );
          ???
          ???Transformer transformer = template.newTransformer();?// 使用保存的樣式表模板對象
          ???transformer.transform(source, result );?????// 生成轉換器,轉換文檔對象
          ???if( log.isLoggable( Level.INFO)){
          ????log.info("轉換完成, 請查看 " + outFileName + " 文件。");
          ???}
          ??} catch (Exception e) {
          ???log.severe( e.getMessage() );
          ??}?
          ?}
          }
          posted on 2006-03-25 11:16 點滴鑄就輝煌 閱讀(825) 評論(1)  編輯  收藏 所屬分類: 技術點滴
          Comments
          • # re: 使用 JTidy 協助抽取網頁內容
            xiaoyao
            Posted @ 2007-06-07 11:09
            還是中文亂碼問題,請問如和解決?  回復  更多評論   
           
          主站蜘蛛池模板: 肃南| 北碚区| 永嘉县| 连平县| 济南市| 财经| 鱼台县| 大宁县| 枣庄市| 柳江县| 宁晋县| 保德县| 梅河口市| 岱山县| 定陶县| 五莲县| 新余市| 凤庆县| 海丰县| 武城县| 巴彦县| 芷江| 青川县| 龙口市| 柳林县| 都江堰市| 罗山县| 正蓝旗| 涪陵区| 右玉县| 区。| 崇仁县| 普格县| 五华县| 海原县| 绥棱县| 绩溪县| 古田县| 潍坊市| 钟祥市| 宁明县|