准备资料
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) 支持、系统托盘支持、文件扩展集成和其他桌面特性。
另,刚刚找到的一篇好文章,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);
- }
- }
- }
- 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都已经执行完了的代码?