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登录新浪微博

  • live http header这个用着很方便啊,抓包一直用ethereal。。。Wireshark这个看上去更好用 ;D

  • cx

    Live HTTP headers真是好东东,看到了Content-Length里面的内容,语言就不是问题了

  • 确实不错,看到Content-Length中的内容后,语言什么的都是神马

  • 刷屏多出了一条。。

  • wx098

    用循环反复get好像会connection refused,即使每次休息20秒都不行,请问可能是什么原因呢?

    • icycandy

      你试试休息更长时间看行不行。对于一些防爬虫的网站,还需要设置好client的header参数,比如第二幅图里的Referer和User-Agent等等。

      • wx098

        谢谢回复。我就是访问新浪微博。我把参数设好了再试一下。其实还有个问题想请教,爬虫运行的时候有时候会卡住,什么错也没有,就是网页抓捕下来。你觉得会是settimeout的问题吗?

        • icycandy

          我猜也许和网络情况有关,比如你的网关限制了带宽,或者新浪方面限制了每分钟爬取的次数。

          你可以装个性能测试的插件,比如Eclipse TPTP之类的,来分析程序运行的时间主要消耗在哪些代码行。找到那些运行得很慢的代码以后,再去分析原因。

  • cnwolf

    哥们,我用了下java代码的,好像没有登录啊。难道新浪改了?

    • icycandy

      当时写这篇日志时测试是能登录的。
      首先请检查一下在浏览器里是否能正常登录新浪微博,先把网络问题排除掉;然后照文中第1步的方法获取新的登录参数,再登录试一试。

  • cwu

    上面的代码的确不行了,新浪好像更换了点策略,我看它参数里增加了个什么时间什么的,可能还要研究下他生成这个时间用的js,否则会报超时。还没仔细看,晚上回去研究研究

  • 好像可以的。可能是我搞错了。但是改成先post登录,再来个post评论就不行了。我手动设置了cookies貌似可以了。但我不明白为什么你的代码里最后的httpclient get并没有设置cookies,却正常呢。
    当然,我暂时还不确定。等我测试几次再来

    • icycandy

      可能是因为post和get在同一个http会话里面(二者的代码是在同一个方法里面),所以不用设置cookies
      建议你去了解一下httpclient管理cookies的方法,之后这类问题就应该能很好的解决了

  • zhaojiguang

    我用这种方式登录,返回来的页面源代码并没有登录var $CONFIG = {
    $lang : “zh”,
    $oid : “”,
    $uid : “”,
    $severtime : “1301031702”,
    $token : “b85b158144832b8f50aaa02074b1e391”,
    $product : “miniblog”,
    $pageid : “login”,
    $cuser_status : “full”,
    $skin : “skin_001”,
    $domain : “t.sina.com.cn/”,
    $FW : “0”
    oid还是空的,登录了不应该是空的,不知道你们返回数据,这个值是什么样的

  • zhaojiguang

    这个password => ‘password’,在抓包工具里看不是明文的,这篇文章有很详尽的论述http://www.blogjava.net/cenwenchu/archive/2011/03/13/345663.html,我真不知道上述代码是如何登录进去的,我也测试了几天,没看见预期效果

    • icycandy

      请参看日志更新的部分。同时非常感谢你提供的链接。

      • zhaojiguang

        日志更新的部分指那部分。能不能贴点你程序返回的数据,最好能向我邮箱里发一次,测试url为http://t.sina.com.cn/k/iphone,谢谢

  • 不错啊,学习到一些抓包及分析的方法!

  • vicyo

    新浪微博POST不难啊..

  • 这个Java的代码现在登不了了,我也通过Live HTTP headers工具重新抓取了post的地址和参数。现在好像新浪的密码在前端有了加密。能帮忙看看你的这段代码现在怎样登录到sina吗?O(∩_∩)O谢谢了

    • icycandy

      我刚刚测试了日志中的java代码,发现能够成功获取到登录后的内容,你再试一试吧。

  • 根据抓取结果修改下参数设置就好了!

  • 咕~~(╯﹏╰)b
    那个能把代码和jar包邮件发我一下么
    邮箱 admin@viluo.com
    你这边好像是用httpclient 3.X ,我现在是4.X 。
    O(∩_∩)O谢谢啦

    我今天抓取了下sina的登录post内容
    里面好像还把密码加密了下再提交到服务器的

  • 咕~~(╯﹏╰)b
    完全按照你这个代码是可以的

    我之前由于抓取了新浪的最新的登录
    里面是ssologin.js(v1.3.12)
    密码都加密过

    嘿嘿 有时间看看这个:http://www.iteye.com/topic/1039052
    挺有意思的

    能互加个友链不
    我的是www.viluo.com

  • shen

    我用httpclient4.0照你的重写了一遍,里面中文内容是乱码

    • icycandy

      乱码大多是由于编码设置错误而引起的。我在日志中添加了用HttpClient 4.x 登录新浪微博的示例代码,你可以参考一下。

      • shen

        可以了多谢指导,不过想和你讨论下,你用的模拟登录方式,貌似不是新浪微博本生的登录界面(我同FIREBUG抓包了,和你的不一样,他的密码用js加密了,很多参数也不一样),你用的是新浪会员的登录界面,取得了cookie后跳转到了新浪微博。。。

        • icycandy

          你看我日志中的第2张图片,那是很久之前截的图,那时候密码就已经是加密的。我刚刚用Live HTTP headers抓到了参数,和之前相比几乎差不多。日志中的代码能够成功运行就说明,post一个未加密的密码过去也是能够正常登录的。

  • linlinno

    结合您的两篇日志,我写了一个密码加密的新浪微博模拟登陆的代码,上周还运行的好好的,这周就挂了,希望达人指导。。。

  • linlinno

    您的代码貌似也登陆不了了。。。

    • icycandy

      你可以把代码贴出来,希望有人能帮到你。我的代码刚刚测试过,确实可以登录的。
      打印出来的结果有类似下面这样的就说明登录成功了,

      <div class="sim_tag"><a href="/pub/tags/%E9%9F%B3%E4%B9%90" rel="nofollow">音乐</a><em>(1610747)</em></div>
  • linlinno

    我发现貌似是我的账号被禁了。。。换了个账号就好了。。。

Leave a Reply to linlinno Cancel 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>

  

  

  

*