君子博学而日参省乎己 则知明而行无过矣

博客园 首页 新随笔 联系 订阅 管理

 转载 http://blog.csdn.net/rongyongfeikai2/article/details/7798838

最近,在看博客园上的文章。希望能够爬取指定的博客园的文章,并保存为WORD文档的形式。所以,趁着周末休息,花了半天时间把它给做了出来。

完整代码下载地址:http://download.csdn.net/detail/rongyongfeikai2/4462085

首先,我们爬取的文章,应该包括三个部分:标题、链接和正文。所以,我们用一个POJO来存储文章。

  1. package com.BlogCrawler.Model;  
  2. /* 
  3.  * author:Tammy Pi 
  4.  * function:写入doc文档的类 
  5.  * Email:victory_pj@163.com 
  6.  */  
  7. public class Document {  
  8.   
  9.     //属性域,分别代表文章的标题、内容和文章的链接  
  10.     private String title;  
  11.     private String content;  
  12.     private String link;  
  13.       
  14.     public String getTitle() {  
  15.         return title;  
  16.     }  
  17.     public void setTitle(String title) {  
  18.         this.title = title;  
  19.     }  
  20.     public String getContent() {  
  21.         return content;  
  22.     }  
  23.     public void setContent(String content) {  
  24.         this.content = content;  
  25.     }  
  26.     public String getLink() {  
  27.         return link;  
  28.     }  
  29.     public void setLink(String link) {  
  30.         this.link = link;  
  31.     }  
  32. }  

定义好Document后,我们需要爬取指定URL对应的文章列表,再根据文章列表中文章所对应的链接,提取其对应的文章,并分析文章内容。

目前分析博客园列表结构,它的文章列表是放在class="post"或者class="postTitle"的div中。我们用HttpClient包爬取相应的文章后,再用HtmlParser分析DOM,提取出文章列表。对于博客园正文结构,分析得,它的正文是放在id="cnblogs_post_body",同样也可以用HttpClient包将其提取出来。

提取页面和分析页面的代码为:

  1. package com.BlogCrawler.Fetcher;  
  2. import java.io.BufferedInputStream;  
  3. import java.io.InputStream;  
  4. import java.util.*;  
  5. import java.util.regex.Pattern;  
  6. import org.apache.commons.httpclient.HttpClient;  
  7. import org.apache.commons.httpclient.HttpStatus;  
  8. import org.apache.commons.httpclient.methods.GetMethod;  
  9. import org.htmlparser.Node;  
  10. import org.htmlparser.Parser;  
  11. import org.htmlparser.filters.HasAttributeFilter;  
  12. import org.htmlparser.filters.TagNameFilter;  
  13. import org.htmlparser.util.NodeList;  
  14. import org.htmlparser.util.ParserException;  
  15. /* 
  16.  * author:Tammy Pi 
  17.  * function:用于爬取文章的类,针对于博客园 
  18.  * Email:victory_pj@163.com 
  19.  */  
  20. public class FetcherHelper {  
  21.   
  22.     //根据url爬取url指向的页面的内容,并返回  
  23.     public String getPageContent(String url){  
  24.           
  25.         StringBuffer sb = new StringBuffer();  
  26.         HttpClient httpClient = new HttpClient();  
  27.         GetMethod getMethod = new GetMethod(url);  
  28.         BufferedInputStream reader = null;  
  29.           
  30.         try{  
  31.               
  32.             int statusCode = httpClient.executeMethod(getMethod);  
  33.               
  34.             //判断状态  
  35.             if(statusCode==HttpStatus.SC_OK){  
  36.                   
  37.                 InputStream inputStream = getMethod.getResponseBodyAsStream();  
  38.                 reader = new BufferedInputStream(inputStream);  
  39.                   
  40.                 int index;  
  41.                 byte[] buffer = new byte[1024];  
  42.                   
  43.                 while((index=reader.read(buffer))!=-1){  
  44.                       
  45.                     sb.append(new String(buffer,0,index,"utf-8"));  
  46.                 }  
  47.             }else{  
  48.                   
  49.                 System.out.println("爬取出错。错误代码:"+statusCode);  
  50.             }  
  51.         }catch(Exception ex){  
  52.               
  53.             ex.printStackTrace();  
  54.         }  
  55.           
  56.         return sb.toString();  
  57.     }  
  58.       
  59.     //利用HTMLParser过滤文章内容  
  60.     public String filterContent(String page,String tag,String attr,String value){  
  61.           
  62.         TagNameFilter tagFilter = new TagNameFilter(tag);  
  63.         Parser parser = new Parser();  
  64.         parser = parser.createParser(page,"utf-8");  
  65.         NodeList tagList = null;  
  66.         String rtn = "";  
  67.           
  68.         try {  
  69.             tagList = parser.parse(tagFilter);  
  70.             for(int u=0;u<tagList.size();u++) {  
  71.                   
  72.                 String html = tagList.elementAt(u).toHtml();  
  73.                   
  74.                 HasAttributeFilter attrFilter = new HasAttributeFilter(attr,value);  
  75.                 Parser parser2 = parser.createParser(html,"utf-8");  
  76.                 NodeList list2 = parser2.parse(attrFilter);  
  77.                   
  78.                 if(list2.size()>0){  
  79.   
  80.                     rtn = list2.elementAt(0).toHtml();  
  81.                       
  82.                 }  
  83.             }  
  84.         } catch (ParserException e) {  
  85.             // TODO Auto-generated catch block  
  86.             e.printStackTrace();  
  87.         }  
  88.           
  89.         return rtn;  
  90.     }  
  91.       
  92.     //利用HTMLParser分析文章列表  
  93.     public List<com.BlogCrawler.Model.Document> htmlFilter(String page,String tag,String attr,String value){  
  94.           
  95.         String rtn = "";  
  96.         TagNameFilter tagFilter = new TagNameFilter(tag);  
  97.         Parser parser = new Parser();  
  98.         parser = parser.createParser(page,"utf-8");  
  99.         NodeList tagList = null;  
  100.         List<com.BlogCrawler.Model.Document> list = new ArrayList<com.BlogCrawler.Model.Document>();  
  101.           
  102.         try {  
  103.             tagList = parser.parse(tagFilter);  
  104.               
  105.             //遍历过滤后的tagList  
  106.             HasAttributeFilter attrFilter = new HasAttributeFilter(attr,value);  
  107.             NodeList list2 = tagList.extractAllNodesThatMatch(attrFilter);  
  108.             //过滤得到h2,针对博客园的过滤  
  109.             String html = list2.toHtml();  
  110.               
  111.             Parser parser2 = parser.createParser(html,"utf-8");  
  112.             NodeList list3 = null;  
  113.             if(value.equals("post")){  
  114.                   
  115.                 list3 = parser2.parse(new TagNameFilter("h2"));  
  116.             }else if(value.endsWith("postTitle")){  
  117.                   
  118.                 list3 = parser2.parse(new TagNameFilter("a"));  
  119.             }  
  120.               
  121.             for(int i=0;i<list3.size();i++) {  
  122.                   
  123.                 Node node = list3.elementAt(i);  
  124.                   
  125.                 com.BlogCrawler.Model.Document doc = new com.BlogCrawler.Model.Document();  
  126.                 doc.setTitle(node.toPlainTextString());  
  127.                   
  128.                 String html1 = node.toHtml();  
  129.                 html1 = html1.substring(html1.indexOf("href=\"")+6);  
  130.                 html1 = html1.substring(0,html1.indexOf("\""));  
  131.                   
  132.                 doc.setLink(html1);  
  133.                   
  134.                 //获得内容  
  135.                 doc.setContent(filterContent(getPageContent(doc.getLink()),"div","id","cnblogs_post_body"));  
  136.                 list.add(doc);  
  137.             }  
  138.               
  139.         } catch (ParserException e) {  
  140.             // TODO Auto-generated catch block  
  141.             e.printStackTrace();  
  142.         }  
  143.           
  144.         return list;  
  145.     }  
  146.       
  147.     //用于测试的主函数  
  148.     public static void main(String[] args){  
  149.           
  150.         FetcherHelper helper = new FetcherHelper();  
  151.         String rtn = helper.getPageContent("http://www.cnblogs.com/passzh/default.html?OnlyTitle=1");  
  152.           
  153.         if(rtn.indexOf("postTitle")==-1){  
  154.               
  155.             helper.htmlFilter(rtn,"div","class", "post");  
  156.         }else{  
  157.               
  158.             System.out.println("进入");  
  159.             helper.htmlFilter(rtn,"div","class", "postTitle");  
  160.         }  
  161.     }  
  162. }  

最后,我们将文章写入doc文档中,这是就是用IText.jar包,它提供了HtmlWorker类,可以很方便的将HTML按照格式写入Word文档中。写入Word文档的代码为:

  1. package com.BlogCrawler.DocHelper;  
  2. import java.awt.Color;  
  3. import java.io.*;  
  4. import com.lowagie.text.Document;  
  5. import com.lowagie.text.DocumentException;  
  6. import com.lowagie.text.Element;  
  7. import com.lowagie.text.Font;  
  8. import com.lowagie.text.PageSize;  
  9. import com.lowagie.text.Paragraph;  
  10. import com.lowagie.text.Rectangle;  
  11. import com.lowagie.text.html.simpleparser.HTMLWorker;  
  12. import com.lowagie.text.html.simpleparser.StyleSheet;  
  13. import com.lowagie.text.rtf.RtfWriter2;  
  14. import java.util.*;  
  15. /* 
  16.  * author:Tammy Pi 
  17.  * function:写入doc文档的类 
  18.  * Email:victory_pj@163.com 
  19.  */  
  20. public class DocHelper {  
  21.   
  22.     private BufferedWriter writer = null;  
  23.     private String path = "c:\\Blog\\";  
  24.     //定义A4纸张  
  25.     private Rectangle pageSize = new Rectangle(PageSize.A4);  
  26.     private Document doc = null;  
  27.       
  28.     public void docHelper(String fileName,List<com.BlogCrawler.Model.Document> list) {  
  29.           
  30.         try {  
  31.             //判断路径是否存在  
  32.             if(!new File(path).exists()){  
  33.                   
  34.                 new File(path).mkdir();  
  35.             }  
  36.             //判断文件是否存在  
  37.             if(!new File(path+fileName).exists()){  
  38.                   
  39.                 new File(path+fileName).createNewFile();  
  40.             }  
  41.               
  42.             File file = new File(path+fileName);  
  43.             if(!(file.canRead()&&file.canWrite())){  
  44.                   
  45.                 System.out.println("您不具有此word文档的读写操作权限!");  
  46.                 return;  
  47.             }  
  48.               
  49.             pageSize = pageSize.rotate();  
  50.             //创建word文档,并设置纸张大小  
  51.             doc = new Document(pageSize,80,80,50,50);  
  52.               
  53.             //创建一个word文档的书写器  
  54.             RtfWriter2.getInstance(doc,new FileOutputStream(path + fileName));  
  55.             doc.open();  
  56.               
  57.             //设置标题的格式  
  58.             Paragraph titleParagraph = null;  
  59.             Paragraph contentGraph = null;  
  60.               
  61.             //循环遍历Document  
  62.             for(int i=0;i<list.size();i++) {  
  63.                   
  64.                 com.BlogCrawler.Model.Document document = list.get(i);  
  65.                   
  66.                 //书写blog文章的头部  
  67.                 System.out.println(document.getTitle());  
  68.                 titleParagraph = new Paragraph(document.getTitle(),new Font(Font.NORMAL,18,Font.BOLD,new Color(0,0,0)));  
  69.                 //标题居中  
  70.                 titleParagraph.setAlignment(Element.ALIGN_CENTER);  
  71.                 try {  
  72.                     doc.add(titleParagraph);  
  73.                       
  74.                     //书写内容  
  75.                     StyleSheet ss = new StyleSheet();  
  76.                     List htmlList = HTMLWorker.parseToList(new StringReader(document.getContent()), ss);  
  77.                       
  78.                     for(int j=0;j<htmlList.size();j++) {  
  79.                           
  80.                         Element e = (Element) htmlList.get(j);  
  81.                         Paragraph par = new Paragraph();  
  82.                         par.add(e);  
  83.                           
  84.                         doc.add(par);  
  85.                     }  
  86.                 } catch (DocumentException e) {  
  87.                     // TODO Auto-generated catch block  
  88.                     e.printStackTrace();  
  89.                 }  
  90.             }  
  91.               
  92.         } catch (IOException e) {  
  93.             // TODO Auto-generated catch block  
  94.             e.printStackTrace();  
  95.         } finally{  
  96.               
  97.             if(writer!=null){  
  98.                   
  99.                 //关闭文件输出流  
  100.                 try {  
  101.                     writer.close();  
  102.                 } catch (IOException e) {  
  103.                     // TODO Auto-generated catch block  
  104.                     e.printStackTrace();  
  105.                 }  
  106.             }  
  107.               
  108.             if(doc!=null){  
  109.                   
  110.                 doc.close();  
  111.             }  
  112.         }  
  113.     }  
  114.       
  115.     public static void main(String[] args){  
  116.           
  117.         DocHelper docHelper = new DocHelper();  
  118.           
  119.         com.BlogCrawler.Model.Document doc1 = new com.BlogCrawler.Model.Document();  
  120.         doc1.setTitle("标题1");  
  121.         doc1.setContent("内容1");  
  122.           
  123.         com.BlogCrawler.Model.Document doc2 = new com.BlogCrawler.Model.Document();  
  124.         doc2.setTitle("标题2");  
  125.         doc2.setContent("内容2");  
  126.           
  127.         List<com.BlogCrawler.Model.Document> list = new ArrayList<com.BlogCrawler.Model.Document>();  
  128.         list.add(doc1);  
  129.         list.add(doc2);  
  130.         docHelper.docHelper("卧龙居.doc",list);  
  131.           
  132.         System.out.println("word文档书写完成!");  
  133.     }  
  134. }  

最后,程序要运行,自然要有一个入口类。代码为:

  1. package com.BlogCrawler.DocHelper;  
  2. import com.BlogCrawler.Fetcher.FetcherHelper;  
  3. import java.util.*;  
  4. /* 
  5.  * author:Tammy Pi 
  6.  * function:爬取器命令行运行 
  7.  * Email:victory_pj@163.com 
  8.  */  
  9. public class CrawlerHelper {  
  10.   
  11.     public boolean doCrawler(String path,String username) {  
  12.           
  13.         FetcherHelper fetcherHelper = new FetcherHelper();  
  14.         String html = fetcherHelper.getPageContent(path);  
  15.         if(html.equals("")){  
  16.               
  17.             return false;  
  18.         }  
  19.         List<com.BlogCrawler.Model.Document> list = null;  
  20.           
  21.         if(html.indexOf("postTitle")==-1){  
  22.               
  23.             list = fetcherHelper.htmlFilter(html,"div","class","post");  
  24.         }else{  
  25.               
  26.             list = fetcherHelper.htmlFilter(html,"div","class","postTitle");  
  27.         }  
  28.           
  29.         DocHelper docHelper = new DocHelper();  
  30.         docHelper.docHelper(username+".doc", list);  
  31.           
  32.         return true;  
  33.     }  
  34.       
  35.     public static void main(String[] args){  
  36.           
  37.         Scanner scan = new Scanner(System.in);  
  38.         System.out.println("请输入博客地址:");  
  39.         String path = scan.nextLine();  
  40.         System.out.println("请输入用户名:");  
  41.         String username = scan.nextLine();  
  42.           
  43.         CrawlerHelper helper = new CrawlerHelper();  
  44.         int index = 1;  
  45.           
  46.         helper.doCrawler(path, username);  
  47.         System.out.println("写入完成。文档位于c:\\Blog下。");  
  48.     }  
  49. }  

运行CrawlerHelper,运行效果为;

请输入博客地址:
http://www.cnblogs.com/passzh/
请输入用户名:
风清月明
最近项目开发中需记住的一些经验
JSP的URL页面传参乱码问题的解决
Hibernate的使用
比较重要的三个正则表达式(JAVA)
JAVA中Map按照value值逆序排序
MFC的列表控件的使用
MFC中TAB控件的使用
MFC通过ADO连接MS SQLSERVER数据库
不产生乱码的方法
在Dreamweaver中建立JSP站点的方法
写入完成。文档位于c:\Blog下。

再看看你的C盘Blog文件夹下,是否有个“风清月明.doc”,这篇博客的本页内容,就被写入DOC文档了。大功告成!

PS:对于有人在我的资源中评论说不能爬取的问题,我想说,我自己已经试验过了(首先,你写的地址必须是【博客园】的【具体的人的博客的地址】;其次,大概可以爬60%,有40%由于博客DOM结构没有分析到,所以爬取不了)。如果要用,请自行修改。

posted on 2012-10-18 18:02  刺猬的温驯  阅读(535)  评论(0编辑  收藏  举报