轉載請聲明出處http://blog.csdn.net/zhongkejingwang/article/details/39995909
前段時間經常逛貼吧,每次都要手動簽到,有時候也會忘記簽到,很麻煩。於是就想用Java寫個自動簽到的工具並部署到實驗室的服務器上,這樣就可以常年自動簽到了。於是就有了這篇文章,權當玩玩。
看一下程序的執行情況:
將此程序放到服務器後臺運行就可以了,不用再擔心斷籤~
要簽到首先要登錄然後再獲取貼吧頁面裏的簽到鏈接。由於Java自帶的http的API使用起來很不方便,這裏使用的是Apache的httpclient(只用到了三個jar包,後面會提供下載),用post方法提交表單數據即可,關於表單的item參數可以用chrome瀏覽器抓包分析一下(按F12)。登錄地址選擇百度的手機網頁端:http://wappass.baidu.com/passport/login這個地址,這樣的話服務器端識別爲手機簽到,可以加分。在代碼中將用戶名和密碼提交到這個地址即可,在去年的時候抓包分析過這個頁面提交的數據還是明文的....現在已經升級了,網頁是經過加密後提交的密碼,不過明文提交還是可以登錄。
登錄完了需要獲取貼吧首頁中用戶關注的所有貼吧,在這個地址http://tieba.baidu.com/mo,獲取網頁特定內容需要用到html解析工具,這裏使用的是Jsoup,可以在這裏看使用教程http://www.open-open.com/jsoup/
獲取到關注貼吧的首頁然後把該貼吧的html頁面拉下來一份,檢索看看有沒有包含“sign”字符串,沒有表示已經簽到了;有則獲取對應的簽到地址,訪問改地址即可簽到成功。
關於添加依賴包:在eclipse中右鍵工程—>屬性—>Java 構建路徑—>庫(L)裏添加外部JAR,就可以了。
關於怎麼打包成可執行的jar包:這裏有依賴的jar包,建議將依賴的jar包一塊打包進去,可以使用eclipse打包,具體步驟:
右鍵工程—>導出—>Java—>可運行的jar包,點擊下一步,在接下來的選項中選擇Package required libraries into generated JAR:
這樣就可以很方便的把jar包上傳到服務器執行了。否則手動打包需要寫MANIFEST.MF清單文件,指定Class-Path,指向所有依賴包,否則運行時找不到依賴包,比較麻煩。所以還是建議用eclipse打包吧。。。
過程講完了可以講代碼了。寫一個SignUpTool接口:
package com.jingchen.util;
public interface SignUpTool {
/**
* 用戶登錄
*
* @param username
* 用戶名
* @param passwd
* 密碼
* @return 登錄成功返回true,失敗則返回false
*/
boolean login(String username, String passwd);
/**
* 簽到
*
* @return 簽到成功返回true,失敗則返回falses
*/
boolean signUp();
}
接口包含了登錄和簽到方法,此接口不同的實現可以登錄不同的網站。
寫一個HttpUtil,封裝post和get操作:
package com.jingchen.util;
import java.io.IOException;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CookieStore;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
public class HttpUtil {
private HttpClient mHttpClient;
private CookieStore mCookieStore;
private HttpContext mContext;
private HttpPost post;
private HttpGet get;
public HttpUtil() {
mHttpClient = new DefaultHttpClient();
mCookieStore = new BasicCookieStore();
mContext = new BasicHttpContext();
}
public HttpResponse post(String url, HttpEntity he)
throws ClientProtocolException, IOException {
post = new HttpPost(url);
post.setEntity(he);
mContext.setAttribute(ClientContext.COOKIE_STORE, mCookieStore);
HttpResponse hr = mHttpClient.execute(post, mContext);
return hr;
}
public String get(String url) throws ClientProtocolException, IOException {
String result = null;
get = new HttpGet(url);
HttpResponse hr = mHttpClient.execute(get, mContext);
result = EntityUtils.toString(hr.getEntity());
return result;
}
}
實現SignUpTool接口的BaiduSignUp:
package com.jingchen.util;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
/**
* 用於登錄百度貼吧賬號並簽到的類
*
* @author jingchen
*
*/
public class BaiduSignUp implements SignUpTool {
// 登錄鏈接
private String mLoginUrl = null;
// 登錄後跳轉的頁面
private String mIndexUrl = null;
// 獲取網頁中的相對路徑拼接上這個頭部構成完整請求路徑
private String mUrlHead = null;
// 是否需要驗證碼
private boolean isAuth = false;
private HttpUtil httpUtil;
// 關注的貼吧
private List<String> mLikeBars;
// 關注的貼吧首頁
private List<String> mLikeBarsUrls;
public BaiduSignUp() {
mLikeBars = new ArrayList<String>();
mLikeBarsUrls = new ArrayList<String>();
httpUtil = new HttpUtil();
mLoginUrl = "http://wappass.baidu.com/passport/login";
mIndexUrl = "http://tieba.baidu.com/mo";
mUrlHead = "http://tieba.baidu.com";
}
public boolean login(String username, String passwd) {
isAuth = false;
mLikeBars.clear();
mLikeBarsUrls.clear();
print("login...");
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("username", username));
params.add(new BasicNameValuePair("password", passwd));
HttpEntity he;
try {
he = new UrlEncodedFormEntity(params, "UTF-8");
HttpResponse hr = httpUtil.post(mLoginUrl, he);
String firstresult = EntityUtils.toString(hr.getEntity());
if (firstresult.contains("verifycode")) {
// 在異地登錄或者登錄頻繁會出現驗證碼
isAuth = true;
print("需要驗證碼");
return false;
} else if (firstresult.contains("error_area")) {
print("密碼錯誤");
return false;
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
print("登錄成功");
return true;
}
public boolean signUp() {
if (isAuth) {
print("需要驗證碼");
return false;
}
print("signUp...");
if (mLikeBars.size() != 0) {
mLikeBars.clear();
mLikeBarsUrls.clear();
}
if (!getLikeBars())
return false;
try {
for (int i = 0; i < mLikeBars.size(); i++) {
String barview = getWebContent(mLikeBarsUrls.get(i));
if (!barview.contains("sign"))
print(mLikeBars.get(i) + "已簽到");
else {
Elements signurl = Jsoup.parse(barview)
.getElementsByAttributeValueMatching("href",
".*sign.*");
getWebContent(mUrlHead + signurl.attr("href"));
print(mLikeBars.get(i) + "簽到成功");
}
}
} catch (Exception e) {
e.printStackTrace();
print("fail in signUp!");
return false;
}
return true;
}
/**
* 獲取關注的貼吧
*
* @return
*/
private boolean getLikeBars() {
print("getLikeBars...");
String indexresult = getWebContent(mIndexUrl);
if (indexresult == null)
return false;
Document document = Jsoup.parse(indexresult);
Elements likebars = document.select("div.my_love_bar a");
for (Element e : likebars) {
mLikeBarsUrls.add(mUrlHead + e.attr("href"));
mLikeBars.add(e.text());
}
if (mLikeBars.size() == 0)
return false;
return true;
}
/**
* 獲取網頁內容
*
* @param url
* 鏈接地址
* @return 網頁內容
*/
private String getWebContent(String url) {
print("getWebContent...");
String result = null;
try {
result = httpUtil.get(url);
} catch (Exception e) {
e.printStackTrace();
return null;
}
return result;
}
public void print(String s) {
System.out.println(s);
}
}
包含main方法的主類:
package com.jingchen.main;
import com.jingchen.util.BaiduSignUp;
import com.jingchen.util.SignUpTool;
public class MainClass {
public static String username = "******";
public static String passwd = "******";
public static int mInterval = 30;
public static void main(String[] args) {
boolean isSignup = false;
boolean isLogin = false;
SignUpTool tool = new BaiduSignUp();
// SignUpTool tool = new BBSLogin();
while (true) {
try {
isLogin = tool.login(username, passwd);
isSignup = tool.signUp();
if (isLogin && isSignup) {
// 簽到成功則三小時後再簽到
System.out.println("continue after three hours...");
Thread.sleep(3 * 60 * 60 * 1000);
} else {
// 簽到失敗則30分鐘後再次簽到
System.out.println("continue after " + mInterval
+ " minites...");
Thread.sleep(mInterval * 60 * 1000);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
每次簽到前都先登錄,簽到失敗則等半小時再嘗試,簽到成功則等待3小時再次簽到。將用戶名和密碼填上就可以了。就這麼多了,不保證百度後臺升級後程序會一直有效。