HTMLParser HttpClient Firebug结合解析网页
题外话
已经很长时间没有写作了,原因颇多,世事变迁之快,迅雷不及掩耳,技术之路上仍需努力,闲话少说,开整。
背景
一直以来ITS Team都痛苦与build的下载工作,具体流程如下图所示。
1. 登录BuildVault网站。
3. 选择相应的产品下载。
4. 获取一个下载build的URL,要么下载到本地这么还得再传到server上deploy,SCP或者FTP都是件极其痛苦的事情,或者利用CURL命令在server上直接下载,为什么不二次开发这个站点呢?远程在Server上执行curl脚本之间下载呢? 那么好,设想是好的,我们需要考虑很多B/S架构应用程序,UI是一大块,后台的话必须要有API能解析BuildVault网站,所以我们就必须自己分析BuildVault网站的内容,截取出我们自己想要的内容。此时进入正题。利用Firebug+httpclient+htmlparser解析网页内容。
说明
1) HTMLParser
htmlparser是一个纯的java写的html解析的库,它不依赖于其它的java库文件,主要用于改造或提取html。它能超高速解析html,而且不会出错。毫不夸张地说,htmlparser就是目前最好的html解析和分析的工具。无论你是想抓取网页数据还是改造html的内容,用了htmlparser绝对会忍不住称赞。
2) HttpClient
HttpClient 是 Apache Jakarta Common 下的子项目,用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。
实现了所有 HTTP 的方法(GET,POST,PUT,HEAD 等)支持自动转向支持 HTTPS 协议支持代理服务器等
3) Firebug
Console | HTML | CSS | Script | Dom | Net |
控制台 | Html查看器 | Css查看器 | 脚本条时期 | Dom查看器 | 网络状况监视 |
如果你从事过web开发的话,对于HTTP POST/GET提交请求一定不会陌生,如下HTML片段,这里有一些input tag还有hidden的tag,这些都会在用户点击submit的时候一并提交给服务器,服务器可以取到这些input的value。
<form method=”post” action=”http://justice.svl.ibm.com/cgi-bin/build-vault.cgi”>
<table border=”0″>
<tbody>
<tr>
<td align=”right”>Intranet ID</td>
<td><input type=”text” size=”30″ value=”” name=”id”/></td>
</tr>
<tr><td align=”right”>Password</td>
<td><input type=”password” value=”” name=”password”/>
</td>
</tr>
<tr>
<td align=”right” colspan=”2″>
<span class=”button-blue”><input type=”submit” value=”Sign In” name=””/></span>
</td>
</tr>
</tbody>
</table>
<input type=”hidden” value=”” name=”path”/>
<input type=”hidden” value=”Browse” name=”action”/>
<input type=”hidden” value=”” name=”display”/>
<input type=”hidden” value=”Normal” name=”mode”/>
</form>
那么我们的firebug集成在浏览器中当然可以截获这些随从POST/GET请求发送给服务器的这些参数了,打开“网络”->”Post”即可看到。
5) 截获HTTP请求头与响应头(request/response header)
打开“网络”->“Headers”
6) 查看响应HTML代码
请求提交后,服务器响应完毕会传送回浏览器HTML代码进行渲染才看到展示给我们的网页。
打开”网络”->”响应”
代码
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import org.apache.commons.httpclient.Cookie; import org.apache.commons.httpclient.Header; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.NameValuePair; import org.apache.commons.httpclient.cookie.CookiePolicy; import org.apache.commons.httpclient.methods.PostMethod; import org.htmlparser.Node; import org.htmlparser.NodeFilter; import org.htmlparser.Parser; import org.htmlparser.filters.AndFilter; import org.htmlparser.filters.HasAttributeFilter; import org.htmlparser.filters.HasChildFilter; import org.htmlparser.filters.TagNameFilter; import org.htmlparser.tags.InputTag; import org.htmlparser.tags.LinkTag; import org.htmlparser.util.NodeList; public class Test { /** * @param args */ public static void main(String[] args) throws Exception { HttpClient client = new HttpClient(); client.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY); /** * 步骤1. 登陆 */ PostMethod post = new PostMethod("http://justice.svl.ibm.com/cgi-bin/build-vault.cgi"); // 设置请求头信息- 方法1 post.setRequestHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)"); post.setRequestHeader("Connection" , "Keep-Alive"); post.setRequestHeader("Keep-Alive", "300"); post.setRequestHeader("Host", "justice.svl.ibm.com"); // 设置请求头信息- 方法2 // List<Header> headers = new ArrayList<Header>(); // headers.add(new Header("User-Agent", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)")); // headers.add(new Header("Connection", "Keep-Alive")); // headers.add(new Header("Keep-Alive", "300")); // headers.add(new Header("Host", "justice.svl.ibm.com")); // client.getHostConfiguration().getParams().setParameter("http.default-headers", headers); // 设置请求参数,这些参数不同于HTTP头中的参数,它们是放在FORM里提交给服务器的参数 NameValuePair username = new NameValuePair("id","xxxxxx@123.com"); NameValuePair password = new NameValuePair("password", "xxxxxxxx"); NameValuePair action = new NameValuePair("action", "Browse"); NameValuePair mode = new NameValuePair("mode", "Normal"); post.setRequestBody(new NameValuePair[] { username, password, action, mode}); // 开始执行,发送请求到服务器 client.executeMethod(post); // 打印HTTP返回码 System.out.println("~~~~~~~~~~~~~ Print status code begin ~~~~~~~~~~~~~~~~~~"); int status = post.getStatusCode(); System.out.println(status); System.out.println("~~~~~~~~~~~~~ Print status code end ~~~~~~~~~~~~~~~~~~"); // 打印Cookie信息,如果有的话 System.out.println("~~~~~~~~~~~~~ Print Cookie begin ~~~~~~~~~~~~~~~~~~"); Cookie[] cookies=client.getState().getCookies(); String tmpcookies=""; for(Cookie c:cookies){ tmpcookies=tmpcookies+c.toString()+";"; System.out.println(c); } System.out.println(tmpcookies); System.out.println("~~~~~~~~~~~~~ Print Cookie end ~~~~~~~~~~~~~~~~~~"); // 打印请求头消息 Header[] req = post.getRequestHeaders(); System.out.println("~~~~~~~~~~~~~ Print request header begin ~~~~~~~~~~~~~~~~~~"); for(int i = 0;i <req.length; i ++) { System.out.println(req[i].getName()+"||"+req[i].getValue()); } System.out.println("~~~~~~~~~~~~~ Print request header end ~~~~~~~~~~~~~~~~~~"); // 打印响应头消息 Header[] heard = post.getResponseHeaders(); System.out.println("~~~~~~~~~~~~~ Print response header begin ~~~~~~~~~~~~~~~~~~"); for(int i = 0;i <heard.length; i ++) { System.out.println(heard[i].getName()+"||"+heard[i].getValue()); } System.out.println("~~~~~~~~~~~~~ Print response header end ~~~~~~~~~~~~~~~~~~"); // 打印响应内容Body InputStream is = post.getResponseBodyAsStream(); String returnStr = convertStreamToString(is); System.out.println(returnStr); // 断开连接 post.releaseConnection(); // 利用Htmlparser解析返回的body,获取网页中的session值 // 这里这个site是把session放在HTML返回给客户端的,所以用这种方法,如果放在cookie里就从cookie里取 Parser parser = new Parser(returnStr); NodeFilter filter=new AndFilter(new TagNameFilter("input"),new HasAttributeFilter("type","hidden")); NodeList list = parser.extractAllNodesThatMatch(filter); Node[] nodes = list.toNodeArray(); InputTag textnode = (InputTag) (nodes[0]); String line = textnode.getAttribute("value"); System.out.println("session=" + line); /** * 步骤2. 获取我们想要的的字符串(产品列表) */ PostMethod post2 = new PostMethod("http://justice.svl.ibm.com/cgi-bin/build-vault.cgi?path=/distributions&session=" + line); // 设置请求参数,这些参数不同于HTTP头中的参数,它们是放在FORM里提交给服务器的参数 NameValuePair path = new NameValuePair("path", "/distributions"); NameValuePair session = new NameValuePair("session", line); post2.setRequestBody(new NameValuePair[] { path, session}); // 开始执行,发送请求到服务器 client.executeMethod(post2); // 打印响应内容Body InputStream is2 = post2.getResponseBodyAsStream(); String returnStr2 = convertStreamToString(is2); System.out.println(returnStr2); // 利用Htmlparser解析返回的body,或许我们想得到的字符串 // 我们想得到的列表的节点HTML为<td><a href="http://justice.svl.ibm.com/cgi-bin/build-vault.cgi?path=distributions/Cognos-BI-8.4-Rebranding&session=5cX6c38KUsGhU4O7NBhElobakgNro8PI">Cognos-BI-8.4-Rebranding</a></td> Parser parser2 = new Parser(returnStr2); NodeFilter filter2=new AndFilter(new TagNameFilter("TD"),new HasChildFilter(new TagNameFilter ("A"))); NodeList list2 = parser2.extractAllNodesThatMatch(filter2); Node[] nodes2 = list2.toNodeArray(); for (int i = 0; i < nodes2.length; i++) { Node node = nodes2[i].getFirstChild(); if (node instanceof LinkTag) { LinkTag link = (LinkTag) node; line = link.getLink(); String tmp = link.getLinkText(); System.out.println(tmp); //打印我们的产品列表 } } } public static String convertStreamToString(InputStream is) throws UnsupportedEncodingException { BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8")); StringBuilder sb = new StringBuilder(); String line = null; try { while ((line = reader.readLine()) != null) { sb.append(line + "\n"); } } catch (IOException e) { e.printStackTrace(); } finally { try { reader.close(); is.close(); } catch (IOException e) { e.printStackTrace(); } } return sb.toString(); } } |