Categories

用Java和Perl登录新浪微博

===============2011/06/28更新==========================
更新了HttpClient 4.x 模拟登录新浪微博的示例代码,经测试能正常登录,HttpClient 3.x和Perl版本的代码没有更新,有需要的同学自己参考HttpClient 4.x改写一下应该就可以了。希望大家也多一点探索精神,我没有精力经常来更新这个代码。

===============2011/05/24更新==========================
添加了用HttpClient 4.x 模拟登录新浪微博的示例代码

===============2011/05/22更新==========================
今天测试了日志中的Java代码,发现至少在目前是好用的,但是不保证以后会一直好用。感谢viLuo反馈的这个链接 新浪微博如何实现 SSO(t.sina.com.cn/weibo.com) 的分析,里面的内容写得很好很详细,遇到问题的同学可以去学习研究一下。

===============2011/03/29更新==========================
在最开始写这篇日志的时候,文中描述的两种方法的代码都经过了测试,能够成功登录。但是新浪的登录参数可能不停地在变化,所以如果你把日志中的代码直接复制回去,不能运行是很正常的情况。这里是文初写的模拟登录的一篇博客,里面涉及到了更多细节,有兴趣的朋友可以去看看。感谢zhaojiguang在评论中反馈此链接。
====================================================

现在新浪微博已经开放了API,为开发提供了很大的方便。但是仍然有一些事情是API所无能为力的,这时候就需要用到其他办法了。

1. 获得登录参数

一般的网站登录窗口都是一个简单的表单,随便搞一段代码就可以很轻易地登录上去,但是新浪的登录窗口却是由javascript控制的,稍微麻烦一些。对于简单的表单,可以通过查看html源代码获得登录参数;但是对于新浪这种,需要更深入一点的分析才行。

那么,要怎么办呢?答案是:万能的抓包工具。下面的截图分别展示了用Wireshark和Live HTTP headers(Firefox的一款插件)来获取登录参数的情况。

(1) Wireshark

抓包后找到带有 POST /sso/login.php?client=ssologin.js(v1.x.xx) HTTP/1.1的一行

然后右键,选择Follow TCP Stream,就会出来想要的结果,如图。注意看空行下面的红色文字部分。

(2) Live HTTP headers

实际上这个不算抓包工具,但是用起来更简单。注意看图中蓝底白字部分。

2. Java版

当获得了这些登录所需要传给服务器的参数以后,接下来的工作就比较简单了。
Java版主要用到了HttpClient,代码原始来源:http://flysnail.net/?p=27 ,我稍作了修改。
新浪微博中有一些页面登录前和登录后看到的内容不一样,比如 http://t.sina.com.cn/pub/tags ,程序中访问这个页面来检验是否登录成功。

(1) HttpClient 3.x版本

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
import java.io.IOException;
 
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
 
public class SinaLogin
{
	public static String login(String email, String passwd) throws HttpException, IOException
	{
		PostMethod post = new PostMethod("http://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.3.11)");
		post.addParameter("service", "miniblog");
		post.addParameter("client", "ssologin.js(v1.3.11)");
		post.addParameter("entry", "miniblog");
		post.addParameter("encoding", "utf-8");
		post.addParameter("gateway", "1");
		post.addParameter("savestate", "7");
		post.addParameter("from", "");
		post.addParameter("useticket", "0");
		post.addParameter("username", email);
		post.addParameter("password", passwd);
		post.addParameter("url", "http://t.sina.com.cn/ajaxlogin.php?framelogin=1&callback=parent.sinaSSOController.feedBackUrlCallBack");
		post.addParameter("returntype", "META");
		HttpClient client = new HttpClient();
		client.executeMethod(post);
		GetMethod get = new GetMethod("http://t.sina.com.cn/pub/tags");
		client.executeMethod(get);
		System.out.println(new String(get.getResponseBody()));
		return new String(get.getResponseBody());
	}
 
	public static void main(String[] args) throws HttpException, IOException
	{
		login("email","password");
	}
}

(2) HttpClient 4.x版本

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
package com.icycandy;
 
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
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.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
 
public class SinaLogin {
 
	private final static HttpClient client = new DefaultHttpClient();
 
	/**
	 * 抓取网页
	 * 
	 * @param url
	 * @throws IOException
	 */
	static String get(String url) throws IOException {
		HttpGet get = new HttpGet(url);
		HttpResponse response = client.execute(get);
		System.out.println(response.getStatusLine());
		HttpEntity entity = response.getEntity();
 
		String result = dump(entity);
		get.abort();
 
		return result;
	}
 
	/**
	 * 执行登录过程
	 * 
	 * @param user
	 * @param pwd
	 * @param debug
	 * @throws IOException
	 */
	static void login(String user, String pwd) throws IOException {
		HttpPost post = new HttpPost(
				"http://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.3.14)");
		post.setHeader("User-Agent",
				"Mozilla/5.0 (X11; Linux i686; rv:5.0) Gecko/20100101 Firefox/5.0");
		post.setHeader("Referer", "http://weibo.com/");
		post.setHeader("Content-Type", "application/x-www-form-urlencoded");
 
		// 登录表单的信息
		List<NameValuePair> qparams = new ArrayList<NameValuePair>();
		qparams.add(new BasicNameValuePair("entry", "miniblog"));
		qparams.add(new BasicNameValuePair("gateway", "1"));
		qparams.add(new BasicNameValuePair("from", ""));
		qparams.add(new BasicNameValuePair("savestate", "0"));
		qparams.add(new BasicNameValuePair("useticket", "1"));
		qparams.add(new BasicNameValuePair("ssosimplelogin", "1"));
		qparams.add(new BasicNameValuePair("service", "miniblog"));
		// servertime=1309164392
		// nonce=PJZCHM
		// qparams.add(new BasicNameValuePair("pwencode", "wsse"));
		qparams.add(new BasicNameValuePair("encoding", "utf-8"));
		qparams.add(new BasicNameValuePair(
				"url",
				"http://weibo.com/ajaxlogin.php?framelogin=1&callback=parent.sinaSSOController.feedBackUrlCallBack"));
		qparams.add(new BasicNameValuePair("returntype", "META"));
 
		qparams.add(new BasicNameValuePair("username", user));
		qparams.add(new BasicNameValuePair("password", pwd));
 
		UrlEncodedFormEntity params = new UrlEncodedFormEntity(qparams, "UTF-8");
		post.setEntity(params);
 
		// Execute the request
		HttpResponse response = client.execute(post);
		post.abort();
		// 新浪微博登录没有301,302之类的跳转;而是返回200,然后用javascript实现的跳转
		// int statusCode = response.getStatusLine().getStatusCode();
		// if ((statusCode == HttpStatus.SC_MOVED_PERMANENTLY)
		// || (statusCode == HttpStatus.SC_MOVED_TEMPORARILY)
		// || (statusCode == HttpStatus.SC_SEE_OTHER)
		// || (statusCode == HttpStatus.SC_TEMPORARY_REDIRECT)) {
		// // 此处重定向处理 此处还未验证
		// String newUri = response.getLastHeader("Location").getValue();
		// get(newUri);
		// }
 
		// Get hold of the response entity
		HttpEntity entity = response.getEntity();
		// 取出跳转的url
		// location.replace("http://weibo.com/ajaxlogin.php?framelogin=1&callback=parent.sinaSSOController.feedBackUrlCallBack&ticket=ST-MTkxODMxOTI0Nw==-1309224549-xd-263902F174B27BAB9699691BA866EFF2&retcode=0");
		String location = getRedirectLocation(dump(entity));
		get(location);
	}
 
	private static String getRedirectLocation(String content) {
		String regex = "location\\.replace\\(\'(.*?)\'\\)";
		Pattern pattern = Pattern.compile(regex);
		Matcher matcher = pattern.matcher(content);
 
		String location = null;
		if (matcher.find()) {
			location = matcher.group(1);
		}
 
		return location;
	}
 
	/**
	 * 打印页面
	 * 
	 * @param entity
	 * @throws IOException
	 */
	private static String dump(HttpEntity entity) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(
				entity.getContent(), "utf8"));
 
		//return EntityUtils.toString(entity);
		return IOUtils.toString(br);
	}
 
	public static void main(String[] args) throws IOException {
		login("username", "password");
		String result = get("http://t.sina.com.cn/pub/tags");
		System.out.println(result);
	}
}

3. Perl版

Perl版代码是鑫哥给我的,未知原始来源,同样也稍作了修改

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
use LWP::UserAgent;
use HTTP::Cookies;
use HTTP::Headers;
 
my $ua = new LWP::UserAgent(keep_alive => 1);
$ua->timeout(5);
$ua->agent('Mozilla/4.0');
$ua->cookie_jar(HTTP::Cookies->new(file=>'getsina.cookies',autosave=>1));
 
my $res = $ua->post('http://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.3.11)',
    [
        service => 'miniblog',
        client => 'ssologin.js(v1.3.11)',
        entry => 'miniblog',
        encoding => 'utf-8',
        gateway => '1',
        savestate => '7',
        username => 'username',
        password => 'password',
        from => '',
        useticket => '0',
        url => 'http://t.sina.com.cn/ajaxlogin.php?framelogin=1&callback=parent.sinaSSOController.feedBackUrlCallBack',
        returntype => 'META',
    ],
);
if (!$res->is_success) {
    print STDERR $res->status_line, "\n";
}
 
my $req = HTTP::Request->new(GET => 'http://t.sina.com.cn/pub/tags');
$req->content_type('application/x-www-form-urlencoded');
$res = $ua->request($req);
print $res->as_string;
 
exit(0);

95 comments to 用Java和Perl登录新浪微博

  • test

    String regex = “location\\.replace\\(\'(.*?)\’\\)”;

  • liangwei

    之前是好的,前几天试了下不能登录了, 最后dump函数里用了 EntityUtil 就好了

  • nicexw

    楼主能否考虑下,现在新版的微博的JS内容的解析?

  • zfwslf

    楼主 perl的代码貌似登陆不上了
    我抓包之后没看见
    这两个 username => ‘username’,
    password => ‘password’
    参数对这个不是很懂

    entry=weibo&gateway=1&from=&savestate=7&useticket=1&ssosimplelogin=1&su=NTczMDExODEwJTQwcXEuY29t&service=miniblog&servertime=1320296033&nonce=1LIPVQ&pwencode=wsse&sp=d90c21ec6474af4c8b0d55366b971e9d7f3b440&encoding=UTF-8&url=http%3A%2F%2Fweibo.com%2Fajaxlogin.php%3Fframelogin%3D1%26callback%3Dparent.sinaSSOController.feedBackUrlCallBack&returntype=META

    • icycandy

      perl的代码我已经很久没有更新了,也不打算再更新,请参考HttpClient 4.x自行改写一下吧

  • shaoqing0594

    lz 弄微博登录两个礼拜了 还是不行 请教下 是不是现在sina又改变了 登录方式,如果是我改从哪里下手呢 谢谢

  • lirenjuan

    前几天登录,现在登录不了

  • lirenjuan

    方便加我QQ吗? 308920588 – 娟

  • leening

    entry=weibo&gateway=1&from=&savestate=7&useticket=1&ssosimplelogin=1&su=NTczMDExODEwJTQwcXEuY29t&service=miniblog&servertime=1320296033&nonce=1LIPVQ&pwencode=wsse&sp=d90c21ec6474af4c8b0d55366b971e9d7f3b440&encoding=UTF-8&url=http%3A%2F%2Fweibo.com%2Fajaxlogin.php%3Fframelogin%3D1%26callback%3Dparent.sinaSSOController.feedBackUrlCallBack&returntype=META
    httpClient4.x版本也不行了,在上面的代码中是没有了username和password字段,所以登录方式严重变化,还希望版主有时间的话给予解答,帮帮忙,谢谢了。

    • icycandy

      不好意思,实在没有精力来研究。我猜想username和password很有可能是通过javascript加密提交的,我对js一点都不会…

  • 紫枫闲人

    最近在研究新浪博客的client,遇到一些登陆的问题,也是用的ssologin.js,困扰了我很长时间,博主有联系方式吗?迫切希望能跟博主交流,或者请加我Q4157874

  • 糖果,好多人来访问哦,哈哈哈,最近我也弄这个呢,过来看看,不过你这个版本好老了……

Leave a Reply

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

  

  

  

*