回忆学校服务器,总是404爆炸卡顿,查分查不了,选课选不了之类的问题结佣而至, 于是试着用selenium自动化配合python代码编写了这个脚本,便于之后的查分环节,在这个环节中遇到了一些问题, 也有一些问题没有搞定,比如这个验证码,还是有点遗憾的。 关注我,我是沙漏,不定期更新爬虫教学, 其他时间学习java 和 linux, 喜欢分享更多好玩的,有意思的代码。

Python爬取教师资格证成绩 python成绩查询代码_验证码



获取成绩自动脚本:

  • 适用范围:
  • 所需技术:
  • selenium中关键的点:
  • 步骤解析:
  • 寻找登入界面:
  • 定位输入框:
  • 关于验证码:
  • 登入成功之后:
  • 接口操作:
  • 代码:


适用范围:

每个学校教务系统的支持方应该都不相同, 我的学校教务系统支持方是青果软件,如果也是青果的话,就可以很方便的套用了。

如图:

Python爬取教师资格证成绩 python成绩查询代码_Python爬取教师资格证成绩_02

所需技术:

  • python基础语法
  • selenium的定位和简单应用
  • Image的简单 应用
  • python 3.7

效果图涉及到 学校名称 和 本人期末考试情况, 就不发出效果图了, 这个很不好意思。


selenium中关键的点:

在测试过程中,经常会碰到frame和iframe,嵌套等情况

这种情况下直接通过id,name等等是无法定位到的

好在selenium替我们想到了这个问题switch_to方法解决问题

如果正确的定位该节点,但却无法对节点操作, 或者无法发送账号密码等情况的话, 那就需要切换表单, 意思就是, selenium在对于网页中出现多个表单的时候,无法正确的定位你所定位的节点,或者权限不够, 这个时候记得切换,如何切换表单, 在步骤解析中有详细方案。

步骤解析:

寻找登入界面:

教务系统有很多入口, 不仅仅只是学生登入界面,这个时候要确定清楚,比如我学校这样的。

url: http:// ip /jwweb/ ( ip掩住,保护学校)

Python爬取教师资格证成绩 python成绩查询代码_定位_03

定位输入框:

根据上面的登入界面图, 可以发现默认身份是学生, 这样就方便了很多,但是为了确保我们打开的一定是用户登入这个界面 ,在这里我加入了一个显性等待, 直到这个用户登陆界面完全的加载出来, 才进行之后的总总操作

# 用户登入 节点加载  定位
enter = wait.until(EC.element_to_be_clickable((By.XPATH, '//*[@id="m14"]')))
enter.click()

如上, 我是这样定位的, 至于代码为什么这样, 我们暂时可以先不考虑。

我本以为接下来直接定位账号密码, 刷刷的就完成了,但是就没我想象的那么好, 出现了表单切换, 我提交不了数值,如图:

Python爬取教师资格证成绩 python成绩查询代码_定位_04

他所有数据都存放到 表单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 识别率 太低了吧, 压根就不能搞定,后来朋友推荐用 深度学习 去搞定验证码, 但是我不会这个, 我可能还是会考虑打码平台 去实现全自动化的, 本次就人工输入吧, 很无奈, 如果读者有类似的解决方案, 希望评论区留言分享, 多谢。

登入成功之后:

当我登陆成功之后:

Python爬取教师资格证成绩 python成绩查询代码_python_05


当我登入成功之后, 还是以为很简单, 没想到又被打了一脸, 整个网站不是静态网站, 你甚至点击右键都不行, 所以不能用一般的方法去实现, 我猜可能是网站当时编写的语言太远古了,现在的方法不能解析。

当我点击network的时候, 惊呆了。

Python爬取教师资格证成绩 python成绩查询代码_定位_06

好家伙,都是aspx接口, 那行吧, 既然是接口, 那就模拟浏览器访问接口, 在stu_myscore 这个接口中, 我找到了对应的接口url
http:// ip /jwweb/xscj/Stu_MyScore.aspx (ip 保护学校)

接着去继续对这个接口进行操作,就大致完成了。

接口操作:

输入网址, 我进入了这个页面。

Python爬取教师资格证成绩 python成绩查询代码_验证码_07

这个时候,我想到 重开一个网页, 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)  # 模拟登入