凤凰山笔记

java httpclient模拟登录微博完整版

上篇说在研究java模拟登录新浪微博的事情,现在放出全部代码,研究过程中学到不少东西。
首先感谢shrik3写的微博模拟登陆研究,虽然是python版本的但是对我启发很大,描述抓包的过程很详细,我做的工作仅仅是把python代码翻译成java而已。

jar包只有httpclient和fastjson没有其他工具引入,用自己的帐号亲测可用,BTW代码还有很多可以完善的地方。

启动类

1
2
3
4
public static void main(String[] args) throws IOException {
Weibo weibo = new Weibo("用户名","密码明文");
weibo.login();
}

实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
package cn.jarjar.weibo.login;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPublicKeySpec;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

import org.apache.commons.codec.binary.Base64;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
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.params.CookiePolicy;
import org.apache.http.client.params.HttpClientParams;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.ByteArrayBody;

import sun.misc.BASE64Encoder;

import com.alibaba.fastjson.JSONObject;

/**
* @ClassName: Weibo
* @Description: 微博登录验证
* @author cloudroc
* @date 2016年4月19日 下午4:18:06
*
*/
public class Weibo {

private static final Logger logger = Logger.getLogger(Weibo.class);

private static DefaultHttpClient httpclient = null;// HttpClient对象

private String userName = "";// 用户名

private String passWord = "";// 密码明文

private static final String preLoginUrl = "http://login.sina.com.cn/sso/prelogin.php?entry=weibo&callback=sinaSSOController.preloginCallBack&su=&rsakt=mod&client=ssologin.js(v1.4.18)&_=1446099453139";

private static final String userAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.152 Safari/537.36";

private static final String uploadUrl = "http://picupload.service.weibo.com/interface/pic_upload.php?&mime=image%2Fjpeg&data=base64&url=0&markpos=1&logo=&nick=0&marks=1&app=miniblog";

public Weibo(String userName, String passWord) {
this.userName = userName;
this.passWord = passWord;
}

private String weiboCookie = null;

public boolean login(){

boolean flag = true;

String loginUrl = "http://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.18)&_=" +
System.currentTimeMillis();

httpclient = new DefaultHttpClient();
// 设定cookie策略
HttpClientParams.setCookiePolicy(httpclient.getParams(),CookiePolicy.BROWSER_COMPATIBILITY);

String preJosn = getPreLoginJson();
JSONObject preObj=(JSONObject) JSONObject.parse(preJosn);

String pubkey = preObj.getString("pubkey");
String servertime = preObj.getString("servertime");
String nonce = preObj.getString("nonce");
String rsakv = preObj.getString("rsakv");

HttpPost httppost = new HttpPost(loginUrl);
httppost.setHeader("Accept", "*/*");
httppost.setHeader("Accept-Language", "zh-CN,zh;q=0.8,en;q=0.6,ja;q=0.4,zh-TW;q=0.2");
httppost.setHeader("Content-Type", "application/x-www-form-urlencoded");
httppost.setHeader("Host", "login.sina.com.cn");
httppost.setHeader("Origin", "http://weibo.com");

List<NameValuePair> formparams =new ArrayList<NameValuePair>();
formparams.add(new BasicNameValuePair("entry", "weibo"));
formparams.add(new BasicNameValuePair("password", passWord));

formparams.add(new BasicNameValuePair("entry", "weibo"));
formparams.add(new BasicNameValuePair("gateway", "1"));
formparams.add(new BasicNameValuePair("from", ""));
formparams.add(new BasicNameValuePair("savestate", "7"));
formparams.add(new BasicNameValuePair("useticket", "1"));
formparams.add(new BasicNameValuePair("pagerefer", "http://s.weibo.com/weibo/%25E6%2596%2587%25E7%25AB%25A0%25E5%2590%258C%25E5%25AD%25A6?topnav=1&wvr=6&b=1"));
formparams.add(new BasicNameValuePair("vsnf", "1"));
formparams.add(new BasicNameValuePair("su", getEncodeUserName(this.userName)));
formparams.add(new BasicNameValuePair("service", "miniblog"));
formparams.add(new BasicNameValuePair("servertime", servertime));
formparams.add(new BasicNameValuePair("nonce", nonce));
formparams.add(new BasicNameValuePair("pwencode", "rsa2"));
formparams.add(new BasicNameValuePair("rsakv", rsakv));
formparams.add(new BasicNameValuePair("sp", getSP(this.passWord, pubkey, servertime, nonce)));
formparams.add(new BasicNameValuePair("encoding", "UTF-8"));
formparams.add(new BasicNameValuePair("sr", "1366*768"));
formparams.add(new BasicNameValuePair("prelt", "1011"));
formparams.add(new BasicNameValuePair("url", "http://weibo.com/ajaxlogin.php?framelogin=1&callback=parent.sinaSSOController.feedBackUrlCallBack"));
formparams.add(new BasicNameValuePair("domain", "weibo.com"));
formparams.add(new BasicNameValuePair("returntype", "META"));

try {
httppost.setEntity(new UrlEncodedFormEntity(formparams, HTTP.UTF_8));

//获取登陆应答内容
HttpResponse response = httpclient.execute(httppost);

logger.info("登录返回状态码:"+response.getStatusLine().getStatusCode());

HttpEntity httpEntity = response.getEntity();
String responseStr = EntityUtils.toString(httpEntity);

String loginHtml1 = new String(responseStr.getBytes("iso8859-1"), "GBK");

logger.info(userName+"-登录请求第1次返回:"+loginHtml1);

String loginUrl2 = "" ;
String loginHtml2 = "" ;

Pattern pattern1 = Pattern.compile("location.replace\\('(.*?)'\\);");
Matcher m1 = pattern1.matcher(loginHtml1);
if (m1.find()) {
loginUrl2=m1.group(1);
logger.info("第2次登录请求url:"+loginUrl2);
}

//以下几段httpget写的很冗余,可以抽象为方法..
HttpGet loginGet2 = new HttpGet(loginUrl2);

try {
HttpResponse response2 = httpclient.execute(loginGet2);
HttpEntity httpEntity2 = response2.getEntity();
loginHtml2 = EntityUtils.toString(httpEntity2);

logger.info(userName+"-登录请求第2次返回:"+loginHtml2);

} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
loginGet2.abort();
}


String loginUrl3 = "" ;
String loginHtml3 = "" ;

//"userdomain":"?wvr=5&lf=reg"}
Pattern pattern3 = Pattern.compile("\"userdomain\":\"(.*?)\"}");
Matcher m3 = pattern3.matcher(loginHtml2);
if (m3.find()) {
loginUrl3="http://weibo.com/"+m3.group(1);
logger.info("第3次登录请求url:"+loginUrl3);
}

HttpGet loginGet3 = new HttpGet(loginUrl3);

try {
HttpResponse response3 = httpclient.execute(loginGet3);
HttpEntity httpEntity3 = response3.getEntity();
loginHtml3 = EntityUtils.toString(httpEntity3);

logger.info(userName+"-登录请求第3次返回:"+loginHtml3);

} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
loginGet3.abort();
}

logger.info(userName+" 登录成功...");

}catch (Exception e) {
e.printStackTrace();
return false;
} finally {
httppost.abort();
}

return flag;
}



private String getPreLoginJson(){

String json = "" ;

HttpGet httpget = new HttpGet(preLoginUrl.toString());
httpget.setHeader("User-Agent", userAgent);
// Create a response handler
ResponseHandler<String> responseHandler = new BasicResponseHandler();
String responseBody = "";
try {
responseBody = httpclient.execute(httpget, responseHandler);
} catch (Exception e) {
e.printStackTrace();
responseBody = null;
} finally {
httpget.abort();
}

Pattern pattern1 = Pattern.compile("\\((.*)\\)");
Matcher m1 = pattern1.matcher(responseBody);
if (m1.find()) {
json=m1.group(1);
logger.info("预登录信息:"+json);
}

return json;
}

private String getEncodeUserName(String userName){
try {
userName = java.net.URLEncoder.encode(userName, "UTF-8");
byte[] isoret = userName.getBytes("UTF-8");
return Base64.encodeBase64String(isoret);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return "error";
}

}

private String getSP(String pwd,String pubkey,String servertime,String nonce) {
String t = "10001";
String message = servertime + "\t" + nonce + "\n" + pwd;
String result = null;
try {
result = rsa(pubkey, t , message);
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeySpecException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
logger.info("RSA加密后的密码:" + result);
return result;
}

private String rsa(String pubkey, String exponentHex, String pwd)
throws IllegalBlockSizeException, BadPaddingException,
NoSuchAlgorithmException, InvalidKeySpecException,
NoSuchPaddingException, InvalidKeyException,
UnsupportedEncodingException {
KeyFactory factory = KeyFactory.getInstance("RSA");

BigInteger m = new BigInteger(pubkey, 16);
BigInteger e = new BigInteger(exponentHex, 16);
RSAPublicKeySpec spec = new RSAPublicKeySpec(m, e);

//创建公钥
RSAPublicKey pub = (RSAPublicKey) factory.generatePublic(spec);
Cipher enc = Cipher.getInstance("RSA");
enc.init(Cipher.ENCRYPT_MODE, pub);

byte[] encryptedContentKey = enc.doFinal(pwd.getBytes("UTF-8"));

return new String(encodeHex(encryptedContentKey));
}

protected static char[] encodeHex(final byte[] data, final char[] toDigits) {
final int l = data.length;
final char[] out = new char[l << 1];

for (int i = 0, j = 0; i < l; i++) {
out[j++] = toDigits[(0xF0 & data[i]) >>> 4];
out[j++] = toDigits[0x0F & data[i]];
}
return out;
}

public static char[] encodeHex(final byte[] data, final boolean toLowerCase) {
return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
}

public static char[] encodeHex(final byte[] data) {
return encodeHex(data, true);
}

private static final char[] DIGITS_LOWER = { '0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

private static final char[] DIGITS_UPPER = { '0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
}
cloudroc wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客!
很惭愧,只做了些微小的工作,您的支持将鼓励我继续努力创作!