編輯:關於Android編程
兩周廢寢忘食的創作終於成功了,現在拿出來分享一下。
先不說別的看一下程序運行效果圖,我沒怎麼設計ui所以界面不是很好看但是能說明問題~~~



現在我們來看看實現這個功能需要些什麼准備工作,我們需要網絡信息抓取工具一般windows可以用httpwatch我是mac系統所以我詳細介紹一下mac上面的工具
1.Charles
2.Google Chrome
接下來就可以進行網頁信息抓包了,先看一下我們學校的教務網頁
然後我們開始進行對浏覽器抓包我使用的是Charles首先要配置成下圖這個樣子然後才可以抓包

首先對登錄信息抓包時要找下面這張截圖上的信息

然後對獲取驗證嗎抓包

我們在response中可以看到返回信息
然後我們需要下載一個解析HTML源碼的架構包叫Jsoup放到libs目錄下然後右鍵選擇
as library

這些就准備好了然後我們來看一小段HTML代碼方便解析時候講解
可以看到我們需要的信息都被一個一個的標簽包裹著,Jsoup所做的就是將我們需要的信息從標簽裡剝離出來。
然後我們來看代碼實現,我這裡分了兩個Activity來實現
1.MainActivity
public class MainActivity extends ActionBarActivity {
//使用SharedPreferences進行用戶的用戶名密碼以及cookie的保存
SharedPreferences sharedPreferences;
SharedPreferences.Editor editor;
private EditText studentNumber;
private EditText passWord;
private EditText idCode;
private Bitmap bitmap;
private ImageView IdcodeImage;
//注意這裡Handler使用的是import android.os.Handler;這個包
private Handler handler;
private Button logIn;
String StudentNumber;
String PassWord;
String IdCode;
String groupId="";
String login="登錄";
//這條是解析出來進行獲取驗證碼的圖片的網址
String url2="http://jw.djtu.edu.cn/academic/getCaptcha.do";
//這條是解析出來進行提交登錄信息的網址
String url3="http://jw.djtu.edu.cn/academic/j_acegi_security_check";
//這裡使用HttpClient進行數據的獲取和提交
HttpClient client;
@Override
protected void onCreate(final Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//實例化HttpClient對象
client=new DefaultHttpClient();
//sharedPreferences第一個參數是給你保存的信息起個名字,第二個參數設置為Context.MODE_PRIVATE屬性,
// 這樣會避免其他應用可以直接訪問我們保存的信息
sharedPreferences=getSharedPreferences("params", Context.MODE_PRIVATE);
//實例化SharedPreferences.Editor對象
editor=sharedPreferences.edit();
studentNumber=(EditText)findViewById(R.id.studentNumber);
passWord=(EditText)findViewById(R.id.key);
IdcodeImage=(ImageView)findViewById(R.id.passImage);
idCode=(EditText)findViewById(R.id.identifyingCode);
logIn=(Button)findViewById(R.id.login);
//實例化Handler對象方便線程之間通信
handler=new Handler();
//對我們的驗證碼綁定一個單擊響應事件,這是為了去實現驗證碼看不清時再更新一張驗證碼而用
IdcodeImage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread() {
@Override
public void run() {
//我們需要同步Cookie信息所以從驗證碼開始就需要獲取Cookie
List cookies1;
//HttpGet來發送獲取驗證碼請求
HttpGet httpGet = new HttpGet(url2);
//聲明一個HttpResponse
HttpResponse httpResponse = null;
try {
//實例化HttpResponse
httpResponse = client.execute(httpGet);
} catch (IOException e) {
e.printStackTrace();
}
//如果服務器響應成功
if (httpResponse.getStatusLine().getStatusCode() == 200) {
try {
//使用輸入流來接受數據
InputStream in = httpResponse.getEntity().getContent();
//bitmap來獲取數據流中的圖片信息
bitmap = BitmapFactory.decodeStream(in);
//關閉輸入流
in.close();
String Cookies;
//獲取Cookie
cookies1 = ((AbstractHttpClient) client).getCookieStore().getCookies();
Cookies = "JSESSIONID="+cookies1.get(0).getValue().toString();
//System.out.println(Cookies);
//在SharedPreferences中保存cookie
editor.putString("Cookies", Cookies);
//提交保存數據
editor.commit();
//通過handler.post方法在線程中更新主線程中的驗證碼圖片信息
handler.post(new Runnable() {
@Override
public void run() {
if (bitmap != null) {
IdcodeImage.setImageBitmap(bitmap);
}
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
}
}.start();
}
});
//初始化時獲取驗證碼圖片代碼與上面的一致
new Thread() {
@Override
public void run() {
List cookies1;
HttpGet httpGet = new HttpGet(url2);
HttpResponse httpResponse = null;
try {
httpResponse = client.execute(httpGet);
} catch (IOException e) {
e.printStackTrace();
}
if (httpResponse.getStatusLine().getStatusCode() == 200) {
try {
InputStream in = httpResponse.getEntity().getContent();
bitmap = BitmapFactory.decodeStream(in);
in.close();
String Cookies;
cookies1 = ((AbstractHttpClient) client).getCookieStore().getCookies();
Cookies = "JSESSIONID="+cookies1.get(0).getValue().toString();
System.out.println(Cookies);
editor.putString("Cookies", Cookies);
editor.commit();
handler.post(new Runnable() {
@Override
public void run() {
if (bitmap != null) {
IdcodeImage.setImageBitmap(bitmap);
}
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
}
}.start();
//對登錄按鈕綁定單擊響應事件
logIn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//獲取輸入信息
StudentNumber =studentNumber.getText().toString();
PassWord =passWord.getText().toString();
IdCode = idCode.getText().toString();
//這裡寫入StudentNumber和PassWord是為了做記住密碼登錄
editor.putString("StudentNumber", StudentNumber);
editor.putString("PassWord", PassWord);
editor.putString("IdCode", IdCode);
editor.commit();
new Thread() {
@Override
public void run() {
//提交數據用List的方式
List params = new ArrayList();
//這裡的名稱不要有多余的符號,因為提交數據時httppost方法會幫你維護數據
//這裡表單的數據順序要按照剛剛解析所顯示的順序排列
params.add(new BasicNameValuePair("groupId", groupId));
params.add(new BasicNameValuePair("j_username", StudentNumber));
params.add(new BasicNameValuePair("login",login));
params.add(new BasicNameValuePair("j_password", PassWord));
params.add(new BasicNameValuePair("j_captcha", IdCode));
System.out.println(params);
try {
HttpPost httpPost = new HttpPost(url3);
String Cookies;
//獲取到剛剛在獲取驗證碼時得到的Cookie
Cookies = sharedPreferences.getString("Cookies", null);
//System.out.println(Cookies);
//提交數據做准備
httpPost.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));
//同步cookie
httpPost.setHeader("Cookie", Cookies);
//獲取返回的信息
HttpResponse httpResponse = client.execute(httpPost);
//如果響應成功則進入Score_find的Activity
if (httpResponse.getStatusLine().getStatusCode() == 200) {
String result = EntityUtils.toString(httpResponse.getEntity());
//System.out.println(result);
startActivity(new Intent(MainActivity.this, Score_find.class));
} else {
System.out.println("登錄失敗!");
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
});
}
}
2.Score_find Activity
public class Score_find extends ActionBarActivity{
private String Cookies;
HttpClient client;
private String url="http://jw.djtu.edu.cn/academic/manager/score/studentOwnScore.do?groupId=&moduleId=2021";
private String year=null;
private String trem=null;
private String para="0";
private String sortColumn="";
private String Submit="查詢";
private TextView showScore;
private EditText InputYear;
private EditText InputTrem;
SharedPreferences sharedPreferences;
StringBuffer sb=new StringBuffer();
private Handler handler=null;
private Button searchButton;
//這兩個標記是用於判斷用戶輸入的數據是否合法
private int mark1=0;
private int mark2=0;
@Override
protected void onCreate(final Bundle saveInstanceState)
{
super.onCreate(saveInstanceState);
setContentView(R.layout.score_find);
InputTrem=(EditText)findViewById(R.id.InputTrem);
InputYear=(EditText)findViewById(R.id.InputYear);
searchButton=(Button)findViewById(R.id.searchButton);
showScore=(TextView)findViewById(R.id.show_score);
//設置showScore可以滾動
showScore.setMovementMethod(ScrollingMovementMethod.getInstance());
handler=new Handler()
{
@Override
public void handleMessage(Message message)
{
//加載信息
showScore.setText(sb.toString());
}
};
sharedPreferences = getSharedPreferences("params", Context.MODE_PRIVATE);
Cookies=sharedPreferences.getString("Cookies", null);
showScore=(TextView)findViewById(R.id.show_score);
client=new DefaultHttpClient();
searchButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String years=null,trems=null;
years=InputYear.getText().toString();
trems=InputTrem.getText().toString();
System.out.println(years+trems);
//輸入信息的判斷
if("春".equals(trems))
{
trem="1";
mark1=1;
System.out.println(trems+"\t"+trem);
}else if("秋".equals(trems))
{
trem="2";
mark1=1;
}else
{
mark1=0;
Toast.makeText(Score_find.this,"輸入學期有誤請重新輸入!",Toast.LENGTH_SHORT).show();
}
if("2014".equals(years))
{
year="34";
mark2=1;
System.out.println(years+"\t"+year);
}else if("2015".equals(years))
{
year="35";
mark2=1;
}
else
{
mark2=0;
Toast.makeText(Score_find.this,"輸入年份有誤請重新輸入!",Toast.LENGTH_SHORT).show();
}
//如果兩個信息都輸入合法則提交請求
if(mark1==1&&mark2==1) {
//是耗時操作都要放到新線程裡執行
new Thread() {
@Override
public void run()
{
HttpResponse httpResponse;
HttpPost httpPost = new HttpPost(url);
List params = new ArrayList();
params.add(new BasicNameValuePair("year", year));
params.add(new BasicNameValuePair("term", trem));
params.add(new BasicNameValuePair("para", para));
params.add(new BasicNameValuePair("sortColumn", sortColumn));
params.add(new BasicNameValuePair("Submit", Submit));
System.out.println(params);
httpPost.setHeader("Cookie", Cookies);
try {
httpPost.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));
httpResponse = client.execute(httpPost);
if (httpResponse.getStatusLine().getStatusCode() == 200) {
StringBuffer stringBuffer = new StringBuffer();
String result = null;
InputStream inputStream = httpResponse.getEntity().getContent();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
String data = "";
//讀取得到的數據
while ((data = bufferedReader.readLine()) != null) {
stringBuffer.append(data);
stringBuffer.append("\n");
}
result = stringBuffer.toString();
//判斷是否獲取到數據
if (result == null) {
System.out.println("NULL!!!!");
} else {
//這裡使用jsoup開源的解析包進行html源碼的解析
//獲取要解析的網址或者文檔或者網址
Document document = Jsoup.parse(result);
//經過分析成績保存在datalist這個Class中因此要定位到這個類中
Elements elements = document.getElementsByClass("datalist");
//獲取他的第一個元素集合
Element element = elements.get(0);
//再分析可以看到在tr標簽下有成績的詳細信息
Elements elements1 = element.getElementsByTag("tr");
Element element2;
Elements elements3;
Element element3;
Element element4;
for (int i = 0; i < elements1.size(); i++) {
//剝離每一個標簽
element2 = elements1.get(i);
//再重新定位td標簽下的內容
elements3 = element2.getElementsByTag("td");
for (int j = 0; j < elements3.size(); j++) {
//這裡為了獲取td標簽中的子元素要進行一個循環
if (j == 0) {
//我發現我要的課程名和成績分別在elements3集合中的第5個元素和第11個元素
element3 = elements3.get(4);
element4 = elements3.get(10);
sb.append(element3.text()).append(":").append("\t\t").append(element4.text()).append("\n");
} else {
break;
}
}
}
//數據獲取完成通知組件重繪信息
handler.sendEmptyMessage(0);
}
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
}
});
}
}
最後我用紅字強調一下做這個demo我一開始失敗了好多次的地方:
1.Cookie信息獲取要在獲取驗證碼時同時獲取。
2.如果線程操作封裝成類的話會造成SharedPreferences綁定content失敗。
3.對HTML源碼進行解析的時候我嘗試將解析方法寫成一個函數,但是會出現一些未捕獲的錯誤而導致程序崩潰,因此我把解析步驟也放到了新線程中。
有什麼不足的地方可以留言給我我會盡快回復並改正!
Android Studio正確引入jar包
1.首先找到你需要的jar包2.復制粘貼到下圖位置3.你的粘貼後可能是這樣的4.正確的方式是這樣的5.在粘貼後還需要操作2步(1.選中Add As Library)然後進
Android程序版本更新之通知欄更新下載安裝
Android應用檢查版本更新後,在通知欄下載,更新下載進度,下載完成自動安裝,效果圖如下:•檢查當前版本號AndroidManifest文件中的versio
兩種Android打電話實現方法
在android開發中,用戶能夠撥打電話是最基本的需求。俗話說“條條大路通羅馬”,實現撥打電話的方式有多種,今天,就提供最常用兩種。 首先,撥打電話,對於用戶來說,是一
Android開發技巧之在a標簽或TextView控件中單擊鏈接彈出Activity(自定義動作)
在5.2.1節和5.2.2節介紹了<a>標簽以及TextView自動識別的特殊文本(網址、電話號、Email等),這些都可以通過單擊來觸發不同的動作。雖然這些