前言
最近在折腾服务器,而服务器没有公网地址,连接着校园网,而校园网若想链接到Internet需要使用学号密码进行登录。但这种登录方式经常被踢下线,就需要重新登录联网。服务器放在很远的机房,而我又是懒人本懒,好在实验室的电脑也连接着相同的校园网,校园网内是可以互相访问的,也就是我可以不连接到互联网,通过校园网就可以对服务器进行一系列的操作。所以想能不能写个简单的程序,实现远程控制服务器联网。
思路
之前用Python实现过一个自动网课的脚本,通过selenium库的浏览器驱动,模拟浏览器上的表单、点击事件等。而网络登录也是个网页(客户端不支持Linux),所以考虑通过同样的方式模拟填写表单,点击登录,以实现浏览器端登录。
准备工作
服务器是Ubuntu系统,并且已经安装过了Chrome,所以这次驱动也选择Chromedriver。这里采用了无头浏览器的方式进行登录。
我们假设服务器端已经安装了Anaconda基础环境,python版本3.8,chromedriver一定要对应版本进行下载,下载地址:http://chromedriver.storage.googleapis.com/index.html
需要额外安装的python库:selenium和urllib3。
如果服务器当前已经连接了网络,可以直接把上述环境安装到服务器上。
假设服务器处于断网状态,而又懒得去机房上网(没错,说的就是我...),可以通过下载离线安装包的方式进行安装。推荐使用清华大学镜像:https://pypi.tuna.tsinghua.edu.cn/simple/
需要注意的是:要先安装rullib3,再安装selenium。
这里给出我的环境仅供参考:Python3.8 + selenium 3.141.0 + urllib3 1.25.11
离线包下载完成后,将包和chromedriver一并通过SSH连接传入服务器中。进入anaconda环境,pip安装selenium和urllib3的离线包,至此,可以开始写代码了。
代码
代码思路很简单,通过webdriver创建浏览器对象,访问登录url,通过element找到用户名、密码的text和登录button。这里查找定位元素的方法为find_element_by_xpath(),而上述元素的xpath可以通过右键——审查元素——Copy——Copy XPath来一键复制。以百度为例:
这样我们就获取到了一个元素的xpath,我们用同样的方法获取登录页面的用户名、密码、登录按钮或其他一切登录时需要修改的元素的xpath,依次进行操作。如果是输入至文本框,则调用send_keys(输入的内容),如果是按钮,则直接调用click()函数。详细代码如下:
def connect(driver_path, url, userName, userPassword):
# 创建浏览器参数对象
chrome_options = Options()
# 设置无头无界面
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')
# 创建Chrome对象
driver = webdriver.Chrome(executable_path=driver_path, options=chrome_options)
# 访问登录地址
driver.get(url)
# 让网页响应一会儿
time.sleep(5)
# 通过用户名xpath进行定位, 使用send_keys填写用户名。
el_userName = driver.find_element_by_xpath("//*[@id=\"testUserName\"]")
el_userName.send_keys(userName)
# 通过密码xpath进行定位, 使用send_keys填写密码。
el_userPwd = driver.find_element_by_xpath("//*[@id=\"testUserPassword\"]")
el_userPwd.send_keys(userPwd)
# 通过xpath定位登录按钮, 使用click()模拟点击操作。
driver.find_element_by_xpath("//*[@id=\"testLogin\"]").click()
time.sleep(3)
核心代码还是很简单的,我们使用requests库进行测试,查看是否真的连接至网络了(requests库如果没有安装,参照selenium库安装方法,使用离线包进行安装):
# 测试是否连接至网络,其实就是ping一ping百度
def isConnected():
try:
html = requests.get("http://www.baidu.com", timeout=2)
except:
return False
return True
我们使用main函数进行组装,完整代码如下:
import time
import os
import getpass
import requests
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
# 测试是否连接至网络,其实就是ping一ping百度
def isConnected():
try:
html = requests.get("http://www.baidu.com", timeout=2)
except:
return False
return True
def connect(driver_path, url, userName, userPassword):
# 创建浏览器参数对象
chrome_options = Options()
# 设置无头无界面
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')
# 创建Chrome对象
driver = webdriver.Chrome(executable_path=driver_path, options=chrome_options)
# 访问登录地址
driver.get(url)
# 让网页响应一会儿
time.sleep(5)
# 通过用户名xpath进行定位, 使用send_keys填写用户名
el_userName = driver.find_element_by_xpath("//*[@id=\"testUserName\"]")
el_userName.send_keys(userName)
# 通过密码xpath进行定位, 使用send_keys填写密码
el_userPwd = driver.find_element_by_xpath("//*[@id=\"testUserPassword\"]")
el_userPwd.send_keys(userPwd)
# 通过xpath定位登录按钮, 使用click()模拟点击操作
driver.find_element_by_xpath("//*[@id=\"testLogin\"]").click()
time.sleep(3)
if __name__ == '__main__':
# 控制台输入用户名密码
userName = input('用户名:')
userPassword= getpass.getpass('密码:')
# chromedriver存放路径
dv_path = '/shares/chromedriver'
# 登录地址
login_url = 'http://test.login'
# 调用连接函数
connect(dv_path, login_url, userName, userPassword)
# 检查是否连接至网络
if isConnected():
print('The connection is established')
else:
print('Connecting to the network failed.\nPlease check your \'Username\' and \'Password\'!')
展望
这种方法肯定是有安全缺陷的,因为平时服务器不需要上网,而且账户只允许一个IP登录,所以一般都是上网结束后就在本地把账户登回来了,故安全方面未做太多考虑。