【教程】模拟登陆百度之Java代码版

【背景】

之前已经写了教程,分析模拟登陆百度的逻辑:

【教程】手把手教你如何利用工具(IE9的F12)去分析模拟登陆网站(百度首页)的内部逻辑过程

然后又去用不同的语言:

Python的:

【教程】模拟登陆网站 之 Python版(内含两种版本的完整的可运行的代码)

C#的:

【教程】模拟登陆网站 之 C#版(内含两种版本的完整的可运行的代码)

去实现对应逻辑。

此处,继续尝试,用Java代码,实现这套,模拟登陆百度,的逻辑。

【折腾过程】

1.之前已经整理了一些Java代码:

http://code.google.com/p/crifanlib/source/browse/trunk/java/crifanLib.java

现在是:

继续去丰富此套库。

然后把模拟登陆百度的逻辑模拟出来。

2.期间,想要实现Java的函数的默认参数,结果却发现不支持:

【已解决】Java中函数的默认参数

3.然后就是一点点去写代码,去调试了。

4.期间,出错了:

【基本解决】java中没法new:Cannot instantiate the type HttpParams

5.再去搞懂参数配置:

【整理】关于Java中的httpClient中可以传入的参数

6.再继续写代码,期间遇到各种问题,基本都解决了:

【已解决】Java代码中new List时出错:Cannot instantiate the type List<NameValuePair>

【已解决】实现Java中控制台中输入字符串

【无需解决】Java代码new BasicNameValuePair时出错:The constructor BasicNameValuePair(String, boolean) is undefined

【已解决】Java中实现{String, boolean}类型的字典Dict变量

【已解决】Eclipse中用java代码去new Date结果出错:The constructor Date(String) is deprecated

【暂未解决】Eclipse中调试Java代码期间如何修改值

【已解决】Java中的new Date所得的年份异常:传入2043年结果却是3943年

 

7.最终,完成了,主体代码为:

/**
 * [File]
 * EmulateLoginBaidu.java
 * 
 * [Function]
 * Use Java code to emulate login baidu
 * 
 * 【教程】模拟登陆百度之Java代码版
 * http://www.crifan.com/emulate_login_baidu_use_java_code
 * 
 * [Version]
 * v1.0, 2013-09-17
 * 
 * [Note]
 * 1. need add apache http lib:
 * 【已解决】Eclipse的java代码出错:The import org.apache cannot be resolved
 * http://www.crifan.com/java_eclipse_the_import_org_apache_cannot_be_resolved/
 * 2.need crifanLib.java
 * http://code.google.com/p/crifanlib/source/browse/trunk/java/crifanLib.java
 * 
 * [History]
 * [v1.0]
 * 1. initial version, finally successfully emulate login baidu using java code.
 */

//import java.io.IOException;
import java.util.ArrayList;
//import java.util.Calendar;
//import java.util.Date;
//import java.util.GregorianCalendar;
import java.util.HashMap;
//import java.util.Hashtable;
import java.util.List;
//import java.util.Map;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.cookie.Cookie;
//import org.apache.http.impl.cookie.BasicClientCookie;
//import org.apache.http.impl.cookie.BasicClientCookie2;
import org.apache.http.message.BasicNameValuePair;

//import crifanLib;

/**
 * @author CLi
 *
 */
public class EmulateLoginBaidu {
	static crifanLib crl;

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		crl = new crifanLib();
				
		// TODO Auto-generated method stub
		EmulateLoginBaiduUsingJava();
	}

	// emulate login baidu using java code	
	public static void EmulateLoginBaiduUsingJava()
	{
		System.out.println("============ 程序说明 ============");
		System.out.println("功能:本程序是用来演示使用Java代码去实现模拟登陆百度");
		System.out.println("注意事项:部分百度账户,在登陆时会出现:");
		System.out.println("1.部分百度账户,在登陆时会出现:");
		System.out.println("系统检测到您的帐号疑似被盗,存在安全风险。请尽快修改密码。");
		System.out.println("此时,本程序,无法成功模拟登陆,请自行按照提示去修改密码后,就可以了。");
		
		boolean bLoginBaiduOk = false;
		List<Cookie> curCookieList;
		
		//step1: login baidu, got cookie BAIDUID
		System.out.println("====== 步骤1:获得BAIDUID的Cookie ======");
		String strTokenValue = "";
		boolean bGotCookieBaiduid = false;
		String strBaiduUrl = "http://www.baidu.com/";
		HttpResponse baiduResp = crl.getUrlResponse(strBaiduUrl);
		
		curCookieList =crl.getCurCookieStore().getCookies(); 
		crl.dbgPrintCookies(curCookieList, strBaiduUrl);
		for(Cookie ck : curCookieList)
		{
			String cookieName = ck.getName();
			if(cookieName.equals("BAIDUID"))
			{
				bGotCookieBaiduid = true;
			}
		}
        if (bGotCookieBaiduid)
        {
        	System.out.println("正确:已找到cookie BAIDUID");
        }
        else 
        {
        	System.out.println("错误:没有找到cookie BAIDUID !");
        }
		
		//step2: login, pass paras, extract resp cookie
        System.out.println("====== 步骤2:提取login_token ======");
        boolean bExtractTokenValueOK = false;
		if(bGotCookieBaiduid)
		{
			//https://passport.baidu.com/v2/api/?getapi&class=login&tpl=mn&tangram=true
			String getapiUrl = "https://passport.baidu.com/v2/api/?getapi&class=login&tpl=mn&tangram=true";
			String getApiRespHtml = crl.getUrlRespHtml(getapiUrl);
			
			curCookieList =crl.getCurCookieStore().getCookies(); 
			crl.dbgPrintCookies(curCookieList, getapiUrl);

			//bdPass.api.params.login_token='3cf421493884e0fe9080593d05f4744f';
			Pattern tokenValP = Pattern.compile("bdPass\\.api\\.params\\.login_token='(?<tokenVal>\\w+)';");
			Matcher tokenValMatcher = tokenValP.matcher(getApiRespHtml);
			//boolean foundTokenValue = tokenValMatcher.matches(); // will not match, but can search to find it
			boolean foundTokenValue = tokenValMatcher.find();
			if(foundTokenValue)
			{
				strTokenValue = tokenValMatcher.group("tokenVal"); //3cf421493884e0fe9080593d05f4744f
				System.out.println("正确:找到 bdPass.api.params.login_token=" + strTokenValue);
				
				bExtractTokenValueOK = true;
			}
			else
			{
				System.out.println("错误:没找到bdPass.api.params.login_token !");
			}
		}
		
		//step3: verify returned cookies
        if (bGotCookieBaiduid && bExtractTokenValueOK)
        {
        	System.out.println("======步骤3:登陆百度并检验返回的Cookie ======");
        	
        	/*
        	//Note:
        	//here, has verify, not manually update some cookie's domain and expiry
    		//also can emulate baidu successfully
        	
        	//do some workaround to makesure here cookie H_PS_PSSID not expire
        	//[version: 0][name: H_PS_PSSID][value: 3359_3341_2776_1424_2981][domain: .baidu.com][path: /][expiry: null]
        	
			//Thu Sep 17 14:22:08 CST 2043
        	//Date newExpiryDate = new Date(2043, 9, 17);
        	Date newExpiryDate = new Date(143, 9, 17);
			//Calendar newExpiryCalendar = new GregorianCalendar(2043, 9, 17, 14, 22, 8);
        	
        	BasicClientCookie hPsPssidCookie = null;
        	BasicClientCookie dbsvrtmCookie = null;
        	//int hPsPssidCookieIdx = 0;
        	
        	curCookieList = crl.getCurCookieList();
        	for(Cookie ck : curCookieList)
        	{
        		if(ck.getName().equalsIgnoreCase("H_PS_PSSID"))
        		{
        			//hPsPssidCookieIdx = curCookieList.indexOf(ck);
        			hPsPssidCookie = (BasicClientCookie) ck;
        			hPsPssidCookie.setExpiryDate(newExpiryDate);
        			ck = hPsPssidCookie;
        			//break;
        		}
        		
        		if(ck.getName().equalsIgnoreCase("BDSVRTM"))
        		{
        			dbsvrtmCookie = (BasicClientCookie) ck;
        			dbsvrtmCookie.setDomain(".baidu.com");
        			dbsvrtmCookie.setExpiryDate(newExpiryDate);
        			ck = dbsvrtmCookie;
        			//break;
        		}
        	}
        	crl.setCurCookieList(curCookieList);
        	*/

        	
        	String staticPageUrl = "http://www.baidu.com/cache/user/html/jump.html";

        	List<NameValuePair> postDict = new ArrayList<NameValuePair>();
        	//ArrayList<NameValuePair> headerDict = new ArrayList<NameValuePair>();
        	//postDict.add(new BasicNameValuePair("ppui_logintime", ""));
            postDict.add(new BasicNameValuePair("charset", "utf-8"));
            //postDict.add(new BasicNameValuePair("codestring", ""));
            postDict.add(new BasicNameValuePair("token", strTokenValue));
            postDict.add(new BasicNameValuePair("isPhone", "false"));
            postDict.add(new BasicNameValuePair("index", "0"));
            //postDict.add(new BasicNameValuePair("u", ""));
            //postDict.add(new BasicNameValuePair("safeflg", "0"));
            postDict.add(new BasicNameValuePair("staticpage", staticPageUrl));
            postDict.add(new BasicNameValuePair("loginType", "1"));
            postDict.add(new BasicNameValuePair("tpl", "mn"));
            postDict.add(new BasicNameValuePair("callback", "parent.bdPass.api.login._postCallback"));
        	
            //get input baidu username and password
            String strBaiduUsername = "";
        	String strBaiduPassword = "";
            Scanner inputReader = new Scanner(System.in);
            System.out.println("Please Enter Your:" );
            System.out.println("Baidu Username:" );
            strBaiduUsername = inputReader.nextLine();
            //System.out.println("You Entered Username=" + strBaiduUsername);
            System.out.println("Baidu Password:" );
            strBaiduPassword = inputReader.nextLine();
            //System.out.println("You Entered Password=" + strBaiduPassword);
            inputReader.close();

            postDict.add(new BasicNameValuePair("username", strBaiduUsername));
            postDict.add(new BasicNameValuePair("password", strBaiduPassword));
            
            postDict.add(new BasicNameValuePair("verifycode", ""));
            postDict.add(new BasicNameValuePair("mem_pass", "on"));

            String baiduMainLoginUrl = "https://passport.baidu.com/v2/api/?login";
            String loginBaiduRespHtml = crl.getUrlRespHtml(baiduMainLoginUrl, null, postDict);
            
            //Map cookieNameDict = new Map();
            //Map cookieNameDict = new Hashtable();
            HashMap<Object, Boolean> cookieNameDict = new HashMap<Object, Boolean>();     
            cookieNameDict.put("BDUSS", false);
            cookieNameDict.put("PTOKEN", false);
            cookieNameDict.put("STOKEN", false);
            //Set-Cookie: SAVEUSERID=deleted; expires=Mon, 17-Sep-2012 09:45:03 GMT; path=/; domain=passport.baidu.com; httponly,
            //cookieNameDict.put("SAVEUSERID", false);
            
            curCookieList = crl.getCurCookieList();
            for(Object objCookieName : cookieNameDict.keySet().toArray())
            {
            	String strCookieName = objCookieName.toString();
                for(Cookie ck: curCookieList)
                {
                	if(strCookieName.equalsIgnoreCase(ck.getName()))
                	{
                		cookieNameDict.put(strCookieName, true);
                	}
                }
            }
            
            boolean bAllCookiesFound = true;
            for (Object  objFoundCurCookie : cookieNameDict.values())
            {
            	bAllCookiesFound = bAllCookiesFound && Boolean.parseBoolean(objFoundCurCookie.toString()); 
            }

            bLoginBaiduOk = bAllCookiesFound;
                        
            if (bLoginBaiduOk)
            {
            	System.out.println("成功模拟登陆百度首页!" );
            }
            else
            {
            	System.out.println("模拟登陆百度首页 失败!");
            	System.out.println("所返回的HTML源码为:" + loginBaiduRespHtml);
            }
        }

		return;
	}
}

正常,成功模拟登陆百度的输出为:

emulate login baidu normal output

 

8.完整的Eclipse下面的代码下载:

EmulateLoginBaidu_java_2013-09-17_crifanLibVersion.7z

 

注意:

1.使用此项目,需要导入org.apache.http的库。

详见:

【已解决】Eclipse的java代码出错:The import org.apache cannot be resolved

2.上面的贴出来的代码,用到了对应的我自己的java库,需要的先去下载,才能用上面代码:

crifanLib.java

 

3.部分百度账户,在登陆时会出现:

系统检测到您的帐号疑似被盗,存在安全风险。请尽快修改密码。

此时,本程序,无法成功模拟登陆,请自行按照提示去修改密码后,就可以了。

 

【总结】

java在处理http方面的库,相对来说,还是很不方便使用。

只能算是基本够用吧。



18 Thoughts on “【教程】模拟登陆百度之Java代码版

  1. 还是把一门语言学精去实现吧!楼主写的很不“java”

  2. 这是怎么回事啊?
    var url = encodeURI(‘http://www.baidu.com/cache/user/html/jump.html?callback=parent.bdPass.api.login._postCallback&index=0&codestring=tcIcaptchaservice38623639645138763738344f3854366e363761427967656f47515731695a655055766869655070544430454363504536325a6b4658572f594531524b487348524a53713162466847636877706644476174734768746466784b545446575a4c53766f38394171644a386857513941504d4771326349655873735678464838584f6963476d624b556b767a6646647a535649684d356338304c55756348484a3733397559544a4b474e54685a53594d55794757614154355574522f6837774a344f654f375232694278527242596b783857755a747857506e594e7077696b6432764e434837454a4344486434395561306849446277506978546b6848525a7a4e746c5a654c5a5a5131445a505779782f4a36445932494f67586b562f417173694d36397a674c64786e313948654d7a6e52&username=%3F%3F986&phonenumber=&mail=&tpl=mn&u=https%3A%2F%2Fpassport.baidu.com%2F&needToModifyPassword=&gotourl=&auth=&error=1’);
    //parent.callback(url)
    window.location.replace(url);

    • 出现这些警告

      Description Resource Path Location Type
      The value of the field crifanLib.constUserAgent_Firefox is not used crifanLib.java /EmulateLoginBaidu/src line 113 Java Problem
      The value of the field crifanLib.constUserAgent_IE9_x64 is not used crifanLib.java /EmulateLoginBaidu/src line 108 Java Problem
      The value of the field crifanLib.constUserAgent_IE7_x64 is not used crifanLib.java /EmulateLoginBaidu/src line 104 Java Problem
      The value of the field crifanLib.constUserAgent_Chrome is not used crifanLib.java /EmulateLoginBaidu/src line 111 Java Problem
      The value of the field crifanLib.constUserAgent_IE9_x86 is not used crifanLib.java /EmulateLoginBaidu/src line 109 Java Problem

  3. 博主,你发的crifanLib.java链接地址链接不上去哎,google网站链接不上了

  4. Pingback: Apache HttpComponents - HttpComponents HttpClient

  5. 你好,现在百度的登录方式是变了吗,因为发现密码是加密后的,不知道是用的是什么加密方式

  6. 楼主你好 感谢分享这么多有用的知识 受益匪浅
    我有一个问题 这几天用java做的百度登陆 在账号密码重复输入多次的情况下会要求输入验证码 可是我取到的验证码部分一直出现问题 取到的验证码不是实际的验证码 总是提示验证码错误 请问是否可以做一个带验证码功能的模拟百度登陆呢?
    期待某一天 在更新的日志里会出现“应某位小虾米的要求 做了这个程序。。。”
    best wishes
    再次感谢你的热心分享

  7. 您好,谢谢您的指导,代码已经调通了。我现在想做一个安卓程序,该程序可以模拟登陆访问QQ相册,并且查看到QQ相册的照片,请问下这个该如何实现呢?非常非常感谢

    • 大概思路:
      1.据我所知,qq也有授权方面的api,供你调用,可以授权你访问qq。要么是手动分析qq登陆过程,然后自己写代码模拟。
      2.模拟登陆后,就可以正常查看qq相册照片了。

  8. 您好,很高兴学习到您的经验。我使用了您的JAVA代码,出现了错误Exception in thread “main” java.lang.Error: Unresolved compilation problem:
    The method group(int) in the type Matcher is not applicable for the arguments (String)

    at EmulateLoginBaidu.EmulateLoginBaiduUsingJava(EmulateLoginBaidu.java:123)
    at EmulateLoginBaidu.main(EmulateLoginBaidu.java:62)。主要是这句代码 strTokenValue = tokenValMatcher.group(“tokenVal”),group后面应该是int型,请问下这个错误如何解决??

  9. Pingback: 求助httpclient模拟登录百度https的问题 - Java SE - 开发者第2289182个问答

发表评论

电子邮件地址不会被公开。 必填项已用*标注

无觅相关文章插件,快速提升流量