转载自:http://www.open-open.com/lib/view/open1331187174202.html
你想要的任何信息,基本上在互联网上存在了,问题是如何把它们整理成你所需要的,比如在某个行业网站上抓取所有相关公司的的名字,联系电话,Email等,然后存到Excel里面做分析。网页信息抓取变得原来越有用了。
一般传统的网页,web服务器直接返回Html,这类网页很好抓,不管是用何种方式,只要得到html页面,然后做Dom解析就可以了。但对于需要Javascript生成的网页,就不那么容易了。张瑜 目前也没有找到好办法解决此问题。各位有抓javascript网页经验的朋友,欢迎指点。
所以今天要谈的还是传统html网页的信息抓取。虽然前面说了,没有技术难度,但是是否能有相对更容易的方法呢? 用过jQuery等js框架的朋友,可能都会觉得javascript貌似抓取网页信息的天然助手,而且其出生就是为了网页解析而存在的。当然现在有更多的应用了,如Server端的javascript应用,NodeJs.
如果能在我们的应用程序,如java程序中,能使用jQuery去抓网页,绝对是件激动人心的事情 。确实有现成的解决方案,一个Javascript引擎,一个能支撑jQuery运行的环境就可以了。
工具 : java, Rhino, envJs. 其中 Rhino是Mozzila提供的开源Javascript引擎,envJs是一个模拟浏览器额环境,如Window等。 代码如下,
01 | package stony.zhang.scrape; |
04 | import java.io.FileNotFoundException; |
05 | import java.io.FileReader; |
06 | import java.io.IOException; |
07 | import java.lang.reflect.InvocationTargetException; |
09 | import org.mozilla.javascript.Context; |
10 | import org.mozilla.javascript.ContextFactory; |
11 | import org.mozilla.javascript.Scriptable; |
12 | import org.mozilla.javascript.ScriptableObject; |
16 | * @Emal: zhangyu0182@sina.com |
19 | public class RhinoScaper { |
21 | private String jsFile; |
24 | private Scriptable scope; |
26 | public String getUrl() { |
30 | public String getJsFile() { |
34 | public void setUrl(String url) { |
36 | putObject( "url" , url); |
39 | public void setJsFile(String jsFile) { |
44 | cx = ContextFactory.getGlobal().enterContext(); |
45 | scope = cx.initStandardObjects( null ); |
46 | cx.setOptimizationLevel(- 1 ); |
47 | cx.setLanguageVersion(Context.VERSION_1_5); |
49 | String[] file = { "./lib/env.rhino.1.2.js" , "./lib/jquery.js" }; |
50 | for (String f : file) { |
55 | ScriptableObject.defineClass(scope, ExtendUtil. class ); |
56 | } catch (IllegalAccessException e1) { |
58 | } catch (InstantiationException e1) { |
60 | } catch (InvocationTargetException e1) { |
63 | ExtendUtil util = (ExtendUtil) cx.newObject(scope, "util" ); |
64 | scope.put( "util" , scope, util); |
67 | protected void evaluateJs(String f) { |
70 | in = new FileReader(f); |
71 | cx.evaluateReader(scope, in, f, 1 , null ); |
72 | } catch (FileNotFoundException e1) { |
74 | } catch (IOException e1) { |
79 | public void putObject(String name, Object o) { |
80 | scope.put(name, scope, o); |
84 | evaluateJs( this .jsFile); |
测试代码:
01 | package stony.zhang.scrape; |
03 | import java.util.HashMap; |
06 | import junit.framework.TestCase; |
08 | public class RhinoScaperTest extends TestCase { |
10 | public RhinoScaperTest(String name) { |
14 | public void testRun() { |
15 | RhinoScaper rs = new RhinoScaper(); |
17 | rs.setUrl( "http://www.baidu.com" ); |
18 | rs.setJsFile( "test.js" ); |
test.js文件,如下
02 | url: "http://www.baidu.com" , |
03 | context: document.body, |
04 | success: function (data){ |
07 | var result =parseHtml(data); |
09 | var $v= jQuery(result); |
11 | $v.find( '#u a' ).each( function (index) { |
12 | util.log(index + ': ' + $( this ).attr( "href" )); |
19 | function parseHtml(html) { |
23 | var oIframe = document.createElement( 'iframe' ); |
25 | oIframe.style.display = 'none' ; |
27 | document.body.appendChild(oIframe); |
29 | document.documentElement.appendChild(oIframe); |
32 | oIframe.contentDocument.open(); |
33 | oIframe.contentDocument.write(html); |
34 | oIframe.contentDocument.close(); |
38 | var oBody = oIframe.contentDocument.body; |
我们执行Unit Test,将会在控制台打印从网页上抓取的三个baidu的连接,
0: http://www.baidu.com/gaoji/preferences.html
1: http://passport.baidu.com/?login&tpl=mn
2: https://passport.baidu.com/?reg&tpl=mn
测试成功,故证明在java程序中用jQuery抓取网页是可行的.