回忆学校服务器,总是404爆炸卡顿,查分查不了,选课选不了之类的问题结佣而至, 于是试着用selenium自动化配合python代码编写了这个脚本,便于之后的查分环节,在这个环节中遇到了一些问题, 也有一些问题没有搞定,比如这个验证码,还是有点遗憾的。
关注我,我是沙漏,不定期更新爬虫教学, 其他时间学习java 和 linux, 喜欢分享更多好玩的,有意思的代码。
获取成绩自动脚本:
- 适用范围:
- 所需技术:
- selenium中关键的点:
- 步骤解析:
- 寻找登入界面:
- 定位输入框:
- 关于验证码:
- 登入成功之后:
- 接口操作:
- 代码:
适用范围:
每个学校教务系统的支持方应该都不相同, 我的学校教务系统支持方是青果软件,如果也是青果的话,就可以很方便的套用了。
如图:
所需技术:
- python基础语法
- selenium的定位和简单应用
- Image的简单 应用
- python 3.7
效果图涉及到 学校名称 和 本人期末考试情况, 就不发出效果图了, 这个很不好意思。
selenium中关键的点:
在测试过程中,经常会碰到frame和iframe,嵌套等情况
这种情况下直接通过id,name等等是无法定位到的
好在selenium替我们想到了这个问题switch_to方法解决问题
如果正确的定位该节点,但却无法对节点操作, 或者无法发送账号密码等情况的话, 那就需要切换表单, 意思就是, selenium在对于网页中出现多个表单的时候,无法正确的定位你所定位的节点,或者权限不够, 这个时候记得切换,如何切换表单, 在步骤解析中有详细方案。
步骤解析:
寻找登入界面:
教务系统有很多入口, 不仅仅只是学生登入界面,这个时候要确定清楚,比如我学校这样的。
url: http:// ip /jwweb/ ( ip掩住,保护学校)
定位输入框:
根据上面的登入界面图, 可以发现默认身份是学生, 这样就方便了很多,但是为了确保我们打开的一定是用户登入
这个界面 ,在这里我加入了一个显性等待, 直到这个用户登陆界面
完全的加载出来, 才进行之后的总总操作
。
# 用户登入 节点加载 定位
enter = wait.until(EC.element_to_be_clickable((By.XPATH, '//*[@id="m14"]')))
enter.click()
如上, 我是这样定位的, 至于代码为什么这样, 我们暂时可以先不考虑。
我本以为接下来直接定位账号密码, 刷刷的就完成了,但是就没我想象的那么好, 出现了表单切换, 我提交不了数值,如图:
他所有数据都存放到 表单frmHomeShow 里面, 所以进行表单的切换。
# 切换表单 输入数据
browser.switch_to.frame('frmHomeShow')
切换成功之后, 定位 账号 密码:
# 定位学号
class_ID = wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="txt_asmcdefsddsd"]')))
class_ID.clear()
class_ID.send_keys(ID)
# 定位密码
class_password = wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="txt_pewerwedsdfsdff"]')))
class_password.clear()
class_password.send_keys(password)
关于验证码:
在这个网站中, 验证码 需要点击 验证码的输入框,右边才会显示出验证码。
# 定位验证码 暂时考虑直接输入 后续考虑使用tesserocr来识别
class_img = wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="txt_sdertfgsadscxcadsads"]')))
class_img.click()
关于这个验证码, 本来以为很简单的,使用PIL去底纹,去边框,去噪点就能完成, 结果傻逼了,
tesserocr
识别率 太低了吧, 压根就不能搞定,后来朋友推荐用深度学习
去搞定验证码, 但是我不会这个, 我可能还是会考虑打码平台
去实现全自动化的, 本次就人工输入
吧, 很无奈, 如果读者有类似的解决方案, 希望评论区留言分享, 多谢。
登入成功之后:
当我登陆成功之后:
当我登入成功之后, 还是以为很简单, 没想到又被打了一脸, 整个网站不是静态网站, 你甚至点击右键都不行, 所以不能用一般的方法去实现, 我猜可能是网站当时编写的语言太远古了,现在的方法不能解析。
当我点击network的时候, 惊呆了。
好家伙,都是aspx接口, 那行吧, 既然是接口, 那就模拟浏览器访问接口, 在stu_myscore 这个接口中, 我找到了对应的接口url
http:// ip /jwweb/xscj/Stu_MyScore.aspx (ip 保护学校)
接着去继续对这个接口进行操作,就大致完成了。
接口操作:
输入网址, 我进入了这个页面。
这个时候,我想到 重开一个网页, get这个网址, 然后点击检索, 这样不就出来了。 事实上, 也就这样, 但是对于成绩图片来说, 坑爹的还有一点, 这张成绩图片 不是 在网页中,而是保存在学校的后端服务器中, 我压根就爬不了这张图, 好在 selenium 有一个截屏函数, 最终使用了这个截屏功能, get到了这个分数。这里也要切换一次表单, 记得注意下。
browser.execute_script('window.open()') # 新建选项卡 功能
browser.switch_to.window(browser.window_handles[1])
browser.get(url)
# 定位检索按钮
find = wait.until(EC.presence_of_element_located(
(By.XPATH, '/html/body/form/table/tbody/tr[2]/td/table/tbody/tr[1]/td[3]/input[1]')))
find.click()
browser.switch_to.frame('main')
img = wait.until(EC.presence_of_element_located((By.XPATH, '/html/body/center/div/div/img')))
screen_path = 'screen_shot.png'
browser.save_screenshot(screen_path)
print('屏幕截图保存在:', screen_path)
# 精准定位图片
left = img.location['x'] + 200
top = img.location['y'] - 100
right = img.location['x'] + img.size['width'] + 200
bottom = img.location['y'] + img.size['height'] + 400
browser.quit()
# 打开图片 重新构造
im = Image.open(screen_path)
im = im.crop((left, top, right, bottom)) # 对浏览器截图进行裁剪
im.show()
这样就完成了本次脚本, 自动获取成绩, 总体来说,代码中还是存在一些问题, 这需要改良。有好的方法, 希望各位提出, 我就可以更好的修改。
代码:
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
import time
from PIL import Image
def sim_enter(url, ID, password):
"""
切换表单,模拟登入
params : url : NL_url
params: ID
params: password
"""
browser.get(url)
# 用户登入 节点加载 定位
enter = wait.until(EC.element_to_be_clickable((By.XPATH, '//*[@id="m14"]')))
enter.click()
# 切换表单 输入数据
browser.switch_to.frame('frmHomeShow')
# 定位学号
class_ID = wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="txt_asmcdefsddsd"]')))
class_ID.clear()
class_ID.send_keys(ID)
# 定位密码
class_password = wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="txt_pewerwedsdfsdff"]')))
class_password.clear()
class_password.send_keys(password)
# 定位验证码 暂时考虑直接输入 后续考虑使用tesserocr来识别
class_img = wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="txt_sdertfgsadscxcadsads"]')))
class_img.click()
time.sleep(10)
get_score('http://(ip)/jwweb/xscj/Stu_MyScore.aspx') # 成绩接口 得到分数函数
def get_score(url):
"""
根据登入的页面
查询成绩表
params: url : 登入后的页面
"""
browser.execute_script('window.open()') # 新建选项卡 功能
browser.switch_to.window(browser.window_handles[1])
browser.get(url)
# 定位检索按钮
find = wait.until(EC.presence_of_element_located(
(By.XPATH, '/html/body/form/table/tbody/tr[2]/td/table/tbody/tr[1]/td[3]/input[1]')))
find.click()
# 定位图片地址
browser.switch_to.frame('main')
img = wait.until(EC.presence_of_element_located((By.XPATH, '/html/body/center/div/div/img')))
# 对屏幕进行截图
screen_path = 'screen_shot.png'
browser.save_screenshot(screen_path)
print('屏幕截图保存在:', screen_path)
# 精准定位图片
left = img.location['x'] + 200
top = img.location['y'] - 100
right = img.location['x'] + img.size['width'] + 200
bottom = img.location['y'] + img.size['height'] + 400
browser.quit()
# 打开图片 重新构造
im = Image.open(screen_path)
im = im.crop((left, top, right, bottom)) # 对浏览器截图进行裁剪
im.show()
if __name__ == '__main__':
# 基本设置
NL_url = 'http://(ip)/jwweb/'
print('网页打开自动提交学号密码, 验证码自行填写后,点击登入!')
print('切换网页有点卡顿,请勿关闭!')
ID = eval(input('输入学号:'))
password = input('输入密码:')
browser = webdriver.Chrome()
wait = WebDriverWait(browser, 20) # 显示时间
sim_enter(NL_url, ID, password) # 模拟登入