自動連線南郵校園網app的實現
其實連線校園網不是個難題,就是傳輸一次post請求,之前也看到有大佬用python做到電腦上的自啟動指令碼。不過由於這次想做的是app,而app最好還是用java寫,相比python會存在不少問題。
一、python指令碼的實現
雖然要弄java,但還是藉著之前看到的python指令碼先理解一下思路。首先在校園網登入的介面用F12觀察一下連線的時候post了哪些引數:
可以看到主要有兩個引數,DDDDD對應的是學號,形式是",0,學號和字尾",字尾如果是@cmcc就是中國移動,如果是@njxy就是中國電信,如果無後綴則是校園網;而upass即是密碼。所以我們要手動實現一次登入,只需要post這兩個引數就行,程式碼如下:
import requests url="http://10.10.244.11:801/eportal/c=ACSetting&a=Login&wlanacip=10.255.252.150" data={"DDDDD": ",0,學號和字尾","upass": "密碼"} response=requests.post(url,data)
可以說是簡單的不能再簡單……不過我們的目標肯定不是一次登入,但是要是反覆的post如果已經登入則也不太合理,參考大佬的指令碼,發現有這樣一個網址:"http://p.njupt.edu.cn:801/eportal/?c=ACSetting&a=checkScanIP&wlanuserip=",ip後加上的是get"http://p.njupt.edu.cn/"得到的v46ip的值,就能檢視到是否連線(ok/fail),如果連線還能看到自己的學號和連線的字尾,所以我們設定每隔一段時間的迴圈,先用get檢查是否連線,未連線則post資訊。程式碼如下:
import requests import requests import re import time def getIp(): url = "http://p.njupt.edu.cn/" res = requests.get(url = url) res.encoding = 'gbk' results = re.search("v46ip=\'([^\']*)\'", res.text) ip=results.group(1) return ip def checkIp(ip): url = "http://p.njupt.edu.cn:801/eportal/?c=ACSetting&a=checkScanIP&wlanuserip={}".format(ip) res = requests.get(url = url) status = re.search('\"result\":\"([^\"]*)\"', res.text).group(1) if (status == 'ok'): account = re.search('\"account\":\"([^\"]*)\"', res.text).group(1) return account else: return False def login(): url="http://10.10.244.11:801/eportal/?c=ACSetting&a=Login&wlanacip=10.255.252.150" data={"DDDDD": ",0,學號@cmcc","upass": "密碼"} #修改學號和密碼 response=requests.post(url,data) return True while True: try: ip = getIp() if checkIp(ip) == False: login() except: pass time.sleep(5)
二、java指令碼的實現
可以說思路和python一樣,但是我們需要找到這幾個函式在java中的實現方法:requests.get、requests.post、re.search
1、re.search
用Pattern類來實現
private String re_search(String pa, String li) { String line = li; String pattern = pa; Pattern r = Pattern.compile(pattern); Matcher m = r.matcher(line); if (m.find()) { return m.group(1); } else { return "Null"; } }
2、get&post
網上有很多指令碼,這裡我用的是java自帶的HttpsURLConnection。
private final String USER_AGENT = "Mozilla/5.0"; private String sendGet(String Url) throws Exception { String url = Url; URL obj = new URL(url); HttpURLConnection con = (HttpURLConnection) obj.openConnection(); con.setRequestMethod("GET"); con.setRequestProperty("User-Agent", USER_AGENT); int responseCode = con.getResponseCode(); System.out.println("\nSending 'GET' request to URL : " + url); System.out.println("Response Code : " + responseCode); BufferedReader in = new BufferedReader( new InputStreamReader(con.getInputStream())); String inputLine; StringBuffer response = new StringBuffer(); while ((inputLine = in.readLine()) != null) { response.append(inputLine); } in.close(); return response.toString(); } private void sendPost(String Url) throws Exception { String url = Url; URL obj = new URL(url); HttpURLConnection con = (HttpURLConnection) obj.openConnection(); con.setRequestMethod("POST"); con.setRequestProperty("User-Agent", USER_AGENT); con.setRequestProperty("Accept-Language", "en-US,en;q=0.5"); String urlParameters = "DDDDD=,0,學號@cmcc&upass=密碼"; // 修改學號密碼 con.setDoOutput(true); DataOutputStream wr = new DataOutputStream(con.getOutputStream()); wr.writeBytes(urlParameters); wr.flush(); wr.close(); int responseCode = con.getResponseCode(); System.out.println("\nSending 'POST' request to URL : " + url); System.out.println("Post parameters : " + urlParameters); System.out.println("Response Code : " + responseCode); BufferedReader in = new BufferedReader( new InputStreamReader(con.getInputStream())); String inputLine; StringBuffer response = new StringBuffer(); while ((inputLine = in.readLine()) != null) { response.append(inputLine); } in.close(); }
3、完整程式碼
import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import javax.net.ssl.HttpsURLConnection; import java.util.regex.Matcher; import java.util.regex.Pattern; public class HttpURLConnectionExample { private final String USER_AGENT = "Mozilla/5.0"; public static void main(String[] args) throws Exception { HttpURLConnectionExample http = new HttpURLConnectionExample(); String ip, status, account = ""; int count = 0; while (true) { try { Thread.sleep(5 * 1000); ip = http.re_search("v46ip=\'([^\']*)\'", http.sendGet("http://p.njupt.edu.cn/")); ip = "http://p.njupt.edu.cn:801/eportal/?c=ACSetting&a=checkScanIP&wlanuserip=" + ip; status = http.re_search("\"result\":\"([^\"]*)\"", http.sendGet(ip)); if (status.equals("ok")) { account = http.re_search("\"account\":\"([^\"]*)\"", http.sendGet(ip)); } else { http.sendPost("http://10.10.244.11:801/eportal/?c=ACSetting&a=Login&wlanacip=10.255.252.150"); } count++; System.out.println(count); } catch (InterruptedException e) { e.printStackTrace(); } } } private String re_search(String pa, String li) { String line = li; String pattern = pa; Pattern r = Pattern.compile(pattern); Matcher m = r.matcher(line); if (m.find()) { return m.group(1); } else { return "Null"; } } private String sendGet(String Url) throws Exception { String url = Url; URL obj = new URL(url); HttpURLConnection con = (HttpURLConnection) obj.openConnection(); con.setRequestMethod("GET"); con.setRequestProperty("User-Agent", USER_AGENT); int responseCode = con.getResponseCode(); System.out.println("\nSending 'GET' request to URL : " + url); System.out.println("Response Code : " + responseCode); BufferedReader in = new BufferedReader( new InputStreamReader(con.getInputStream())); String inputLine; StringBuffer response = new StringBuffer(); while ((inputLine = in.readLine()) != null) { response.append(inputLine); } in.close(); return response.toString(); } private void sendPost(String Url) throws Exception { String url = Url; URL obj = new URL(url); HttpURLConnection con = (HttpURLConnection) obj.openConnection(); con.setRequestMethod("POST"); con.setRequestProperty("User-Agent", USER_AGENT); con.setRequestProperty("Accept-Language", "en-US,en;q=0.5"); String urlParameters = "DDDDD=,0,學號@cmcc&upass=密碼"; // 修改學號密碼 con.setDoOutput(true); DataOutputStream wr = new DataOutputStream(con.getOutputStream()); wr.writeBytes(urlParameters); wr.flush(); wr.close(); int responseCode = con.getResponseCode(); System.out.println("\nSending 'POST' request to URL : " + url); System.out.println("Post parameters : " + urlParameters); System.out.println("Response Code : " + responseCode); BufferedReader in = new BufferedReader( new InputStreamReader(con.getInputStream())); String inputLine; StringBuffer response = new StringBuffer(); while ((inputLine = in.readLine()) != null) { response.append(inputLine); } in.close(); } }
三、app的實現
然而當我用java在電腦上寫好的時候才意識到get和post在windowst和android不太一樣……android相比windows還要解決以下幾個問題:
1、get&post
2、面向使用者時資料的讀取和儲存
3、下拉框(選擇移動電信還是校園網)
1、get&post
注意的是要首先加上傳送網路請求的許可權,網上一搜有很多,除此以外注意android studio要求網路連線只能在子執行緒中進行。
//get的用法,用String獲取get的訪問值來滿足對ip和狀態的確定 public String sendGet(String ip){ try { connection = null; URL url = new URL(ip); connection = (HttpURLConnection) url.openConnection(); connection.setConnectTimeout(3000); connection.setReadTimeout(3000); connection.setRequestMethod("GET"); connection.setDoInput(true); connection.setDoOutput(false); connection.connect(); responseCode = connection.getResponseCode(); if (responseCode != HttpURLConnection.HTTP_OK) { throw new IOException("HTTP error code" + responseCode); } result = getStringByStream(connection.getInputStream()); return result; }catch (IOException e) { e.printStackTrace(); return "error"; } } //post 因為這裡用不到返回值所以void就行 public void sendPost(String ip,String pa){ try { connection = null; URL url = new URL(ip); connection = (HttpURLConnection) url.openConnection(); connection.setConnectTimeout(3000); connection.setReadTimeout(3000); connection.setRequestMethod("POST"); connection.setDoInput(true); connection.setDoOutput(false); connection.connect(); DataOutputStream dos=new DataOutputStream(connection.getOutputStream()); param=pa; dos.writeBytes(param); responseCode = connection.getResponseCode(); if (responseCode != HttpURLConnection.HTTP_OK) { throw new IOException("HTTP error code" + responseCode); } }catch (IOException e) { e.printStackTrace(); } } //用於返回值的處理 private String getStringByStream(InputStream inputStream) { Reader reader; StringBuffer buffer; try { reader = new InputStreamReader(inputStream, "UTF-8"); char[] rawBuffer = new char[512]; buffer = new StringBuffer(); int length; while ((length = reader.read(rawBuffer)) != -1) { buffer.append(rawBuffer, 0, length); } return buffer.toString(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; }
2、資料的永久性儲存
因為涉及需要儲存的資訊很少,所以用SharedPreferences就行。
3、下拉框
spinner的使用,由於只是選擇和讀取所以弄個監聽器就行,不需要動態和其它的內容。
4、完整程式碼
values.xml:
<?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="choice"> <item>中國移動</item> <item>中國電信</item> <item>校園網</item> </string-array> </resources>
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <Button android:id="@+id/button" android:layout_width="238dp" android:layout_height="107dp" android:text="自動連線校園網" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.514" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.62" /> <EditText android:id="@+id/edt1" android:layout_width="261dp" android:layout_height="61dp" android:autofillHints="username" android:ems="10" android:hint="請輸入學號" android:inputType="textPersonName" android:textSize="24sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.44" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.134" /> <EditText android:id="@+id/edt2" android:layout_width="261dp" android:layout_height="61dp" android:autofillHints="password" android:ems="10" android:hint="請輸入密碼" android:inputType="textPassword" android:textSize="24sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.433" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.225" /> <TextView android:id="@+id/txv1" android:layout_width="227dp" android:layout_height="117dp" android:text="Test" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.538" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.884" /> <TextView android:id="@+id/txv2" android:layout_width="228dp" android:layout_height="50dp" android:text="Test" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.54" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/txv1" app:layout_constraintVertical_bias="0.0" /> <Button android:id="@+id/btn" android:layout_width="121dp" android:layout_height="66dp" android:text="修改" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.944" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.407" /> <Spinner android:id="@+id/spinner" android:entries="@array/choice" android:layout_width="262dp" android:layout_height="39dp" app:layout_constraintBottom_toTopOf="@+id/button" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.436" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/edt2" app:layout_constraintVertical_bias="0.0" /> </androidx.constraintlayout.widget.ConstraintLayout>
package com.example.network; import androidx.appcompat.app.AppCompatActivity; import java.io.*; import android.content.SharedPreferences; import android.os.Bundle; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.AdapterView; import android.widget.Button; import android.app.Activity; import android.widget.Spinner; import android.widget.TextView; import android.widget.EditText; import android.widget.Toast; import java.net.HttpURLConnection; import java.net.URL; import javax.net.ssl.HttpsURLConnection; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.net.URLConnection; public class MainActivity extends AppCompatActivity { Person p1=new Person(); String pa ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button button2 = findViewById(R.id.button); Button button1 = findViewById(R.id.btn); button1.setOnClickListener(new BtnClickListener()); button2.setOnClickListener(new BtnClickListener()); Spinner cho=findViewById(R.id.spinner); cho.setOnItemSelectedListener(new ProvOnItemSelectedListener()); } //下拉框的監聽 private class ProvOnItemSelectedListener implements AdapterView.OnItemSelectedListener { @Override public void onItemSelected(AdapterView<?> adapter,View view,int position,long id) { String sInfo=adapter.getItemAtPosition(position).toString(); if(sInfo.equals("中國移動")) p1.setType("@cmcc"); if(sInfo.equals("中國電信")) p1.setType("@njxy"); if(sInfo.equals("校園網")) p1.setType("校園網"); } @Override public void onNothingSelected(AdapterView<?> arg0) { String sInfo="null"; } } // 按鈕的監聽 class BtnClickListener implements View.OnClickListener { //學號和密碼 String name; String code; @Override public void onClick(View v) { EditText txtName=findViewById(R.id.edt1); EditText txtCode=findViewById(R.id.edt2); Integer i=v.getId(); //修改被點選時 if(i.equals(R.id.btn)){ //獲取輸入框的值 name = txtName.getText().toString().trim(); code = txtCode.getText().toString().trim(); //資料的永久儲存 SharedPreferences.Editor editor = getSharedPreferences("lock", MODE_PRIVATE ).edit(); editor.putString("name", name); editor.putString("code", code); editor.putString("type", p1.getType()); editor.apply(); //提示資訊 Toast.makeText(getApplicationContext(), "設定成功", Toast.LENGTH_LONG).show(); } //連線校園網被點選時 if(i.equals(R.id.button)) { //從SharedPreferences中讀取資料 SharedPreferences read = getSharedPreferences("lock", MODE_PRIVATE ); p1.set(read.getString("name", ""), read.getString("code", ""),read.getString("type","")); //校園網的時候引數沒有後綴,修改無法實現,怎麼辦?修改就直接改成校園網,加個判斷就行 if(p1.getType().equals("校園網")) { pa = "DDDDD=,0," + p1.getId() + "&upass=" + p1.getPassword(); }else{ pa = "DDDDD=,0," + p1.getId() + p1.getType() + "&upass=" + p1.getPassword(); } //提示資訊 Toast.makeText(getApplicationContext(), pa, Toast.LENGTH_LONG).show(); //開啟子執行緒實現網路訪問 new Thread(runnable).start(); } } } //用類方便修改學號密碼以及型別,其實這裡不用也挺方便的 public class Person{ String id; String password; String type="@cmcc"; public Person(){ } public void set(String i,String p,String t){ id=i; password=p; type=t; } public void setType(String t){ type=t; } public String getId(){ return id; } public String getPassword(){ return password; } public String getType(){ return type; } } //子執行緒 Runnable runnable = new Runnable() { String ip,status,account,text; int responseCode,count=0; HttpURLConnection connection ; String result,param; String line,pattern; @Override public void run() { TextView text1 = findViewById(R.id.txv1); TextView text2 = findViewById(R.id.txv2); text1.setText("請稍等…………"); text2.setText("大約有五秒間隔"); count=0; while(true){ try { Thread.sleep(5000); count++; //get改網址讀取ip text = sendGet("http://p.njupt.edu.cn/"); ip = re_search("v46ip='([^']*)'", text); //這個ip可以訪問聯網的狀態 ip = "http://p.njupt.edu.cn:801/eportal/?c=ACSetting&a=checkScanIP&wlanuserip=" + ip; text = sendGet(ip); status = re_search("\"result\":\"([^\"]*)\"", text); text1.setText(status+"\n"+ip); //第一次可能存在該ip已經對應有聯網的狀態了,所以必須post if(count==1) { ip = "http://10.10.244.11:801/eportal/?c=ACSetting&a=Login&wlanacip=10.255.252.150"; sendPost(ip, pa); } else if (status.equals("ok")&&count!=1) { //ok的時候可以獲取到學號,其實這裡什麼也不需要做 account = re_search("\"account\":\"([^\"]*)\"", text); text2.setText(account); } else { //fail或者其它情況傳送post請求 ip = "http://10.10.244.11:801/eportal/?c=ACSetting&a=Login&wlanacip=10.255.252.150"; sendPost(ip, pa); } //count做個計數,沒有也行,但既然有計數那就也考慮一下溢位上限的情況 if(count<0) { count = 2; } text2.setText(account+" "+count); } catch (Exception e) { e.printStackTrace(); } } } //get的用法,用String獲取get的訪問值來滿足對ip和狀態的確定 public String sendGet(String ip){ try { connection = null; URL url = new URL(ip); connection = (HttpURLConnection) url.openConnection(); connection.setConnectTimeout(3000); connection.setReadTimeout(3000); connection.setRequestMethod("GET"); connection.setDoInput(true); connection.setDoOutput(false); connection.connect(); responseCode = connection.getResponseCode(); if (responseCode != HttpURLConnection.HTTP_OK) { throw new IOException("HTTP error code" + responseCode); } result = getStringByStream(connection.getInputStream()); return result; }catch (IOException e) { e.printStackTrace(); return "error"; } } //post 因為這裡用不到返回值所以void就行 public void sendPost(String ip,String pa){ try { connection = null; URL url = new URL(ip); connection = (HttpURLConnection) url.openConnection(); connection.setConnectTimeout(3000); connection.setReadTimeout(3000); connection.setRequestMethod("POST"); connection.setDoInput(true); connection.setDoOutput(false); connection.connect(); DataOutputStream dos=new DataOutputStream(connection.getOutputStream()); param=pa; dos.writeBytes(param); responseCode = connection.getResponseCode(); if (responseCode != HttpURLConnection.HTTP_OK) { throw new IOException("HTTP error code" + responseCode); } }catch (IOException e) { e.printStackTrace(); } } //用於返回值的處理 private String getStringByStream(InputStream inputStream) { Reader reader; StringBuffer buffer; try { reader = new InputStreamReader(inputStream, "UTF-8"); char[] rawBuffer = new char[512]; buffer = new StringBuffer(); int length; while ((length = reader.read(rawBuffer)) != -1) { buffer.append(rawBuffer, 0, length); } return buffer.toString(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; } //模擬python中的re.search private String re_search(String pat, String li) { line = li; pattern = pat; Pattern r = Pattern.compile(pattern); Matcher m = r.matcher(line); if (m.find()) { return m.group(1); } else { return "null"; } } }; }
以上,不過也就只有在南郵能用,主要是寫一下思路。