其实连接校园网不是个难题,就是传输一次post请求,之前也看到有大佬用python做到电脑上的自启动脚本。不过由于这次想做的是app,而app最好还是用java写,相比python会存在不少问题。
https://www.cnblogs.com/chi4ki/p/16068429.html
一、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要求网络连接只能在子线程中进行。
网络权限:在AndroidManifest.xml中添加
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
和android:usesCleartextTraffic="true"
位置如下:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.network"> <!--第一处--> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.INTERNET" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.Network" android:usesCleartextTraffic="true"> <!--第二处--> <activity android:name=".MainActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
get&post:
HttpURLConnection connection ; String line,pattern,param,results; int responseCode; //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); } results = getStringByStream(connection.getInputStream()); return results; }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; }
开启一个子线程并调用:
new Thread(()->{ //先做个连接,因为有时候这个ip还不是对应自己的 sendPost(ip3,content); //做个计数 int count=1; while(true) { try{ //每20秒进行一次的循环 Thread.sleep(20000); text = sendGet(ip1); ip = re_search("v46ip='([^']*)'", text); ip2 += ip; text = sendGet(ip2); result = re_search("\"result\":\"([^\"]*)\"", text); if (!result.equals("ok")) { //不是ok的时候发起连接 Log.d("tag",content+String.valueOf(count)); count++; } else { //已经连上时弹出消息框已经连接 runOnUiThread(() -> Toast.makeText(getApplicationContext(), "connected", Toast.LENGTH_SHORT).show()); Log.d("tag",String.valueOf(count)); count++; } }catch (Exception e) { e.printStackTrace(); } } }).start();
2、数据的永久性存储
因为涉及需要存储的信息很少,所以用SharedPreferences就行。
//获取SharedPreferences对象 SharedPreferences.Editor editor = getSharedPreferences("lock", MODE_PRIVATE ).edit(); //添加数据 editor.putString("name", name); editor.putString("code", code); editor.apply(); //读取数据 SharedPreferences read = getSharedPreferences("lock", MODE_PRIVATE ); read.getString("name", ""); read.getString("code", "");
3、下拉框
spinner的使用,由于只是选择和读取所以弄个监听器就行。在values.xml里加入我们需要的选项,并在下拉框里加入android:entries="@array/choice"。
values.xml:
<?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="choice"> <item>中国移动</item> <item>中国电信</item> <item>校园网</item> </string-array> </resources>
监听函数:
//下拉框的监听 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"; } }
4、完整代码
Person.java
package com.example.network_2; public class Person{ String id; String password; String type; 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; } }
activity_main.xml
<?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"> <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" /> <Button android:id="@+id/btn1" 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" /> <Button android:id="@+id/btn2" 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:layout_width="262dp" android:layout_height="48dp" android:entries="@array/choice" app:layout_constraintBottom_toTopOf="@+id/btn1" 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>
MainActivity.java
package com.example.network_2; import androidx.appcompat.app.AppCompatActivity; import android.content.SharedPreferences; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.AdapterView; import android.widget.Button; import android.widget.EditText; import android.widget.Spinner; import android.widget.Toast; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.io.UnsupportedEncodingException; import java.net.HttpURLConnection; import java.net.URL; import java.util.regex.Matcher; import java.util.regex.Pattern; public class MainActivity extends AppCompatActivity { String ip,text,result,content,name,code; String ip1="http://p.njupt.edu.cn/"; String ip2="http://p.njupt.edu.cn:801/eportal/?c=ACSetting&a=checkScanIP&wlanuserip="; String ip3= "http://10.10.244.11:801/eportal/?c=ACSetting&a=Login&wlanacip=10.255.252.150"; Person person=new Person(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //给两个按钮设置监听 Button btn1=findViewById(R.id.btn1); btn1.setOnClickListener(new BtnClickListener()); Button btn2=findViewById(R.id.btn2); btn2.setOnClickListener(new BtnClickListener()); //给下拉框设置监听 Spinner spinner=findViewById(R.id.spinner); spinner.setOnItemSelectedListener(new ProvOnItemSelectedListener()); } //按钮的监听 class BtnClickListener implements View.OnClickListener { @Override public void onClick(View v){ Integer id=v.getId(); if(id.equals(R.id.btn2)) setUp(); if(id.equals(R.id.btn1)) connect(); } } //下拉框的监听 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("中国移动")) person.setType("@cmcc"); if(sInfo.equals("中国电信")) person.setType("@njxy"); if(sInfo.equals("校园网")) person.setType("校园网"); } @Override public void onNothingSelected(AdapterView<?> arg0) { String sInfo="null"; } } //连接的步骤 public void connect(){ EditText txtName=findViewById(R.id.edt1); EditText txtCode=findViewById(R.id.edt2); //读取存储的内容 SharedPreferences read = getSharedPreferences("lock", MODE_PRIVATE ); name=read.getString("name", ""); code=read.getString("code", ""); person.set(name, code,read.getString("type","")); //将两行输入框设置为我们现在用的学号和密码 txtName.setText(name); txtCode.setText(code); //因为选择校园网的时候后缀为空但这里不能直接设置为空,所以我们加个判断来区分选择校园网的时候 if(person.getType().equals("校园网")) { content = "DDDDD=,0," + person.getId() + "&upass=" + person.getPassword(); }else{ content = "DDDDD=,0," + person.getId() + person.getType() + "&upass=" + person.getPassword(); } //开启子线程 new Thread(()->{ //先做个连接,因为有时候这个ip还不是对应自己的 sendPost(ip3,content); //做个计数 int count=1; while(true) { try{ //每20秒进行一次的循环 Thread.sleep(20000); text = sendGet(ip1); ip = re_search("v46ip='([^']*)'", text); ip2 += ip; text = sendGet(ip2); result = re_search("\"result\":\"([^\"]*)\"", text); if (!result.equals("ok")) { //不是ok的时候发起连接 sendPost(ip3,content); Log.d("tag",content+String.valueOf(count)); count++; } else { //已经连上时弹出消息框已经连接 runOnUiThread(() -> Toast.makeText(getApplicationContext(), "connected", Toast.LENGTH_SHORT).show()); Log.d("tag",String.valueOf(count)); count++; } }catch (Exception e) { e.printStackTrace(); } } }).start(); } //修改学号密码 public void setUp(){ //读取输入框的值 EditText txtName=findViewById(R.id.edt1); EditText txtCode=findViewById(R.id.edt2); 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", person.getType()); editor.apply(); //提示消息设置成功 Toast.makeText(getApplicationContext(), "设置成功", Toast.LENGTH_SHORT).show(); } //以下是Get、Post以及search函数 HttpURLConnection connection ; String line,pattern,param,results; int responseCode; //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); } results = getStringByStream(connection.getInputStream()); return results; }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 public 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"; } } }
(比较好看的代码显示识别开启线程的lambda表达式时会整个花掉,所以为了清楚一点就只能用这个了)
运行效果如下:
以上,不过也就只有在学校里能用,主要是写一下思路。