您的位置:首页 > Web前端 > JavaScript

动态爬虫jsoup+jdic实现

2013-09-25 00:45 603 查看


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

准备资料

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

jsoup的主要功能如下:

从一个URL,文件或字符串中解析HTML;
使用DOM或CSS选择器来查找、取出数据;
可操作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代码



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 进行解析

Java代码



Document doc=Jsoup.parse(result);


例子

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

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

Java代码



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());即可



Java代码



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代码,可以不管







Java代码



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



Java代码



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"));

}

}



}







Java代码



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导出








遗留问题

Java代码



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都已经执行完了的代码?

DynamicParseHtml.rar (1.1 MB)
下载次数: 452

查看图片附件
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: