利用java和浏览器导出的cookies进行模拟登录百度贴吧

来源:互联网 发布:java 接口文档编写 编辑:程序博客网 时间:2024/05/15 23:47

这一久一直在尝试利用java写一个爬虫程序。java语言里面可以利用现成的工具包HttpClient+jsoup就能完成简单爬虫程序的编写。

爬虫程序的第一部就是“模拟登录”,模拟登录顾名思义也就是模拟浏览器提交表单的过程,因此需要对这个过程进行抓包分析,分析出在网站登录期间都提交了一些什么参数,然后利用这些参数构造相应的post请求;对于这种简单的抓包需求,我们用IE的F12开发者工具足够了用不着Wireshark这样复杂的工具。

最开始我尝试抓取登录知乎和自己学校的教务处,总的来说这两个网站的模拟登录post请求挺简单的。下面这个截图是知乎就是知乎的登录参数:

下面是抓取的整个过程:

1.打开IE浏览器,按下F12打开开发人员工具。

2.打开知乎的登录页,输入你的账户和密码或许还需要验证码,并提交。

3.这个时候开F12工具里面会充满了各种http请求和响应,找到方法为post的那几个请求并点开各个请求的正文(post方法和get方法的不同大家可以自行百度),总有一个有知乎的登录参数。如下图所示,第四个就是我们想要的,点开就能看见如上图所示的登录参数


4.对post参数的解析。总的来说一个网站登录时候post的参数分为随机和不是随机的两种。知乎登录需要四个参数,

_xsrf,email,password以及rember_me四个参数。

_xsrf:这是一个变动的值,但是我们可以从登录页面的源代码中找出该值来,具体到编程的时候你需要先向http://www.zhihu.com/这个网址发送一个get请求,然后从返回的结果中利用正则表达式获取到_xsrf的值。就像下面这样。

HttpClient httpClient = new HttpClients.createDefalut();HttpGet httpGet = new HttpGet("http://www.zhihu.com/");HttpResponse response = httpClient.execute(httpGet);HttpEntity responseEntity = response.getEntity();String responseHtml = EntityUtils.toString(responseEntity);String _xsrfValue = responseHtml.split("<input type=\"hidden\" name=\"_xsrf\" value=\"")[1].split("\"/>")[0];System.out.println("获取_xsrf的值成功,_xsrf 的值是 :" + _xsrfValue);
email:你的邮件地址

password:你的登录密码,可以看的出来知乎的密码在提交的时候是明文的。至于登录的密码是明文的,安全不安全?这又是另外一回事了。具体可以参考:https://www.zhihu.com/question/20060155

remenber_me:设置为true

我们可以看出来,登录一个网站的时候post的有些参数是固定的,而有一些参数是变动乃至随机的。比如这里的_xsrf就是变动的,这里我们采取了一种讨巧的做法,直接从网页的源代码中获取_xsrf。然而大多数时候很多post参数是随机生成的,需要你从网页的javascript代码中分析得出(当然不是所有的参数都需要用)。

当这些参数都构造好之后,我们就可以构造相应的post请求,不管你用的是java还是python写原理都一样。

List<NameValuePair> para = new ArrayList<NameValuePair>();           para.add(new BasicNameValuePair("_xsrf",_xsrf));para.add(new BasicNameValuePair("email",email));para.add(new BasicNameValuePair("password",password));para.add(new BasicNameValuePair("remember_me",remember_me));httpPost.setEntity(new UrlEncodedFormEntity(para,"UTF-8"));
我们可以看到模拟登录知乎是一件很简单的事情,网上也有很多教程。本文的重点不在于如何利用java模拟登录知乎。我们想得是可不可以利用相同的原理登录百度呢?我觉得应该是可以的,我在网上查了很久,不过一直没有找到合适的解决方案。下面我们就来看一下利用相同的方法我们能够得到什么结果.。

下面是我用自己账户登录百度的截图:



是不是下一跳,截图不完整,登录的参数一下子多了很多。而且大多数是用js代码生成的,观察password、token、username、verifycode(验证码)这几项。token这个字段是由服务器返回,你可以向获取_xsrf的值一样通过下面这个网址:https://passport.baidu.com/v2/api/?getapi&tpl=pp&apiver=v3得到。username是没有经过加密,只是经过了UTF-8编码。

重点来谈一下password,可以很明显地看出password不在是明文是经过加密的,而且参数里面还有rsakey这一项难道是用的RSA加密?我猜也是这样的:服务器端先发送一个RSA的公钥(publickey)给浏览器,然后浏览器利用js对用户提交的口令进行加密(保证提交口令),在将加密后的password发送到服务器进行验证。经过一番分析和搜索资料,发送公钥的是这个网址:https://passport.baidu.com/v2/getpublickey。一般的话发送如下内容:

{"errno":'0',"msg":'',"pubkey":'-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkjbcs3aXy\/ULgmC\/bdbZ5gwIP\nL+q3a0l0ET3+LyPhY5BFU3HNUXzkFVP7sZNM3DVEqL8iWhkB9vBaP3gEmRXX7Fxl\n3cJ3cDCI6w0WJStNIrYEeZGPwmEGYaBNE1BPB4NePc3oLhTDkQims60C4V4JswcC\nBPzg4N60x5ugo2c4zwIDAQAB\n-----END PUBLIC KEY-----\n',"key":'r1xVDjxLztyqUFGXPNLX90iEEatt0k1e'}
key即rsakey(不知道有什么用,应该不是加密用的公钥),经过百度这应该是一个pem文件。我们要做的就是从-----BEGIN PUBLIC KEY-----和-----END PUBLIC KEY-----中解析出公钥。

水平有限,我也就只能到这了。有能力的同学可以顺着这个思路做下去,在结合网页的js代码应该可以出结果的。

哪有没有其他的方法呢?我们可以换个思路,既然编写的程序是我们自己使用。我们大不必大费周章这样做。这种方法基于如下原理:当你登录网站成功之后,网站会给浏览器返回用于标识登录成功的cookies,当用户下次访问这个网站的时候,浏览器将这个cookies发送到服务器,服务通过读取这个cookies,判断用户处于登录状态。(当然这个cookies是有时效的)。既然这样我们想要登录百度就很简单了:通过浏览器登录到某一个网站,然后利用浏览器获取你登录以后的cookies;利用该cookies构造我们所要编写get请求的头部。我们就能很顺利的登录到该网站啦!就像下面这样:


用的是Apache的HttpClient,完整代码在这里,顺着这个思路。你应该就能写一个发帖机器人啦。

import java.io.File;import java.io.PrintWriter;import org.apache.http.HttpEntity;import org.apache.http.HttpResponse;import org.apache.http.client.config.CookieSpecs;import org.apache.http.client.config.RequestConfig;import org.apache.http.client.methods.HttpGet;import org.apache.http.impl.client.CloseableHttpClient;import org.apache.http.impl.client.HttpClients;import org.apache.http.util.EntityUtils; public class Test{private final static CloseableHttpClient httpClient;  static  {    RequestConfig requestConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD_STRICT).build();    httpClient = HttpClients.custom().setDefaultRequestConfig(requestConfig).build();  }public static void main(String[] args){new Test().firstGet();}public void firstGet() {    String tieba = "http://tieba.baidu.com/";        HttpGet httpGet = new HttpGet(tieba);        String Cookie = "";//在这里补充你的cookies        try {             httpGet.setHeader("Accept","text/html, application/xhtml+xml, image/jxr, */*");             httpGet.setHeader("User-Agent","Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko");             httpGet.setHeader("Content-Type","application/x-www-form-urlencoded;charset=UTF-8");             httpGet.setHeader("Connection","Keep-Alive");             httpGet.setHeader("host","tieba.baidu.com");             httpGet.setHeader("Accept-Language","zh-CN");             httpGet.setHeader("Referer","http://tieba.baidu.com/");             httpGet.setHeader("Cookie",Cookie);            HttpResponse response = httpClient.execute(httpGet);            HttpEntity responseEntity = response.getEntity();            if(response.getStatusLine().getStatusCode() ==  200 && responseEntity != null)            {             String responseHtml = EntityUtils.toString(responseEntity);             File baidu = new File("baidu/get.txt");             PrintWriter pw = new PrintWriter(baidu);             pw.println(responseHtml);             pw.close();            }        }        catch(Exception e) {            e.printStackTrace();        }        httpGet.abort();    }}











0 0
原创粉丝点击