用python寫一個腳本,自動連wifi,自動登錄校園網(wǎng)
↑ 關(guān)注 + 星標 ,每天學(xué)Python新技能
后臺回復(fù)【大禮包】送你Python自學(xué)大禮包
來源:網(wǎng)絡(luò)
1.實現(xiàn)原理
剛好最近學(xué)了http協(xié)議,就當是復(fù)習(xí)了。
簡單概括就是,通過網(wǎng)址找到登錄界面,然后發(fā)送post請求,把登錄信息提交給服務(wù)器,從而完成登錄。
1.1認識 URL
我們所說的網(wǎng)址,其實就是統(tǒng)一資源定位符(uniform resource locator簡稱URL),通過這個唯一的地址,可以找到對應(yīng)的服務(wù)。它的標準格式如下:
協(xié)議://用戶名:密碼@子域名.域名.頂級域名:端口號/目錄/文件名.文件后綴?參數(shù)=值#標志

這個只是標準的格式,有些信息是可以省略的,比如登錄信息等,還有服務(wù)器地址可以用域名地址,也可以用ip地址。帶層次的文件路徑其實就是你要訪問的服務(wù)器資源,問號?
后面是get請求的參數(shù)。http協(xié)議有多種請求方法,post和get只是其中的兩種。
1.get方法主要是獲取服務(wù)器的資源信息,請求的參數(shù)一般放在url?后面。
2.post方法主要是把數(shù)據(jù)提交給服務(wù)器,在報文的正文部分進行提交。
http協(xié)議本質(zhì)是獲得某種“資源”(視頻、音頻、網(wǎng)頁、圖片……),而傳輸則是其功能。實際上,上網(wǎng)的大部分行為,都在進行著進程間通信,既然是通信,就需要獲取信息和發(fā)送信息,所以對應(yīng)到我們生活中,大部分的上網(wǎng)行為無非兩種:
1.把服務(wù)器上面的資源拿到本地(下載短視頻、網(wǎng)絡(luò)小說……)
2.把本地的服務(wù)器推送到服務(wù)器(搜索、登錄、下單……)
1.2 http請求報文格式

首行: [方法] + [url] + [版本]
Header: 請求的屬性, 冒號分割的鍵值對;每組屬性之間使用\n分隔;遇到空行表示Header部分結(jié)束
Body: 空行后面的內(nèi)容都是Body. Body允許為空字符串. 如果Body存在, 則在Header中會有一個 Content-Length屬性來標識Body的長度;
1.3 http響應(yīng)報頭格式
首行: [版本號] + [狀態(tài)碼] + [狀態(tài)碼解釋]
Header: 請求的屬性, 冒號分割的鍵值對;每組屬性之間使用\n分隔;遇到空行表示Header部分結(jié)束
Body: 空行后面的內(nèi)容都是Body. Body允許為空字符串. 如果Body存在, 則在Header中會有一個 Content-Length屬性來標識Body的長度; 如果服務(wù)器返回了一個html頁面, 那么html頁面內(nèi)容就是在 body中。
HTTP常見Header:
Content-Type: 數(shù)據(jù)類型(text/html等) Content-Length: Body的長度
Host: 客戶端告知服務(wù)器, 所請求的資源是在哪個主機的哪個端口上; User-Agent: 聲明用戶的操作系統(tǒng)和瀏覽器版本信息;
referer: 當前頁面是從哪個頁面跳轉(zhuǎn)過來的;
location: 搭配3xx狀態(tài)碼使用, 告訴客戶端接下來要去哪里訪問;
Cookie: 用于在客戶端存儲少量信息. 通常用于實現(xiàn)會話(session)的功能;
2.具體實現(xiàn)
import requestsimport socket# 獲取ip地址def get_host_ip():"""查詢本機ip地址:return: ip"""try:s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)s.connect(('10.255.255.255', 1))ip = s.getsockname()[0]finally:s.close()return ipuser_ip = get_host_ip()# 校園網(wǎng)地址,最好不要用瀏覽器里的url,還是建議抓包獲取post_addr = "http://10.10.244.11:801/eportal/"#下面兩個大括號里面都是復(fù)制自己學(xué)校校園網(wǎng)登錄網(wǎng)站中的,冒號兩邊都要加上雙引號post_header = { #報頭信息,通過抓包,獲取}post_data = {#正文數(shù)據(jù),通過抓包獲取}#提交http請求報文z = requests.post(post_addr, data=post_data, headers=post_header)print("登錄校園網(wǎng)成功,局域網(wǎng)ip如下:")print(user_ip)#input("")
上面是代碼的主要邏輯,細節(jié)信息還需要抓包填充。一開始電腦上是沒有安裝requests包的,需要自己先安裝一下,后面python需要導(dǎo)入的包都是用pip3命令安裝。如果沒安裝pip3命令的,請自行安裝。
pip3 install requests2.1 獲取url
在谷歌瀏覽器先打開上網(wǎng)登錄窗口,然后按F12鍵進入開發(fā)者模式,勾選保留日志,輸入賬號密碼,進行登錄,在網(wǎng)絡(luò)那里獲取登錄時的http請求報文。
然后查看抓到的包,查看第一個即可,一般是第一個,如果不放心可以點進區(qū)查看,看到標頭里的請求方法,確保是post。然后里面還有一個請求網(wǎng)址,就是url了。只需要復(fù)制?問號前面的內(nèi)容即可,后面的是一些get方法的請求參數(shù),不明白什么意思的看長文url的解釋。
往下拉,還有響應(yīng)標頭,請求標頭等信息,:warning:注意,因為我們要向服務(wù)器請求登錄,所以我們需要的是請求標頭,而不是響應(yīng),別搞錯了。
校園網(wǎng)地址,最好不要用瀏覽器里的url,還是建議抓包獲取post_addr = "http://10.10.244.11:801/eportal/"這樣就完成了第一步,獲取到了校園網(wǎng)地址。為什么說不建議直接從瀏覽器里面復(fù)制呢,比如我們學(xué)校這種情況返回的響應(yīng)是3xx,說明網(wǎng)址被重定向過了,所以抓包到的地址比較準確一些。
2.2 獲取請求報文的報頭

把請求標頭里的內(nèi)容填充到代碼塊里,部分header的含義上文已經(jīng)解釋過,還想了解更多請自行搜索。填充的格式是鍵值 key:values模式,key和values都是字符串需要加引號,上下鍵值用逗號隔開,下面是我自己的報文,只是個例子。
#下面兩個大括號里面都是復(fù)制自己學(xué)校校園網(wǎng)登錄網(wǎng)站中的,冒號兩邊都要加上雙引號post_header = {'Accept': '*/*','Accept-Encoding': 'gzip, deflate','Accept-Language': 'zh-CN,zh;q=0.9','Cache-Control': 'max-age=0','Connection': 'keep-alive','Host': '10.10.244.11','Referer': 'http://10.10.244.11/','Upgrade-Insecure-Requests': '1','User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36',}
2.3 獲取請求報文的數(shù)據(jù)


把載荷里的查詢字符串、表單數(shù)據(jù)都填充到程序塊中,這里主要上傳的就是你的登錄信息,不要填錯了。
post_data = {'c': 'ACSetting','a': 'Login','DDDDD': 'xxxx','upass': 'xxxxx','protocol': 'http:','hostname': '10.10.244.11','iTermType': '1','wlanuserip': user_ip,'wlanacip': 'xxxxxx','wlanacname': 'SPL-BRAS-SR8806-X','mac': '00-00-00-00-00-00','ip': user_ip,'enAdvert': '0','queryACIP': '0','loginMethod': '1'}
2.4 獲取本機的局域網(wǎng)ip
為什么要單獨寫一個函數(shù)獲取主機IP呢,因為IP地址分為固定IP地址和動態(tài)IP地址,我們需要獲取的是動態(tài)的IP地址,它是一直變化的,不能直接在請求數(shù)據(jù)里填抓包拿到的地址,不然你換個地方,可能那個地址就失效了。
固定IP:固定IP地址是長期固定分配給一臺計算機使用的IP地址,一般是特殊的服務(wù)器才擁有固定IP地址。
動態(tài)IP:因為IP地址資源非常短缺,通過電話撥號上網(wǎng)或普通寬帶上網(wǎng)用戶一般不具備固定IP地址,而是由ISP動態(tài)分配暫時的一個IP地址,這些都是計算機系統(tǒng)自動完成的。
# 獲取ip地址#需要導(dǎo)入socket包,系統(tǒng)應(yīng)該自帶def get_host_ip():"""查詢本機ip地址:return: ip"""try:s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)s.connect(('10.255.255.255', 1))ip = s.getsockname()[0] finally:s.close()return ipuser_ip = get_host_ip()
寫到這里其實,已經(jīng)可以自動連接校園網(wǎng)了,但是前提是你先打開Wi-Fi,連到學(xué)校的校園網(wǎng)Wi-Fi。說到底,現(xiàn)在的功能只能幫助你登錄校園網(wǎng),連接校園網(wǎng)Wi-Fi的事情還是得你來做,如果你之前連的是其他網(wǎng)絡(luò),那么你還有進行網(wǎng)絡(luò)的切換。
所以還要再增加一個自動連接Wi-Fi的功能,剛好python里有一個pywifi包可以支持這個功能。但是!!直接pip3 安裝的pywifi包里面不支持mac os的Wi-Fi控制,因為開發(fā)這個pywifi包的作者不用mac os系統(tǒng),所以pywifi包只支持windows和linux。
好在,后來有人提出這個問題,作者后來又寫了一個適合mac os的包,不過需要自己下載。我也是經(jīng)歷很多波折,才解決了這個問題。
3.自動連接Wi-Fi
還是先在終端安裝pywifi包,然后找到pywifi包對應(yīng)位置,把內(nèi)容全部替換成支持moc os 的pywifi包。
pip3 install pywifi如果找不到pywifi路徑可以先執(zhí)行卸載命令,然后就會彈出所以安裝過的包路徑了,然后復(fù)制所需的路徑,最好選擇n命令,停止卸載就行。
得到安裝路徑以后,可以在終端里查看,也可以在mac可視化文件模式里查看,我更喜歡可視化,打開的時候有的文件夾就翻譯成中文了,我相信只要用心肯定能找到。
找到pywifi路徑之后,就要下載支持mac os的pywifi包了,下載完進行替換就行。那這個支持mac os的pywifi在哪呢?這里給出作者github的地址,作者awkman在Issue24里面也回答了,他寫了一個兼容Macos的demo程序。
moc版pywifi
作者回復(fù)
可以在終端用git命令下載,也可以,直接到作者倉庫取自己下載,大家隨意。git命令下載指令如下:-b 后面帶的是分支,作者放在macos_dev里了。
git clone -b macos_dev https://github.com/awkman/pywifi.git下載完檢查一下是不是包含了mac的.py文件,包含了就沒問題。然后把包含了mac的這個pywifi文件和之前的pywifi進行替換就行。先cd到當前文件夾,然后cp拷貝到原來路徑(怎么找路徑前文已經(jīng)說了),文件名相同會自動替換里面內(nèi)容。
cd pywificp -r pywifi /Users/wenanqin/Library/Python/3.8/lib/python/site-packages
之前我在這樣做完,運行還是報錯,因為發(fā)現(xiàn)_wifiutil_macos.py里有一個包沒安裝,裝完就好了。
pip3 install pyobjc下面開始完成連接wifi功能的代碼,在統(tǒng)一路徑下,新建一個wifi.py文件。
import pywifiimport time#保存包中寫義的常量from pywifi import constdef wifi_connect_status():"""判斷本機是否有無線網(wǎng)卡,以及連接狀態(tài):return: 已連接或存在無線網(wǎng)卡返回1,否則返回0"""#創(chuàng)建一個元線對象wifi = pywifi.PyWiFi() #取當前機器,第一個元線網(wǎng)卡iface = wifi.interfaces()[0] #有可能有多個無線網(wǎng)卡,所以要指定#判斷是否連接成功if iface.status() in [const.IFACE_CONNECTED,const.IFACE_INACTIVE]: #print('wifi已經(jīng)連接了網(wǎng)絡(luò)')return 1else:print("兄弟,我沒設(shè)置自動打開Wi-Fi功能,你先打開wifi再試?") return 0def scan_wifi():"""掃描附件wifi:return: 掃描結(jié)果對象"""#掃描附件wifiwifi = pywifi.PyWiFi()iface = wifi.interfaces()[0]iface.scan() #掃描附件wifitime.sleep(1)basewifi = iface.scan_results() # for i in basewifi:# print('wifi掃描結(jié)果:{}'.format(i.ssid)) # ssid 為wifi名稱# print('wifi設(shè)備MAC地址:{}'.format(i.bssid))return basewifidef connect_wifi():wifi = pywifi.PyWiFi() # 創(chuàng)建一個wifi對象ifaces = wifi.interfaces()[0] # 取第一個無限網(wǎng)卡#print("本機無線網(wǎng)卡名稱:")#print(ifaces.name()) # 輸出無線網(wǎng)卡名稱ifaces.disconnect() # 斷開網(wǎng)卡連接time.sleep(3) # 緩沖3秒profile = pywifi.Profile() # 配置文件profile.ssid = "NJUPT-CMCC" # wifi名稱#連校園網(wǎng)不需要密碼登錄,另有登錄模塊# profile.auth = const.AUTH_ALG_OPEN # 需要密碼# profile.akm.append(const.AKM_TYPE_WPA2PSK) # 加密類型# profile.cipher = const.CIPHER_TYPE_CCMP # 加密單元# profile.key = '4000103000' #wifi密碼ifaces.remove_all_network_profiles() # 刪除其他配置文件tmp_profile = ifaces.add_network_profile(profile) # 加載配置文件ifaces.connect(tmp_profile) # 連接time.sleep(1) # 嘗試10秒能否成功連接isok = Trueif ifaces.status() == const.IFACE_CONNECTED:print("連接校園網(wǎng)成功") else:print("連接校園網(wǎng)失敗") #ifaces.disconnect() # 斷開連接time.sleep(1) return isok
這里有三個功能,前兩個測試用的,實際可以只調(diào)用第三個。link.py登錄校園網(wǎng)之前先調(diào)用連接wifi模塊。
import requestsimport socket#導(dǎo)入剛才寫的wifi模塊,一定放在同一文件夾內(nèi)import wifi#查看wifi狀態(tài)wifi.wifi_connect_status()#連接wifiwifi.connect_wifi()# 獲取ip地址def get_host_ip():"""查詢本機ip地址:return: ip"""try:s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)s.connect(('10.255.255.255', 1))ip = s.getsockname()[0]finally:s.close()return ipuser_ip = get_host_ip()# 校園網(wǎng)地址post_addr = "http://10.10.244.11:801/eportal/"#下面兩個大括號里面都是復(fù)制自己學(xué)校校園網(wǎng)登錄網(wǎng)站中的,冒號兩邊都要加上雙引號post_header = {'Accept': '*/*','Accept-Encoding': 'gzip, deflate','Accept-Language': 'zh-CN,zh;q=0.9','Cache-Control': 'max-age=0','Connection': 'keep-alive','Host': '10.10.244.11','Referer': 'http://10.10.244.11/','Upgrade-Insecure-Requests': '1','User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36',}post_data = {'c': 'ACSetting','a': 'Login','DDDDD': ',0,xxxxxxx@cmcc','upass': 'xxxxx','protocol': 'http:','hostname': '10.10.244.11','iTermType': '1','wlanuserip': user_ip,'wlanacip': 'xxxxxxx','wlanacname': 'SPL-BRAS-SR8806-X','mac': '00-00-00-00-00-00','ip': user_ip,'enAdvert': '0','queryACIP': '0','loginMethod': '1'}z = requests.post(post_addr, data=post_data, headers=post_header)#如果不想每次都手動關(guān)閉窗口可以刪除下面的input,然后將print里的內(nèi)容改成自己想要的print("登錄校園網(wǎng)成功,局域網(wǎng)ip如下:")print(user_ip)#input("")
4.打包成exe文件
1.先安裝pyinstaller包
pip3 install pyinstaller2.找到pyinstaller命令路徑(帶bin,老方法卸載看路徑),我直接執(zhí)行不了pyinstaller指令,因為python系統(tǒng)就有,環(huán)境變量還沒配置。
3.執(zhí)行指令打包
先cd到需要打包文件的路徑下,然后執(zhí)行指令,我安裝了一個超級右鍵程序,很方便操作
#將 xx.py 打包為 xx.exe
/Users/wenanqin/Library/Python/3.8/bin/pyinstaller -F xx.py執(zhí)行完操作,會生成三個文件,exe文件在dist文件內(nèi),至此,全部工作完成。


