最近写了一个程序,模拟登录百度进行一些操作,例如下载文库文档,网盘,修改个人信息等等,分析过程很痛苦,但是做完之后回头想想还是很意思的。代码有点乱,我不整理了,这里分享一下模拟百度相关原理与相关代码,以及一些注意事项。我比较热爱各种抓包,之前做过模拟新浪微博登录、发微博,转发、评论等操作,有兴趣的程序员可以一起交流。
我使用的是java去模拟,apache下的core包。抓包工具我用的是Httpwatch pro和firebug。
Httpclinet 官方API:http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/
Httpclient LIB以及DEMO下载地址:http://hc.apache.org/downloads.cgi.
登录代码已整理:http://blog.csdn.net/programmer_sir/article/details/43193611
百度登录源码及LIB下载地址:http://download.csdn.net/detail/programmer_sir/8400495
一、百度登录原理。
1、访问http://www.baidu.com生成cookie,cookie里有一个BAIDUID。
2、访问https://passport.baidu.com/v2/api/?getapi&tpl=mn&apiver=v3&class=login&logintype=dialogLogin,得到token。
{"errInfo":{ "no": "0" }, "data": { "rememberedUserName" : "sir_belen", "codeString" : "", "token" : "a5ff667c0360dbdcb43cae85018e3e97", "cookie" : "1", "usernametype":"1", "spLogin" : "rate", "disable":"", "loginrecord":{ 'email':[ ], 'phone':[ ] } }}
3、访问https://passport.baidu.com/v2/api/?login,登录为POST,需要的将登录参数传过去。
// 登录POST参数。
private List produceFormEntity() throws UnsupportedEncodingException{
List list = new ArrayList();
list.add(new BasicNameValuePair("tt", ""+System.currentTimeMillis()));
list.add(new BasicNameValuePair("tpl", "mn"));
list.add(new BasicNameValuePair("token", token));
list.add(new BasicNameValuePair("isPhone", ""));
list.add(new BasicNameValuePair("username", username));
list.add(new BasicNameValuePair("password", password));
list.add(new BasicNameValuePair("verifycode", verifycode));
list.add(new BasicNameValuePair("codestring", codestring));
return list;
}
4、访问http://www.baidu.com。搜索是否有登录两字,若没有说明登录成功!
二、注意事项:
1、要得到token必须要先预访问一下百度,只有获取到BAIDUID才能获取到token。
2、登录返回结果如下:
err_no相关参数意思,参照以下代码:
int code = Integer.parseInt((String)json.get("err_no"));
switch (code) {
case 0: // 登录成功。
m.setStatusCode(200);
break;
case 4: // 密码错误。
m.setStatusCode(6);
m.setO(json);
break;
case 5: // 帐号被百度认定为异常,需要去百度(www.baidu.com)验证手机号。
m.setStatusCode(5);
break;
case 6: // 验证码错误。
m.setStatusCode(4);
m.setO(json);
break;
case 257:// 需要填写验证码。
m.setStatusCode(3);
m.setO(json);
break;
case 120019: // 帐号被百度认定为异常,需要去百度(www.baidu.com)验证手机号。
m.setStatusCode(5);
break;
default: // 其它原因,请联系工作人员。
m.setStatusCode(500);
break;
}
codeString是验证码,如果不为空说明需要输入验证码,如果出现验证码的问题,可以将图片下载到本地服务器。
然后让用户看图片填写验证码,登录时将验证码与codeString带过去即可。
3、Httpclient core能自动管理Cookie,在模拟登录时保证client是同一个,且多个地方使用到get或post请求,可以将httpclient封装一下。这里我写的是单例,以保证HTTP请求是同一个。这样登录成功后管理或下载百度相关的,例如获取个人信息,下载百度文库或其它操作都不会有问题了。
package com.baidu.service;
import java.util.List;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.CookieStore;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import com.baidu.util.Log;
@SuppressWarnings("deprecation")
public class BaiduConnectService {
private CookieStore cookieStore = new BasicCookieStore();
private BaiduConnectService(){}
private static class BaiduConnectServiceContainer{
private static BaiduConnectService bc = new BaiduConnectService();
}
public static BaiduConnectService getInstance(){
Log.logInfo("init BaiduConnectService.");
return BaiduConnectServiceContainer.bc;
}
public HttpResponse execute(String url) throws Exception{
return this.execute(url,null);
}
public HttpResponse execute(String url, List params) throws Exception{
HttpClient httpClient = new DefaultHttpClient(
new ThreadSafeClientConnManager());
HttpResponse response = null;
HttpUriRequest request = null;
if (params != null) {
HttpPost httpPost = new HttpPost(url);
try {
HttpEntity postBodyEnt = new UrlEncodedFormEntity(params);
httpPost.setEntity(postBodyEnt);
} catch (Exception e) {
e.printStackTrace();
}
request = httpPost;
} else {
HttpGet httpGet = new HttpGet(url);
request = httpGet;
}
HttpContext localContext = new BasicHttpContext();
localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
response = httpClient.execute(request, localContext);
Log.logInfo("Request URL:"+url);
Log.logRed("[Status:" + response.getStatusLine().getStatusCode()+"]");
return response;
}
public CookieStore getCookieStore() {
return cookieStore;
}
public void setCookieStore(CookieStore cookieStore) {
this.cookieStore = cookieStore;
}
}
4、我的代码中没有在请求添加头信息,例如Host,User-Agent之类的,百度登录这块是不需要添加的。
5、以下是我做的一个小系统的部分功能页面,供参考:模拟登录百度、验证码、搜索并下载百度文库、搜索并下载网盘等。
1)登录百度
2)密码输入错误三次,百度会出现验证码,下载验证码。
3)验证码输入后,模拟调用百度验证接口,检测验证码输入是否正确 。
更换验证码请求地址:
https://passport.baidu.com/v2/?reggetcodestr&token="
+ getToken(getCookies()) + "&tpl=mn&apiver=v3&tt="
+ System.currentTimeMillis() + "&fr=login
检测验证码输入是否正确请求地址:
https://passport.baidu.com/v2/?checkvcode&token="
+ getToken(getCookies()) + "&tpl=mn&apiver=v3&tt="+System.currentTimeMillis()+"&verifycode="+verifycode+"&codestring="+codeString
5)下载百度文库时百度发现异常,有时候需要输入验证码。
6)输入验证码后,点击“提交”。
7)下载百度文库成功!