最新动态
模拟登陆百度并发帖
2024-12-06 16:39  浏览:64

用程序模拟提交表单登录百度。

模拟登陆百度并发帖

从实用意义上说,这种问题其实意义不大,并且也并不适合写成博客。百度网页在不断变化,而此博客内容却不会相应更新,无法保证内容的正确性。 从学习知识方面说,这种问题适合作为学习课题。这几天学了下python,感触良多。python确实比java灵活,语法也有许多漂亮的特性。比如多行字符串,raw字符串(无需转义的字符串),在java中都没有,好难受。 这种问题需要耐心,像破解密码一样,需要去尝试,去理解,去猜想,耗费时间和精力,性价比较低,有这功夫就不如多学点别的。还是应该多多学习,孔子曰:终日而思,不如须臾之所学也。意思是说:思考一天不如学习半晌。

chrome浏览器,ctrl+u打开源代码,f12打开开发者工具。重点监测network,设置成preserve模式,实验之前清空过去的cookie和缓存等信息,排除干扰。剩下的任务就是盯着network的同时,执行登录,登出,发帖,评论等动作,然后查看cookie的变化及返回结果。从数据中发挥想象力,大胆猜测,寻找规律。

三步走,登陆成功

1. 首先,访问百度的任何一个页面,都会获得一个百度id(BAIDUID),这是一个cookie;

2. 其次,访问https://passport.baidu.com/v2/api/?getapi&tpl=mn&apiver=v3&class=login页面获取token

3. 最后,对https://passport.baidu.com/v2/api/?login页面提交表单

v2表示version2。此页面get请求后面的参数不同返回的结果也不同。 一开始抓包时,在浏览器中看到的参数是这样的:

- getapi:

- tpl:mn

- apiver:v3

- tt:1461752974956 登录时间

- class:login行为是登录,而非其它行为

- gid:36400D4-3078-460D-ABD8-9DEFBA99604B

- logintype:dialogLogin 登录类型,通过对话框登录

- callback:bdcbsgyljq1 回调

返回的结果是这样的:

这是一个不纯的json串,有些冗余。errInfo结果为0表示一切顺利,data是一个json串,里面唯一有用的信息是token。 这个get请求参数有许多是多余的,请求参数不同,返回的结果不同,可以直接在浏览器地址栏中测试。去掉callback参数之后,最后变成:getapi&apiver=v3参数,返回的json串就变得十分周正了。

再去掉apiver=v3(apiversion=3)属性,参数变为:getapi&class=login时,返回值就变成了键值对的方式:

所以,version2需要getapi和class=longin两个属性,version3需要getapi和apiver=v3两个属性,其中没有tpl=mn属性登录会失败,虽然可以返回json串,但是用于登录时,必须要有tpl=mn属性。 version2好像log4j得配置文件有没有。如何解析出来呢?可以用正则表达式,也可以用json解析version3的返回结果,还可以用属性解析version2的返回结果。正则表达式效果应该最好。 对于这种问题有两个原则(虽然矛盾,要寻找一个平衡): * 能删的参数尽量删掉 * 没有必要费精力试参数,直接全弄上,多了总不会错(但可能格式会难看一些)

在浏览器中看到的表单数据项很多,其中有许多是毫无用处的,没有它们照样登陆成功。经过删了测,测了删,发现只有如下表单有用:

再删就要出错了,tpl=mn这个属性还是必不可少。在这一步里,用到了第二步获取的token。 登录百度,不需要设置浏览器头部伪装成浏览器,也不需要伪装referer等头部,直接get,get,post三步走就登陆成功了。cookie也不需要管,因为api自己处理了cookie。本次请求会自动带上上次获得的cookie。 登录百度首页之后,就可以访问百度的各个部分了(包括贴吧,知道等)。 如何验证有没有登陆成功呢?有两种方法: 0. 访问www.baidu.com,看看页面里面有没有自己的名字 1. 查看cookie里面有没有PTOKEN和STOKEN等关键cookie

百度返回值说明,no表示错误码(0为正常),errorcode也表示错误码,error表示错误信息,data表示数据:

用到第三方库fastjson进行json解析,apache httpclient进行网络请求。

终于登陆成功了,下一步就要发帖了。百度贴吧的数据类型十分重要,这个层次不分清楚就不好办。

* 贴吧forum,forum是论坛的意思,贴吧是一个大话题,是一个比较大的类型。它下面是许多分支,是大话题的细化。比如:金庸吧包括很多thread,武功最高的人是谁?扫地僧和独孤求败谁厉害?....每一个thread都会引发很多post(帖子),而每一个帖子又会引来人们的评论。

* 话题thread,提出话题就相当于准备盖个楼。

* 帖子post,每一个post都为thread添加了一层楼。

* 评论comment,每一个post下面可以有评论,这样针对性才强,盖楼是表达自己的观点犹如重武器,长枪大戟发前人之所未发,评论就像小匕首短兵刃一样更直接。

常见错误类型:

* 没有tbs,返回230308,其中错误码是308,230是前缀

* 265是错误码,230是固定的前缀,这个大概是发帖太频繁,禁止发帖

* 40是验证码:发帖太频繁,需要验证码,如果能破解验证码,那自然是大大的好,下面就是返回的json串,str_reason表示“请点击验证码完成发贴”。

tbs从http://tieba.baidu.com/dc/common/tbs获得,只需要get一下,解析出json传中的tbs即可。tbs相当于贴吧通行证,你发的每一个评论,盖的每一层楼提交时都需要提交tbs,它们的tbs可以相同,这个tbs是你最近一次获得的tbs,服务器上维持着一份hashmap记录用户id和tbs值。

许多属性是没必要的,一次成功之后删繁就简,删了测测了删,发现header是没有用的,许多表单域也是可有可无的。 表单属性介绍如下:

* kw:thread名称,也就是话题名称

* tid: threadId,也就是话题id,在地址栏中就可以看见tid。

* fid:一个thread好像fid都是一样的,大概跟tid差不多吧,反正据我观察,在一个话题下发了很多贴它是不变的。 打开一个话题主页,比如:http://tieba.baidu.com/p/4195311174,ctrl+u查看源代码,ctrl+f查找关键词fid,很容易发现整页上的fid都是一模一样的。 百度用什么做主键:用long做主键!百度也不用uuid,博客园也不用uuid,很明显可以从网页上看出来。

java确实很长,还是看看python吧,简短有力更适合描述问题。java并不是总是冗长,它要想简单也很容易设计出简洁的API。

java的复杂来源于三个个方面:

* 库设计的不合理,”每次只做一件事,每步只做一件事“的哲学有点像汇编,有些冗长,并且java不屑于设计语法糖

* 问题本身就很复杂,需要进行许多配置,更灵活,python虽短,可能有些事情没法办,因为封装地太严密了,留下的接口太少了。

* 库设计的不合理+问题本身就复杂。这里面有一个概率问题,复杂问题不常用,你却让人们用大量的时间去考虑它们,这就不如预先设计一种简单不完善的接口。宁可简单的缺憾,也不要复杂的完善。举一个例子,选中多行按下tab键之后是应该缩进还是应该替换,当然是缩进了,如果我要替换我是不会这么操作的,缩进带来的简捷性非常大。

把上面的代码串联起来,是这样子的:

关键是tbs只需要获取一次,然后作为全局变量存在就可以了,不需要反复获取。

tieba.baidu.com/f/index/feedlist?tagid=all&limit=2000000&offset=0 这个链接十分重要。有些链接需要复制到地址栏才能访问而不能直接跳转过去,因为服务器可能不允许跨域访问。 它的参数 tagid=like | all 表示请求的标签列表的类型,like表示只返回我喜欢的,all表示返回全部。 limit表示条数,offset表示偏移量。它还有许多其他参数,比如last_tid最后一条的时间(用于加载更多),&_表示 这个链接是怎么知道的,访问tieba.baidu.com加载更多就会向这个feedlist发出请求。 通过jsoup解析html就可以得到好多贴吧及它们的tid了,然后点进去就可以获得fid了,有了tid和fid就可以盖楼了。

 

apache的httpClient组件包含多个部分,比如httpAsycClient是带回调函数的请求服务器;fluent部分是流畅版的httpclient,写起来简直溜溜溜。不信请看:

        Request.Get("http://somehost/")
                .connectTimeout(1000)
                .socketTimeout(1000)
                .execute().returnContent().asString();
        // Execute a POST with the 'expect-continue' handshake, using HTTP/1.1,
        // containing a request body as String and return response content as byte array.
        Request.Post("http://somehost/do-stuff")
                .useExpectContinue()
                .version(HttpVersion.HTTP_1_1)
                .bodyString("important stuff", ContentType.DEFAULT_TEXT)
                .execute().returnContent().asBytes();
        // Execute a POST with a custom header through the proxy containing a request body
        // as an HTML form and save the result to the file
        Request.Post("http://somehost/some-form")
                .addHeader("X-Custom-header", "stuff")
                .viaProxy(new HttpHost("myproxy", 8080))
                .bodyForm(Form.form().add("username", "vip").add("password", "secret").build())
                .execute().saveContent(new File("result.dump"));

这代码确实是写得好

    以上就是本篇文章【模拟登陆百度并发帖】的全部内容了,欢迎阅览 ! 文章地址:http://lanlanwork.gawce.com/quote/10712.html 
     行业      资讯      企业新闻      行情      企业黄页      同类资讯      网站地图      返回首页 阁恬下移动站 http://lanlanwork.gawce.com/mobile/ , 查看更多