java 模拟登陆百度,附带“专业抢二楼”功能。

最近看到java吧的吧主写了个自动抢二楼的脚本。觉得很奇妙,但是他不肯开源,是在不行了,自己摸索吧(当然网上也有类似教程,不过很多太老了)。

由于百度的登陆框是用js动态生成的,所以直接抓源码的话是拿不到你想要的表单的。

这次用的是 ie9。打开ie9进入“www.baidu.com”,按F12可以看到调试界面。我们先把缓存清理一下:


将下图的这两个勾打掉,以防止我们抓到的包由于页面跳转时被清理掉:


做好之后我们可以点击“开始捕获”按钮,然后先刷新一下当前的页面(这样可以避免输入验证码),跟平常一样点击登陆,在弹出框中输入用户名密码。

点击登陆,跳转到登陆后的页面之后,点击“停止捕获”按钮。

可以看到抓到了很多包。如果不知道从哪里入手的话呢,可以在下面所示的搜索框中输入自己刚刚填进去的密码(打码的是我的用户名和密码):


可以看到我们登陆进行post操作的参数,我们可以拷贝到记事本进行分析:

排除掉一些我们知道其含义的参数后,可得出一下未确定的参数:

&token=84a7862f4bf8c2aa8a1d22cf9fbade51
&tpl=mn
&tt=1389080269653
&codestring=
&u=http%3A%2F%2Fwww.baidu.com%2Findex.php%3Ftn%3D10018802_hao
&quick_user=0
&loginmerge=true
&splogin=rate
&ppui_logintime=8801

对于这些参数,我们登陆的时候要么不传,要么照着原来的值传过去。由于以前接触过新浪微博的sdk,它是采用OAuth2.0进行授权认证,认证完后会返回一个成功授权的token。所以可先重点考虑token从哪里来的。

先把token的值复制粘贴到搜索框中,可以看到

由上,我们得知token最早是通过get箭头所示的url得到的。

我们可以尝试着访问这个url看看能否得到一个token:


可以看到是不行的。

那么同样是get方式,为什么刚刚登陆的时候可以拿到token,但是现在却不行了呢?

我能想到的只有cookie了,查了一下cookie:

还是刚刚的第17个请求,可以看到浏览器其实发送了 BAIDUID等cookie。所以我们get的时候应该将之前的cookie一起发送过去,所以第一步应该先访问“www.baidu.com”,拿到cookie,再访问“https://passport.baidu.com/v2/api/?getapi&tpl=mn&apiver=v3&tt=1389080260852&class=login&logintype=dialogLogin&callback=bd__cbs__jndgh2”

同时将cookie发送过去,拿到token以进行登陆操作。

核心代码如下:

// 第一步,登陆百度,获取需要的cookie
org.apache.http.protocol.HttpContext httpContext = new BasicHttpContext();
httpContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);


HttpClient client = new DefaultHttpClient();
HttpGet httpGet1 = new HttpGet("http://www.baidu.com/");
client.execute(httpGet1, httpContext);


// 第二步,用cookie获特定的token,用于模拟登陆的post参数
HttpClient client2 = new DefaultHttpClient();
HttpGet httpGet2 = new HttpGet(
"https://passport.baidu.com/v2/api/?getapi&tpl=mn&apiver=v3"
+ "&tt=1388488343671&class=login&logintype=dialogLogin&callback=bd__cbs__4aeorp");
HttpContext context2 = new BasicHttpContext();
context2.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
HttpResponse response2 = client2.execute(httpGet2, context2);
String temp = EntityUtils.toString(response2.getEntity(), "UTF-8");
System.out.println(temp);
String temp1 = temp.substring(temp.indexOf("token") + 10);
可以看到输出结果:


可以通过解析字符串拿到token。然后在将参数post到“https://passport.baidu.com/v2/api/?login”。核心代码如下:

HttpClient client3 = new DefaultHttpClient();
HttpPost post = new HttpPost("https://passport.baidu.com/v2/api/?login");
List<NameValuePair> parameters = new ArrayList<NameValuePair>();
parameters.add(new BasicNameValuePair("staticpage",
"http://www.baidu.com/cache%2Fuser/html/v3Jump.html"));
parameters.add(new BasicNameValuePair("charset", "utf-8"));
parameters.add(new BasicNameValuePair("token", token));
parameters.add(new BasicNameValuePair("tpl", "mn"));
parameters.add(new BasicNameValuePair("apiver", "v3"));
parameters.add(new BasicNameValuePair("tt", "1388552675432"));
parameters.add(new BasicNameValuePair("safeflg", "0"));
parameters.add(new BasicNameValuePair("u", "http://www.baidu.com/"));
parameters.add(new BasicNameValuePair("isPhone", "false"));
parameters.add(new BasicNameValuePair("quick_user", "0"));
parameters.add(new BasicNameValuePair("loginmerge", "true"));
parameters.add(new BasicNameValuePair("logintype", "dailoglogin"));
parameters.add(new BasicNameValuePair("splogin", "rate"));
parameters.add(new BasicNameValuePair("username", "你的用户名"));
parameters.add(new BasicNameValuePair("password", "你的密码"));
parameters.add(new BasicNameValuePair("men_pass", "on"));
parameters.add(new BasicNameValuePair("callback",
"parent.bd__pcbs__5i3pfd"));
HttpEntity postBodyEnt = new UrlEncodedFormEntity(parameters,"utf-8");
post.setEntity(postBodyEnt);


HttpContext context3 = new BasicHttpContext();
context3.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
HttpResponse re = client3.execute(post, context3);

那么我们怎么知道自己登陆成功了呢?

如果登陆成功了,那么返回的html代码中应该会有一个err_no = 0 如下如ie9所示:


模拟登陆就写到这里。

现在我们看看抢二楼的,抢二楼需要用到 jsoup工具包来解析html。

首先我们可以先访问任意一个贴吧,比如linux吧,进入一个帖子进行回帖,为了方便讲解这里回复了纯字母的。


然后在抓包界面中搜索刚刚的回帖内容:


可以看到回帖时浏览器所提交的参数:


复制到记事本进行分析:

ie=utf-8                 编码
&kw=linux            贴吧名称
&fid=3171            
&tid=2801628284
&vcode_md5=     验证码
&floor_num=22   
&rich_text=1
&tbs=2caa0071fe0f49621389084151
&content=lu+guo+hun+yan+shu               回复内容
&files=%5B%5D                                        附件,这个其实是“[ ]”进过编码后就变成了%5B%5D
&mouse_pwd=23%2C18%2C19%2C9%2C16%2C28%2C18%2C21%2C44%2C20%2C9%2C21%2C9%2C20%2C9%2C21%2C9%2C20%2C9%2C21%2C9%2C20%2C9%2C21%2C9%2C20%2C9%2C21%2C44%2C20%2C23%2C16%2C23%2C28%2C44%2C20%2C22%2C19%2C19%2C9%2C18%2C19%2C29%2C13890841559370                                                           通过反编码,可以得出这个貌似是记录鼠标位置的,先不考虑
&mouse_pwd_t=1389084155937      
&mouse_pwd_isclick=0
&__type__=reply                                      类型

所以要找出的就剩下fid ,tid,floor_num,rich_text,tbs等参数的来源

可以先回到我们刚刚访问的贴吧页面,然后用审查元素(几乎每个浏览器都支持,这里用火狐):


可以看到,每个帖子都是用 li 标签的,回复是0的帖子里面有一个 reply_num = 0,而且里面的id貌似就是我们要找的参数中的 tid,对比了一下:


跟我们刚刚恢复的帖子的tid是一样的(参照上面贴出的tid参数)。我们进入该帖子,右键,查看网页源代码,可以看到网页源代码,然后在搜索看看是否有我们所需要的参数


依照这种方法,我们可以找到原来的网页中有 floor_num,rich_text,tbs;除去鼠标那些我们不管的参数,已经找齐了。

所以可分为以下步骤,在贴吧首页找到 有 reply_num = 0 标志的 li 标签,取出其tid。然后访问 帖子的详细页面“http://tieba.baidu.com/p/(替换为tid)”

在返回的html源码中找到我们需要的 fid,tbs,floor_num,rich_text 等参数的值,然后进行post提交即可。

首先借助jsoup解析某贴吧的首页,比如贝爷吧,代码如下:

//-----------水贴开始-----------------------
HttpClient client4 = new DefaultHttpClient();
HttpGet get = new HttpGet("http://tieba.baidu.com/f?kw=贝爷&fr=index");
HttpContext context4 = new BasicHttpContext();
context4.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
HttpResponse finalResponse = client4.execute(get, context4);



String result = EntityUtils
.toString(finalResponse.getEntity(), "utf-8");
Document doc = Jsoup.parse(result);
Elements elements = doc.getElementsByTag("li");     //找出所有li标签
for (Element e : elements) {
String lingherf = e.attr("data-field");
if (lingherf.contains("\"reply_num\":0")) {  //如果恢复数量是0的话,取出tid

final String tid = lingherf.substring(
lingherf.indexOf("\"id\":") + 5,
lingherf.indexOf(",\"reply_num"));
new GetHtmlThread(new MyCallBack() {      //开启线程抢二楼
           
@Override
public void nextStep(String html) {
// TODO Auto-generated method stub
System.out.println(html);

}


}, "http://tieba.baidu.com/p/" + tid, cookieStore,tid).start();

}
}

然后在访问帖子详细页面:

DefaultHttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet(URL);                          //这个url其实是上面开启线程传进来的那个url
HttpContext context = new BasicHttpContext();
context.setAttribute(ClientContext.COOKIE_STORE, store); //为了消除cookie的影响,一路保存cookie
try {
HttpResponse response = client.execute(get, context);
html = EntityUtils.toString(response.getEntity(), "utf-8");

                        // 取出我们所需要的参数,不会正则表达式哈,见笑。
String fid = html.substring(html.indexOf("fid:'"),
html.indexOf("fid:'") + 20);
fid = fid.substring(fid.indexOf("'") + 1, fid.lastIndexOf("'"));
String floor_num = html.substring(html.indexOf("floor_num:\""),
html.indexOf("floor_num:\"") + 20);
floor_num = floor_num.substring(floor_num.indexOf("\"") + 1,
floor_num.lastIndexOf("\""));
String rich_text = html.substring(html.indexOf("rich_text:'"),
html.indexOf("rich_text:'") + 20);
rich_text = rich_text.substring(rich_text.indexOf("'") + 1,
rich_text.lastIndexOf("'"));
String tbs = html.substring(html.indexOf("'tbs'  : \""),
html.indexOf("'tbs'  : \"") + 40);
tbs = tbs.substring(tbs.indexOf("\"") + 1, tbs.lastIndexOf("\""));
ArrayList<NameValuePair> para = new ArrayList<>();
para.add(new BasicNameValuePair("ie", "utf-8"));
para.add(new BasicNameValuePair("kw", "贝爷"));
para.add(new BasicNameValuePair("fid", fid));
para.add(new BasicNameValuePair("tid", tid));
para.add(new BasicNameValuePair("floor_num", floor_num));
para.add(new BasicNameValuePair("rich_text", rich_text));
para.add(new BasicNameValuePair("tbs", tbs));
para.add(new BasicNameValuePair("content", "我就路过抢个二楼,混个脸熟。"));

                        //鼠标的参数可以照着原来的参数反编码后原样传回去
para.add(new BasicNameValuePair(
"mouse_pwd",
"125,118,125,99,125,120,125,122,70,126,99,127,99,126,99,127,99,126,99,127,99,126,99,127,99,126,99,127,70,124,126,123,120,124,70,126,124,121,121,99,120,121,119,13885747519790"));
para.add(new BasicNameValuePair("mouse_pwd_t", "1388574751979"));
para.add(new BasicNameValuePair("vcode_md5", ""));
para.add(new BasicNameValuePair("flies", "[]"));
para.add(new BasicNameValuePair("mouse_pwd_isclick", "0"));
para.add(new BasicNameValuePair("__type__", "reply"));


// TODO Auto-generated method stub
HttpPost post = new HttpPost(
"http://tieba.baidu.com/f/commit/post/add");
DefaultHttpClient client1 = new DefaultHttpClient();
HttpEntity postBodyEnt;


postBodyEnt = new UrlEncodedFormEntity(para, "utf-8");
post.setEntity(postBodyEnt);
System.out.println(EntityUtils.toString(postBodyEnt));
HttpContext context1 = new BasicHttpContext();
context1.setAttribute(ClientContext.COOKIE_STORE, store);
HttpResponse response1 = client1.execute(post, context1);

由于贝爷吧没二楼抢,换了个贴吧,可以看到水贴结果:


到这里就结束了。最后在吼一吼我最喜欢的一句话!

技术因分享而强大!


用户名,Email地址,昵称 ajax无刷新验证是否已注册 非空验证 用户名验证:由英文字母和数字组成的4-16位字符,以字母开头! 邮箱验证:Email格式不正确,例如web@sohu.com 昵称验证:由汉字组成的2-8位字符! 密码验证:密码不能含有非法字符,长度在4-10之间 再次输入密码验证:两次输入密码不一致! 注册成功后用户直接保存在session里进入登录页面 搜索框实现智能联想(根据关键字联想贴吧名搜索) 登录成功用户保存在session中显示用户昵称 登录失败显示(登录失败!请重新) 注销可以销毁session中的用户对象 横条广告用flash制作替换效果 个人中心显示用户头像及昵称 奇吧朵朵展示留个贴吧信息(滚动文字) 最新话题展示最新发帖标题并可点击进入 常逛贴吧由用户登录后显示 贴吧分类显示不同类型贴吧鼠标移动上去展示贴吧名 热帖分类展示四个贴吧四条回复 热帖排行榜显示回复最多三个帖子 顶部展示贴吧名称,会员数,帖子数,以及帖吧简介 帖子显示回复次数,标题,内容25字符发帖昵称以及发帖时间 签到按钮可以判断是否登录,签到成功次数加一,提示以签到 显示用户头像和昵称 恢复按钮AJAX判断是否登录登录后方可发帖 右侧游戏动态加载 翻页可实现看第一页,向前和向后翻页 顶部显示广告,帖子标题 只看楼主可实现只看楼主发表内容,取消只看楼主查看全部回复 显示回复用户头像和昵称,回复内容签名档,楼层,发表时间 关注AJAX判断用户是否已登录,关注成功次数加一,已关注提示 鼠标移动到用户头像可查看用户信息 实现翻页功能 回复条数,返回当前贴吧 回复按钮AJAX判断是否已登录登陆后方可发帖 我的帖子显示吧名,标题,回复次数,发帖时间,删除提示,删除失败提示 我关注的帖吧显示把名,标题,回复次数,发帖时间,删除提示,删除失败提示
评论 25
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值