登录网址:https://passport.csdn.net/account/login?ref=toolbar 项目源码:https://github.com/geekfly2016/Spider 代码目录:Spider/src/xyz/geekfly/csdn/Login.java
当我们对某些网站进行一些特定操作时,如知乎的点赞,会要求我们登录,这时候一些简单的做法就是粘贴浏览器请求中的Cookie信息,但作为自动化的程序来讲,这个方法明显不可行。因此就有了模拟登录的需求。 注:至于Cookie是什么,在网页请求时有什么用,不在本文讨论范围,自行Google吧。
模拟登录一般分为以下几步:
以CSDN登录为例,详细介绍每一步如何操作和代码实现: 1. 获取登录的所需的信息 打开CSDN,点击登录,即可看到登录页面,打开开发者工具。
注意先清空列表,勾选Preserve log(保持日志),这样点击登录跳转之后才能记录之前的请求。
输入自己的账号密码,点击登录,在第一个请求中我们可以看到登录请求所携带的参数,包括我们输入的用户名(username)和密码(password),但是发现还有几个其它参数。
再次退出,点击登录,查看表单发现存在这几个参数,因此模拟登录前需要获取这些参数。
方案是模拟登录前,先访问https://passport.csdn.net/account/login?ref=toolbar登录页面,使用Jsoup获取三个隐藏参数和表单提交的action(即为模拟登录的Url),保存以供下一步使用。 代码如下:
public static Map<String, String> getLoginInfo(){
String login_url = "https://passport.csdn.net/account/login?ref=toolbar";
String login_host = "https://passport.csdn.net"; //表单中获取的登录地址不带域名,需自行添加,拼接域名需注意‘/’,不要多加或漏加
Map<String, String> return_data = new HashMap<String, String>();
try {
Document document = Jsoup.connect(login_url)
.userAgent("ozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36")
.get();
//获取登录的表单
Elements element = document.select("#fm1");
// System.out.println(element);
//获取登录所需要的一些参数
return_data.put("lt", element.select("input[name=lt]").attr("value"));//登录流水号
return_data.put("execution", element.select("input[name=execution]").attr("value"));
return_data.put("_eventId", element.select("input[name=_eventId]").attr("value"));
//获取点击登录的请求地址
return_data.put("action", login_host + element.attr("action"));
}catch (IOException e) {
e.printStackTrace();
}
return return_data;
}
获取到的数据样例:
{ _eventId=submit, action=https://passport.csdn.net/account/login;jsessionid=092BDD9C93EF4EE91917E080BE78981F.tomcat2?ref=toolbar,
lt=LT-508266-gPApMyjqezncjwuO3e02HDefS3Faa3,
execution=e1s1
}
对于有些网站在分析之后,登录仅需要模拟点击登录所请求的Url带上用户信息即可,没有需要从登录页面获取参数的网站,不需要访问登录页面,只要找到模拟登录的Url即可。
2. 模拟提交账号信息,获取Cookie 在上一步点击登录后,可以在Response Headers中发现后台返回了很多参数,而在之后请求中,主要用到的也就是Cookie了,因此需要提取Cookie,而返回的又有很多个,需要自行拼接。
代码如下:
public static String getCookie(Map<String, String> data){
String cookie = "";
try{
HttpClient httpClient = new DefaultHttpClient();
HttpPost post = new HttpPost(data.get("action"));
/* 模拟登录所需要的参数,有些网站登录时会检测,
如果存在基本上为必须,但CSDN发现并没有检测,故没有添加
在Chrome开发者平台中可查看,粘贴过来即可
*/
// post.setHeader("Host", "passport.csdn.net");
// post.setHeader("Referer","https://passport.csdn.net/account/login?ref=toolbar");
// post.setHeader("Origin", "https://passport.csdn.net");
// post.setHeader("Content-Type","application/x-www-form-urlencoded");
List<NameValuePair> params = new ArrayList<NameValuePair>();
//参数
params.add(new BasicNameValuePair("lt", data.get("lt")));
params.add(new BasicNameValuePair("execution", data.get("execution")));
params.add(new BasicNameValuePair("_eventId", data.get("_eventId")));
//用户名和密码(*号),替换为自己的
params.add(new BasicNameValuePair("username", "******"));
params.add(new BasicNameValuePair("password", "*******"));
post.setEntity(new UrlEncodedFormEntity(params,Consts.UTF_8));
HttpResponse response = httpClient.execute(post);
int statusCode = response.getStatusLine().getStatusCode();
if(statusCode != 200){
System.out.print(statusCode);
}
Header[] map = response.getAllHeaders();
//如需查看所有的响应头,取消以下注释即可
/*System.out.println("显示响应Header信息\n");
for (Header entry : map)
{
System.out.println("Key : " + entry.getName() + " ,Value : " + entry.getValue());
}*/
//对于登录,主要为获取响应头中的Cookie信息,拼接Cookie
for (Header entry : map)
{
if(entry.getName().contains("Set-Cookie")){
cookie += entry.getValue() + ";";
}
}
System.out.println("Cookie信息:" + cookie);
}catch (Exception e) {
e.printStackTrace();
}
return cookie;
}
3. 携带Cookie进行目标操作 在后续请求中,携带Cookie即可。
public static String getData(String target_url, String cookie){
String result = null;
try{
HttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(target_url);
//传入Cookie信息
httpGet.setHeader("Cookie", cookie);
HttpResponse response = httpClient.execute(httpGet);
int statusCode = response.getStatusLine().getStatusCode();
if(statusCode != 200){
System.out.print(statusCode);
}
HttpEntity entity = response.getEntity();
if (entity != null) {
result = EntityUtils.toString(entity, "utf-8");
}
}catch (Exception e) {
e.printStackTrace();
}
return result;
}
主函数调度代码:
public static void main(String[] args) {
//1. 获取登录所需的信息
Map<String, String> login_info = getLoginInfo();
//2. 模拟登录获取Cookie
String cookie = getCookie(login_info);
//3. 携带Cookie访问目标页(换成自己的)
String target_url = "http://blog.csdn.net/tmaskboy";
//携带登录获取的Cookie
String result = getData(target_url, cookie);
Document document = Jsoup.parse(result);
System.out.println("携带Cookie:" + document.select(".navigator").text());
//未携带Cookie
String result1 = getData(target_url, "");
Document document1 = Jsoup.parse(result1);
System.out.println("未携带Cookie:" + document1.select(".navigator").text());
}
运行演示:
Cookie信息:CASTGC=TGT-147082-YbG1A3MxGJHOZTDoHerLF9uAAbE6xiw2tKxc95RszTJ53OdE6U-passport.csdn.net; Path=/; Secure;UserName=TMaskBoy; Domain=.csdn.net; Path=/;UserInfo=NO45ahI1532jJLeoAla%2FybWeLRchb6M4TE4Hy5%2B%2FYjgBdIsumoYTKx%2FLZHKTQ1QUgmGrCjbEmwLO53SS6yLYwKp25%2BKY62REyhgEe3HX2drygMQJuAyjq7%2FYKrZG7tUJ; Domain=.csdn.net; Path=/;UserNick=geekfly; Domain=.csdn.net; Path=/;AU=2DB; Domain=.csdn.net; Path=/;UD=%E5%94%AF%E6%9C%89%E5%89%B2%E8%88%8D%EF%BC%8C%E6%89%8D%E8%83%BD%E4%B8%93%E6%B3%A8%E3%80%82%E5%94%AF%E6%9C%89%E6%94%BE%E5%BC%83%EF%BC%8C%E6%89%8D%E8%83%BD%E8%BF%BD%E6%B1%82%E3%80%82; Domain=.csdn.net; Path=/;UN=TMaskBoy; Domain=.csdn.net; Expires=Mon, 15-Oct-2018 09:09:30 GMT; Path=/;UE="geekfly@126.com"; Version=1; Domain=.csdn.net; Max-Age=31536000; Expires=Mon, 15-Oct-2018 09:09:30 GMT; Path=/;BT=1508058570894; Domain=.csdn.net; Expires=Mon, 15-Oct-2018 09:09:30 GMT; Path=/;access-token=65d8afcc-f6ee-44b2-afca-5d2dbed642f6; Domain=.csdn.net; Path=/;
携带Cookie:目录视图 摘要视图 订阅 管理博客 写新文章
未携带Cookie:目录视图 摘要视图 订阅
我们可以看到携带Cookie后,访问个人主页菜单栏包括了管理博客和写新文章,未携带Cookie则不包括,说明模拟登陆成功。
后记:这里使用的是最简单的模拟登录案例了,稍复杂点的还有带验证码的,登录信息中跳转N次验证的,还有微信网页版那样的扫码验证的,骚年们,任重而道远,继续努力吧。
接下来这个专题写什么呢?