动态爬虫jsoup+jdic实现

转载自:http://yiyickf.iteye.com/blog/1107108

准备资料

jsoup 是一款 Java 的HTML 解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API,可通过DOM,CSS以及类似于JQuery的操作方法来取出和操作数据。

jsoup的主要功能如下:

  1. 从一个URL,文件或字符串中解析HTML;
  2. 使用DOM或CSS选择器来查找、取出数据;
  3. 可操作HTML元素、属性、文本;
如果对jsoup不熟悉,请移步 http://jsoup.org/


JDIC 全程是 JDesktop Integration Components 目的是构建消除本机应用程序和 Java 等价物之间差距的组件。JDIC 单一的 Java API 允许应用程序接进本机操作系统特性,同时保持跨平台支持。它目前提供了本机 Web 浏览器(Internet Explorer 或 Mozilla) 支持、系统托盘支持、文件扩展集成和其他桌面特性。
官网: http://java.net/projects/jdic/
svn地址,直接下了看例子吧: https://svn.java.net/svn/jdic~svn
helloword程序: http://plplum.blog.163.com/blog/static/31032400200910994034328/



另,刚刚找到的一篇好文章,Java 网页浏览器组件介绍: http://www.ibm.com/developerworks/cn/java/j-lo-browser/index.html


动态核心

jsoup 的解析很好用,但是jsoup不能解析动态的代码,于是就有了 JDIC调用ie内核,然后执行
Java代码   收藏代码
  1. String jscript =   "function getAllHtml() {"+  
  2.         "var a='';" +  
  3.         "a = '<html><head><title>';" +  
  4.         "a += document.title;"+       
  5.         "a += '</title></head>';"+  
  6.          "a += document.body.outerHTML;"+  
  7.         "a += '</html>';"+  
  8.         "return a;"+  
  9.     "}"+  
  10.     "getAllHtml();";  
  11.   String result = webBrowser.executeScript(jscript);  
 这段代码得到当前的html,然后交由jsoup 进行解析
Java代码   收藏代码
  1. Document doc=Jsoup.parse(result);  
  

例子

示例目标:
招聘网站,希望出来的结果按照公司规模来排序
购物网站,希望商品按照评论的多少来排序
图片搜索,快速保存所有的结果
。。。。。。

下面的演示实现了找出标题,百度图片搜索的前2页,智联招聘的前6页


Java代码   收藏代码
  1. package ins1000.main;  
  2.   
  3. import ins1000.dialect.DefiniteUrl;  
  4. import ins1000.dialect.impl.CopyOfDefiniteUrl_zhilianzhaoping;  
  5. import ins1000.dialect.impl.DefiniteUrl_baiduMap;  
  6. import ins1000.util.BrowserReadHtml;  
  7.   
  8. import java.util.ArrayList;  
  9. import java.util.List;  
  10.   
  11. /** 
  12.  * 以网页翻页为例子 
  13.  * @author Administrator 
  14.  * 
  15.  */  
  16. public class Main{  
  17.     static List<DefiniteUrl> definiteUrls=new ArrayList<DefiniteUrl>();  
  18.     static{  
  19.         definiteUrls.add(new DefiniteUrl_baiduMap());  
  20.         definiteUrls.add(new CopyOfDefiniteUrl_zhilianzhaoping());  
  21.     }  
  22.       
  23.     public static void main(String[] args) throws Exception {  
  24.         for(DefiniteUrl du:definiteUrls){  
  25.             BrowserReadHtml brh= new BrowserReadHtml(du);  
  26.             brh.begin();  
  27.         }  
  28.     }  
  29.       
  30.     public static void finish(DefiniteUrl du) {  
  31.         definiteUrls.remove(du);  
  32.         if(definiteUrls.size()==0){  
  33.             System.exit(0);  
  34.         }  
  35.           
  36.     }  
  37.   
  38. }  
 主类,扩展的时候直接添加 definiteUrls.add(new xxx());即可

 

Java代码   收藏代码
  1. package ins1000.util;  
  2. import ins1000.dialect.DefiniteUrl;  
  3. import java.awt.BorderLayout;  
  4. import java.net.URL;  
  5. import java.util.Timer;  
  6. import java.util.TimerTask;  
  7.   
  8. import javax.swing.JFrame;  
  9. import javax.swing.JPanel;  
  10.   
  11. import org.jdesktop.jdic.browser.WebBrowser;  
  12. import org.jdesktop.jdic.browser.WebBrowserEvent;  
  13. import org.jdesktop.jdic.browser.WebBrowserListener;  
  14. import org.jsoup.Jsoup;  
  15. import org.jsoup.nodes.Document;  
  16.   
  17.   
  18. /** 
  19.  * 动态读取页面的html 
  20.  * @author ckf 
  21.  * 
  22.  */  
  23. public class BrowserReadHtml {  
  24.     private DefiniteUrl definiteUrl;  
  25.       
  26.     public BrowserReadHtml(DefiniteUrl definiteUrl) {  
  27.         this.definiteUrl=definiteUrl;  
  28.     }  
  29.       
  30.     private  JFrame frame;  
  31.     private JPanel panel_name=new JPanel();  
  32.     private WebBrowser webBrowser = new WebBrowser();  
  33.     public void begin() throws Exception{  
  34.         initwebBrowser();   
  35.         frame = new JFrame("Browser Test");  
  36.         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
  37.         frame.getContentPane().add(webBrowser);  
  38.         frame.pack();  
  39.         frame.setSize(900,500);  
  40.         frame.setLocation((int)(100*Math.random()), (int)(100*Math.random()));  
  41.         frame.setVisible(definiteUrl.isVisible());  
  42.     }  
  43.     int begincount;  
  44.     private void initwebBrowser()  throws Exception{  
  45.   
  46.         panel_name.add(webBrowser, BorderLayout.CENTER);  
  47.         webBrowser .setURL(new URL(definiteUrl.getUrl()));  
  48.         webBrowser .addWebBrowserListener(new WebBrowserListener() {  
  49.       public void documentCompleted(WebBrowserEvent event) {  
  50.           if(begincount==0){  
  51.               getThisPageResult();  
  52.           }  
  53.           begincount++;  
  54.       }  
  55.     public void downloadStarted(WebBrowserEvent event) {}  
  56.       public void downloadCompleted(WebBrowserEvent event) {      }  
  57.       public void downloadProgress(WebBrowserEvent event) {       }  
  58.       public void downloadError(WebBrowserEvent event) {          }  
  59.       public void titleChange(WebBrowserEvent event) {        }    
  60.       public void statusTextChange(WebBrowserEvent event) {       }  
  61.      public void windowClose(WebBrowserEvent arg0) {     }  
  62.   
  63.      });  
  64.           
  65.     }  
  66.       
  67.     private void callback(String result) {  
  68.         Document doc=Jsoup.parse(result);  
  69.         definiteUrl.page(doc);  
  70.         if(definiteUrl.isEndPage(doc)){  
  71.             frame.dispose();  
  72.             definiteUrl.finish();  
  73.         }else{  
  74.             webBrowser.executeScript(definiteUrl.getNextPageJavaScript(doc));  
  75.             getThisPageResult();  
  76.         }  
  77.     }  
  78.     private void getThisPageResult() {  
  79.         Timer timer = new Timer(false);  
  80.         timer.schedule(new AllTask(), 1 * 1000);  
  81.     }  
  82.       
  83.   
  84.      class AllTask extends TimerTask {  
  85.         public void run() {  
  86.             String jscript =   "function getAllHtml() {"+  
  87.             "var a='';" +  
  88.             "a = '<html><head><title>';" +  
  89.             "a += document.title;"+       
  90.             "a += '</title></head>';"+  
  91.              "a += document.body.outerHTML;"+  
  92.             "a += '</html>';"+  
  93.             "return a;"+  
  94.         "}"+  
  95.         "getAllHtml();";  
  96.       String result = webBrowser.executeScript(jscript);  
  97.       callback(result);  
  98.         }  
  99.     }  
  100. }  

这个类是调用ie浏览器,执行javascript代码,可以不管

 

 

 

Java代码   收藏代码
  1. package ins1000.dialect;  
  2.   
  3.   
  4. import ins1000.main.Main;  
  5.   
  6. import org.jsoup.nodes.Document;  
  7.   
  8. /** 
  9.  * 抽象类,每个具体的网站都要继承此类 
  10.  * @author Administrator 
  11.  * 
  12.  */  
  13. public abstract class DefiniteUrl{  
  14.     private String url;  
  15.     private boolean visible;  
  16.     public DefiniteUrl(String url){  
  17.         this.url=url;  
  18.         visible=true;  
  19.     }  
  20.       
  21.     public abstract String getNextPageJavaScript(Document doc);  
  22.       
  23.     public abstract boolean isEndPage(Document doc);  
  24.       
  25.     public abstract void page(Document doc);  
  26.   
  27.       
  28.     public String getUrl() {  
  29.         return url;  
  30.     }  
  31.   
  32.     public void setUrl(String url) {  
  33.         this.url = url;  
  34.     }  
  35.   
  36.     public boolean isVisible() {  
  37.         return visible;  
  38.     }  
  39.   
  40.     public void setVisible(boolean visible) {  
  41.         this.visible = visible;  
  42.     }  
  43.   
  44.     public void finish() {  
  45.         Main.finish(this);  
  46.     }  
  47.   
  48.   
  49.       
  50. }  

 

 这个是抽象类,每个网站要实现对应的方法

getNextPageJavaScript下一页javascript代码,可以是点击下一页按钮,也可以是直接换url

isEndPage是否为最后一页

page当前页面最终的html代码(动态的html代码)

 

 

 

//以下为具体的实现类,扩展的时候直接继承一个DefiniteUrl

 

Java代码   收藏代码
  1. package ins1000.dialect.impl;  
  2.   
  3. import org.jsoup.nodes.Document;  
  4. import org.jsoup.nodes.Element;  
  5. import org.jsoup.select.Elements;  
  6. import ins1000.dialect.DefiniteUrl;  
  7.   
  8. public class DefiniteUrl_baiduMap  extends DefiniteUrl{  
  9.   
  10.     public DefiniteUrl_baiduMap() {  
  11.         //设置网站入口地址  
  12.         super("http://image.baidu.com/i?ct=201326592&cl=2&lm=-1&tn=baiduimage&istype=2&fm=index&pv=&z=0&word=%C2%E3%BB%E9%CA%B1%B4%FA&s=0");  
  13.         //设置窗口是否可视化,默认为true  
  14.         //setVisible(false);  
  15.     }  
  16.     private int count=1;  
  17.     @Override  
  18.     public String getNextPageJavaScript(Document doc) {  
  19.         count++;  
  20.         Element el= doc.select("#pgw").select("a").last();  
  21.         return el.attr("onclick");  
  22.     }  
  23.   
  24.     @Override  
  25.     public boolean isEndPage(Document doc) {  
  26.         if(count>=2){  
  27.             return true;  
  28.         }else{  
  29.             return false;  
  30.         }  
  31.     }  
  32.   
  33.     @Override  
  34.     public void page(Document doc) {  
  35.         Elements els= doc.select("#imgid").select("dl");  
  36.         for(Element el:els){  
  37.             Element img=el.select("img").first();  
  38.             Element link=el.select("dt").select("a").first();  
  39.             System.out.println(link.text()+"=======>"+img.absUrl("src"));  
  40.         }  
  41.     }  
  42.   
  43. }  
 

 

 

Java代码   收藏代码
  1. package ins1000.dialect.impl;  
  2.   
  3. import org.jsoup.nodes.Document;  
  4. import org.jsoup.nodes.Element;  
  5. import org.jsoup.select.Elements;  
  6.   
  7. import ins1000.dialect.DefiniteUrl;  
  8.   
  9. public class CopyOfDefiniteUrl_zhilianzhaoping  extends DefiniteUrl{  
  10.   
  11.     public CopyOfDefiniteUrl_zhilianzhaoping() {  
  12.         //设置网站入口地址  
  13.         super("http://sou.zhaopin.com/jobs/jobsearch_jobtype.aspx?in=210500&jl=%E6%B7%B1%E5%9C%B3&kw=java&sm=1&p=1");  
  14.         //设置窗口是否可视化,默认为true  
  15.         //setVisible(false);  
  16.     }  
  17.     private int count=1;  
  18.     @Override  
  19.     public String getNextPageJavaScript(Document doc) {  
  20.           
  21.           
  22.         String url="http://sou.zhaopin.com/jobs/jobsearch_jobtype.aspx?in=210500&jl=%E6%B7%B1%E5%9C%B3&kw=java&sm=1&p="+count;  
  23.         String next="window.location.href='"+url+"';";  
  24.           
  25.         count++;  
  26.         return next;  
  27.     }  
  28.       
  29.     @Override  
  30.     public boolean isEndPage(Document doc) {  
  31.         if(count>=6){  
  32.             return true;  
  33.         }else{  
  34.             return false;  
  35.         }  
  36.     }  
  37.   
  38.     @Override  
  39.     public void page(Document doc) {  
  40.         Elements els= doc.select("#joblist").select("[class=trW2]");  
  41.         for(Element el:els){  
  42.             try {  
  43.                 System.out.print(el.select("a").first().text());  
  44.                 System.out.print("==========>");  
  45.                 System.out.println(el.select("a").eq(1).text());  
  46.             } catch (Exception e) {  
  47.             }  
  48.         }  
  49.       
  50.     }  
  51.   
  52. }  

 

有图有真相



动态爬虫jsoup+jdic实现_第1张图片

 

附件中有源码,eclipse导出

 

 

 

 

遗留问题

 

 

Java代码   收藏代码
  1. private void getThisPageResult() {  
  2.     Timer timer = new Timer(false);  
  3.     timer.schedule(new AllTask(), 1 * 1000);  
  4. }  
  5.   
  6.   
  7.  class AllTask extends TimerTask {  
  8.     public void run() {  
  9.         String jscript =   "function getAllHtml() {"+  
  10.         "var a='';" +  
  11.         "a = '<html><head><title>';" +  
  12.         "a += document.title;"+       
  13.         "a += '</title></head>';"+  
  14.          "a += document.body.outerHTML;"+  
  15.         "a += '</html>';"+  
  16.         "return a;"+  
  17.     "}"+  
  18.     "getAllHtml();";  
  19.   String result = webBrowser.executeScript(jscript);  
  20.   callback(result);  
  21.     }  

上面是当前代码,求更好的解决方案

 

现在取得当前的html使用了定时器,1秒后执行,感觉很不精确,有没有什么更好的方式,比如判断当前页面所有的内容都已经加载完了,其它的javascript都已经执行完了的代码?

  • DynamicParseHtml.rar (1.1 MB)
  • 下载次数: 452
  • 查看图片附件

你可能感兴趣的:(爬虫,抓取网页,ie内核,jdic)