动态爬虫jsoup+jdic实现

准备资料

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) 支持、系统托盘支持、文件扩展集成和其他桌面特性。
svn地址,直接下了看例子吧: https://svn.java.net/svn/jdic~svn



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


动态核心

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

例子

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

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


package ins1000.main;

import ins1000.dialect.DefiniteUrl;
import ins1000.dialect.impl.CopyOfDefiniteUrl_zhilianzhaoping;
import ins1000.dialect.impl.DefiniteUrl_baiduMap;
import ins1000.util.BrowserReadHtml;

import java.util.ArrayList;
import java.util.List;

/**
 * 以网页翻页为例子
 * @author Administrator
 *
 */
public class Main{
	static List<DefiniteUrl> definiteUrls=new ArrayList<DefiniteUrl>();
	static{
		definiteUrls.add(new DefiniteUrl_baiduMap());
		definiteUrls.add(new CopyOfDefiniteUrl_zhilianzhaoping());
	}
	
	public static void main(String[] args) throws Exception {
		for(DefiniteUrl du:definiteUrls){
			BrowserReadHtml brh= new BrowserReadHtml(du);
			brh.begin();
		}
	}
	
	public static void finish(DefiniteUrl du) {
		definiteUrls.remove(du);
		if(definiteUrls.size()==0){
			System.exit(0);
		}
		
	}

}
 主类,扩展的时候直接添加 definiteUrls.add(new xxx());即可

 

package ins1000.util;
import ins1000.dialect.DefiniteUrl;
import java.awt.BorderLayout;
import java.net.URL;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.JFrame;
import javax.swing.JPanel;

import org.jdesktop.jdic.browser.WebBrowser;
import org.jdesktop.jdic.browser.WebBrowserEvent;
import org.jdesktop.jdic.browser.WebBrowserListener;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;


/**
 * 动态读取页面的html
 * @author ckf
 *
 */
public class BrowserReadHtml {
	private DefiniteUrl definiteUrl;
	
    public BrowserReadHtml(DefiniteUrl definiteUrl) {
    	this.definiteUrl=definiteUrl;
	}
    
    private  JFrame frame;
    private JPanel panel_name=new JPanel();
    private WebBrowser webBrowser = new WebBrowser();
	public void begin() throws Exception{
		initwebBrowser(); 
        frame = new JFrame("Browser Test");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(webBrowser);
        frame.pack();
        frame.setSize(900,500);
        frame.setLocation((int)(100*Math.random()), (int)(100*Math.random()));
        frame.setVisible(definiteUrl.isVisible());
	}
	int begincount;
	private void initwebBrowser()  throws Exception{

        panel_name.add(webBrowser, BorderLayout.CENTER);
        webBrowser .setURL(new URL(definiteUrl.getUrl()));
        webBrowser .addWebBrowserListener(new WebBrowserListener() {
      public void documentCompleted(WebBrowserEvent event) {
    	  if(begincount==0){
    		  getThisPageResult();
    	  }
    	  begincount++;
      }
	public void downloadStarted(WebBrowserEvent event) {}
      public void downloadCompleted(WebBrowserEvent event) {      }
      public void downloadProgress(WebBrowserEvent event) {    	  }
      public void downloadError(WebBrowserEvent event) {    	  }
      public void titleChange(WebBrowserEvent event) {    	  }  
      public void statusTextChange(WebBrowserEvent event) {    	  }
     public void windowClose(WebBrowserEvent arg0) {     }

     });
        
	}
	
    private void callback(String result) {
    	Document doc=Jsoup.parse(result);
    	definiteUrl.page(doc);
    	if(definiteUrl.isEndPage(doc)){
    		frame.dispose();
    		definiteUrl.finish();
    	}else{
    		webBrowser.executeScript(definiteUrl.getNextPageJavaScript(doc));
    		getThisPageResult();
    	}
	}
	private void getThisPageResult() {
		Timer timer = new Timer(false);
		timer.schedule(new AllTask(), 1 * 1000);
	}
	

	 class AllTask extends TimerTask {
		public void run() {
			String jscript =   "function getAllHtml() {"+
		    "var a='';" +
		    "a = '<html><head><title>';" +
		    "a += document.title;"+	    
		    "a += '</title></head>';"+
	 	 	 "a += document.body.outerHTML;"+
	 	 	"a += '</html>';"+
			"return a;"+
		"}"+
		"getAllHtml();";
	  String result = webBrowser.executeScript(jscript);
	  callback(result);
		}
	}
}

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

 

 

 

package ins1000.dialect;


import ins1000.main.Main;

import org.jsoup.nodes.Document;

/**
 * 抽象类,每个具体的网站都要继承此类
 * @author Administrator
 *
 */
public abstract class DefiniteUrl{
	private String url;
	private boolean visible;
	public DefiniteUrl(String url){
		this.url=url;
		visible=true;
	}
	
	public abstract String getNextPageJavaScript(Document doc);
	
	public abstract boolean isEndPage(Document doc);
	
	public abstract void page(Document doc);

	
	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	public boolean isVisible() {
		return visible;
	}

	public void setVisible(boolean visible) {
		this.visible = visible;
	}

	public void finish() {
		Main.finish(this);
	}


	
}

 

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

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

isEndPage是否为最后一页

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

 

 

 

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

 

package ins1000.dialect.impl;

import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import ins1000.dialect.DefiniteUrl;

public class DefiniteUrl_baiduMap  extends DefiniteUrl{

	public DefiniteUrl_baiduMap() {
		//设置网站入口地址
		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");
		//设置窗口是否可视化,默认为true
		//setVisible(false);
	}
	private int count=1;
	@Override
	public String getNextPageJavaScript(Document doc) {
		count++;
		Element el= doc.select("#pgw").select("a").last();
		return el.attr("onclick");
	}

	@Override
	public boolean isEndPage(Document doc) {
		if(count>=2){
			return true;
		}else{
			return false;
		}
	}

	@Override
	public void page(Document doc) {
		Elements els= doc.select("#imgid").select("dl");
		for(Element el:els){
			Element img=el.select("img").first();
			Element link=el.select("dt").select("a").first();
			System.out.println(link.text()+"=======>"+img.absUrl("src"));
		}
	}

}
 

 

 

package ins1000.dialect.impl;

import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import ins1000.dialect.DefiniteUrl;

public class CopyOfDefiniteUrl_zhilianzhaoping  extends DefiniteUrl{

	public CopyOfDefiniteUrl_zhilianzhaoping() {
		//设置网站入口地址
		super("http://sou.zhaopin.com/jobs/jobsearch_jobtype.aspx?in=210500&jl=%E6%B7%B1%E5%9C%B3&kw=java&sm=1&p=1");
		//设置窗口是否可视化,默认为true
		//setVisible(false);
	}
	private int count=1;
	@Override
	public String getNextPageJavaScript(Document doc) {
		
		
		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;
		String next="window.location.href='"+url+"';";
		
		count++;
		return next;
	}
	
	@Override
	public boolean isEndPage(Document doc) {
		if(count>=6){
			return true;
		}else{
			return false;
		}
	}

	@Override
	public void page(Document doc) {
		Elements els= doc.select("#joblist").select("[class=trW2]");
		for(Element el:els){
			try {
				System.out.print(el.select("a").first().text());
				System.out.print("==========>");
				System.out.println(el.select("a").eq(1).text());
			} catch (Exception e) {
			}
		}
	
	}

}

 

有图有真相



 

附件中有源码,eclipse导出

 

 

 

 

遗留问题

 

 

	private void getThisPageResult() {
		Timer timer = new Timer(false);
		timer.schedule(new AllTask(), 1 * 1000);
	}
	

	 class AllTask extends TimerTask {
		public void run() {
			String jscript =   "function getAllHtml() {"+
		    "var a='';" +
		    "a = '<html><head><title>';" +
		    "a += document.title;"+	    
		    "a += '</title></head>';"+
	 	 	 "a += document.body.outerHTML;"+
	 	 	"a += '</html>';"+
			"return a;"+
		"}"+
		"getAllHtml();";
	  String result = webBrowser.executeScript(jscript);
	  callback(result);
		}

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

 

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值