一.需要用到的包:
commons-codec-1.4.jar
commons-httpclient-3.0.1.jar
commons-logging-1.1.1.jar
二.分析新浪通行证登录页面
登录页面:
新浪微博的登录页面中,我发现密码在传过去之前已经被js加密过,而js中加密方法很难找,而新浪通行证中的密码并没有加密,所以选择通过新浪通行证登录
地址:http://login.sina.com.cn/signup/signin.php?entry=sso
简要说明登录过程:
1.将用户信息提交到https://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.15)&_=1425914562105中,
火狐浏览器中测出,它返回了一部分cookie和一个json格式的响应信息,但这部分cookie是不能作用在微博中的,因为他们和微博的主机、作用域不同
2.用js处理返回的json信息,构建一个get请求,其参数主要由json中的信息构成
3.返回微博的cookie
4.用这部分cookie可以获取微博的信息
三.具体登录过程:
1.将用户名、密码等信息通过post请求传入https://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.15)&_=1425914562105中,获得许多cookie和一个json格式的响应体。
public static void main(String[] args) { HttpClient client=new HttpClient(); NameValuePair pairs[]={ new NameValuePair("cdult","3"), new NameValuePair("encoding","UTF-8"), new NameValuePair("from",null), new NameValuePair("gateway","1"), new NameValuePair("prelt","0"), new NameValuePair("pagerefer","http://login.sina.com/sso/login.php"), new NameValuePair("returntype","TEXT"), new NameValuePair("savestate","30"), new NameValuePair("service","sso"), new NameValuePair("sp","密码"), new NameValuePair("sr","1366*778"), new NameValuePair("su",getBASE64("用户名")), new NameValuePair("useticket","0"), new NameValuePair("vsnf","1") }; HttpMethod method=getPostMethod("https://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.15)&_="+new Date().getTime(), null, pairs); client.getParams().setContentCharset("GBK"); try { client.executeMethod(method); // System.out.println(method.getResponseBodyAsString()); InputStream stream = method.getResponseBodyAsStream(); BufferedReader br = new BufferedReader(new InputStreamReader(stream, "UTF-8")); StringBuffer buf = new StringBuffer(); String line; while (null != (line = br.readLine())) { buf.append(line).append("\n"); } System.out.println(buf.toString()); method.releaseConnection(); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } } public static HttpMethod getPostMethod(String url,Header headers[],NameValuePair pairs[]){ PostMethod method=new PostMethod(url); if(headers!=null){ for(Header header:headers){ method.setRequestHeader(header); } } method.setRequestBody(pairs); return method; }
上述代码中,最重要的部分是post参数中returntype,“TEXT”因为在ie中如果接收到json或者text格式的数据会自动提示下载,所以ie中这部分参数对应的value是“JFrame”格式的,由于拿不到我想要的东西,其登录过程我没有分析。
经运行,我们得到下述json格式的代码:
{"retcode":"0","uid":"2136324567", "nick":"\u7528\u62372136324567", "crossDomainUrlList": ["https:\/\/passport.weibo.com\/wbsso\/login?ticket=ST-MjEzNjMyNDU2Nw%3D%3D-1425964519-ja-B24DC4AB2894692B3B38928C36A11009&ssosavestate=1457500519", "https:\/\/crosdom.weicaifu.com\/sso\/crosdom?action=login&savestate=1457500519", "http:\/\/passport.weibo.cn\/sso\/crossdomain?action=login&savestate=1"]}
2. 根据返回json构建get请求例如
https://passport.weibo.com/wbsso/login?ticket=ST-MjEzNjMyNDU2Nw%3D%3D-1425965391-ja-BB03424873E09D9B8E6FF8BA8763304F&ssosavestate=1457501391&callback=sinaSSOController.doCrossDomainCallBack&scriptId=ssoscript0&client=ssologin.js(v1.4.15)&_=1425965215809
这里我理解的是新浪会根据我们提交的信息给我们一张票去访问微博,这些参数中,ticket和ssosavestate是json中给的_=后面是new Date().getTime(),其它固定,更新上面代码,全部代码如下
private static String username="xxxxx"; private static String password="xxxxx"; public static void main(String[] args) { String ticket=""; String ssosavestate=""; HttpClient client=new HttpClient(); NameValuePair pairs[]={ new NameValuePair("cdult","3"), new NameValuePair("encoding","UTF-8"), new NameValuePair("from",null), new NameValuePair("gateway","1"), new NameValuePair("prelt","0"), new NameValuePair("pagerefer","http://login.sina.com/sso/login.php"), new NameValuePair("returntype","TEXT"), new NameValuePair("savestate","30"), new NameValuePair("service","sso"), new NameValuePair("sp","wobuaini50"), new NameValuePair("sr","1366*778"), new NameValuePair("su",getBASE64(username)), new NameValuePair("useticket","0"), new NameValuePair("vsnf","1") }; HttpMethod method=getPostMethod("https://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.15)&_="+new Date().getTime(), null, pairs); client.getParams().setContentCharset("GBK"); try { client.executeMethod(method); String temp=method.getResponseBodyAsString(); if(temp.contains("ticket")){ ticket=temp.substring(temp.indexOf("ticket="),temp.indexOf("&")); ssosavestate=temp.substring(temp.indexOf("ssosavestate"),temp.indexOf("\"", temp.indexOf("ssosavestate"))); } } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } String url2="https://passport.weibo.com/wbsso/login?"+ticket+"&"+ssosavestate+"&callback=sinaSSOController.doCrossDomainCallBack&scriptId=ssoscript0&client=ssologin.js(v1.4.15)&_="+new Date().getTime(); String cookieStr=""; Header[] headers=null; HttpClient client2=new HttpClient(); GetMethod method2=new GetMethod(url2); try { client2.executeMethod(method2); headers=method2.getResponseHeaders(); method2.releaseConnection(); } catch (HttpException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } Cookie[] cookies=client2.getState().getCookies(); for (int i = 0; i < cookies.length; i++) { String temp=cookies[i].getName(); if(temp.equals("SUE")||temp.equals("SUS")||temp.equals("SUP")){ cookieStr+=cookies[i].getName()+"="+cookies[i].getValue()+";"; } } cookieStr+="un="+username; System.out.println(cookieStr); } public static HttpMethod getPostMethod(String url,Header headers[],NameValuePair pairs[]){ PostMethod method=new PostMethod(url); if(headers!=null){ for(Header header:headers){ method.setRequestHeader(header); } } method.setRequestBody(pairs); return method; } public HttpMethod getGetMethod(String url,Header headers[]){ HttpMethod method=new GetMethod(url); if(headers!=null){ for(Header header:headers){ method.setRequestHeader(header); } } return method; } @SuppressWarnings("restriction") public static String getBASE64(String s) { if (s == null) return null; return (new sun.misc.BASE64Encoder()).encode( s.getBytes() ); }
返回结果是:
SUS=SID-2136324567-1425965890-JA-6hy0f-a36939ccbd9b8192ecfa6b7dd7fd4122;SUE=es%3D72da1b83721474c9606bbec7bc8080b7%26ev%3Dv1%26es2%3Da0aa1dcd967281462c90f257a9daed9c%26rs0%3DgD8KqazZqR7q%252F3ytvcgRcNWY1frB7gvFQRxN3w0XLhZ3BvZy5tMWHZ58BMpG1X6a%252FisOZ0UPUCyuCdJOv6wfUfp1k1f9AadexOQoOAVFbkqr3LTiLI6u%252FkHe6fezN842YuY0w110jhU0Ls4vFOJvgOksPp4vpi5HOGKhqbmyGWQ%253D%26rv%3D0;SUP=cv%3D1%26bt%3D1425965890%26et%3D1426052290%26d%3Dc909%26i%3D4122%26us%3D1%26vf%3D0%26vt%3D0%26ac%3D0%26st%3D0%26uid%3D2136324567%26name%3D15201315239%2540sina.cn%26nick%3D%25E7%2594%25A8%25E6%2588%25B72136324567%26fmp%3D%26lcp%3D2014-04-29%252018%253A44%253A36;un=yourusername
这时我们只需要在我们的请求头中 setRequestHeader("Cookie", cookieStr);就可以访问微博的各个页面了
举例部分代码如下,可以放到上述代码的main中
HttpClient client3=new HttpClient(); GetMethod method3=new GetMethod("http://weibo.com/friends?leftnav=1&wvr=6&isfriends=1&step=2"); method3.setRequestHeader("Cookie", cookieStr); try { client3.executeMethod(method3); System.out.println(method3.getResponseBodyAsString()); } catch (HttpException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }
测试成功~
代码不合理的地方还请指教