欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

JNU教务系统一键成绩查询

程序员文章站 2024-01-20 18:28:52
本文使用到的主要第三方库:selenium本文主要使用第三方API:腾讯通用文字识别API由于最近出于出成绩时期,每天都会查一下成绩,学校的教务系统cookie不操作一段时间会过期,又要重新登入.需要输入验证码.就感觉挺麻烦的,所以就搞了个自动查询吧.待解决问题:如何访问学校教务系统网站,获取数据.一开始我是想采用http协议get,post直接获取html数据的…不过实在有点懒了,还是直接用之前就用过的selenium库吧.验证码问题:验证码的问题,我前前后后想了好几种解决策略吧,首先是...

本文使用到的主要第三方库:selenium
本文主要使用第三方API:腾讯通用文字识别API

由于最近出于出成绩时期,每天都会查一下成绩,学校的教务系统cookie不操作一段时间会过期,又要重新登入.需要输入验证码.就感觉挺麻烦的,所以就搞了个自动查询吧.

待解决问题:

  • 如何访问学校教务系统网站,获取数据.一开始我是想采用http协议get,post直接获取html数据的…不过实在有点懒了,还是直接用之前就用过的selenium库吧.

  • 验证码问题:验证码的问题,我前前后后想了好几种解决策略吧,首先是尝试了COOKIE,想试试免登入,不过失败了.然后就是尝试绕过验证码,事实证明,虽然教务系统的服务器是土豆,不过也没那么好破解.第三条路就是图像识别了.关于图像识别我尝试了两种方案:

  • 首先是pytesseract.我的理解就是一个图像识别引擎,不过直接用的识别率真的太菜了.然后我尝试对学校验证码降噪,一开始是二值化后,去掉细线.不过虽然学校验证码看着挺草率的两条线,搞起来挺要命的,有粗有细.不太好根据线的宽度进行降噪.我又想到了根据颜色来降噪.因为线是单独的一种颜色,取色器取色,再遍历像素,如果是线的颜色,就改为背景色.即使这样,识别度还是不高.在我以为要失败的时候.

  • 想起了QQ截图自带的文字识别功能,一试…流批!没处理过的验证码都识别出来了,然后我就立刻去找有没有开放API,还真有.那验证码的问题也解决了.

JNU教务系统一键成绩查询

首先是对网站进行操作的相关源码

from selenium import webdriver
from tencentapi import api
from selenium.webdriver.support.ui import Select

#隐藏了浏览器窗口,以及selenium的日志
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('headless')
chrome_options.add_experimental_option('excludeSwitches', ['enable-logging'])
driver = webdriver.Chrome(chrome_options=chrome_options)

driver.get("https://webvpn.jnu.edu.cn/")  # 地址栏里输入网址
driver.find_element_by_id('user_login').send_keys("")#账号
driver.find_element_by_id('user_password').send_keys('')#密码
driver.find_element_by_name('commit').click()

Flag=True
#验证码识别率不是百分百,不成功就再试一次
while(Flag):
    try:
        driver.get("https://jwxt-443.webvpn.jnu.edu.cn/")  # 地址栏里输入网址
        driver.find_element_by_id('txtYHBS').send_keys("")#账号
        driver.find_element_by_id('txtYHMM').send_keys('')#密码
        img = driver.find_element_by_xpath('/html/body/form/table/tbody/tr/td/table/tbody/tr/td/table/tbody/tr[2]/td[2]/table/tbody/tr[9]/td[3]/img')
        #我只能说,这行代码真的很厉害
        base64_data=img.screenshot_as_base64
        FJM = api(base64_data)
        driver.find_element_by_id('txtFJM').send_keys(FJM) 
        driver.find_element_by_id('btnLogin').click()
        driver.get('https://jwxt-443.webvpn.jnu.edu.cn/Secure/Cjgl/Cjgl_Cjcx_XsCxXqCj.aspx')
    except:
        pass
    else:
        break

# driver.get('https://jwxt-443.webvpn.jnu.edu.cn/Secure/Cjgl/Cjgl_Cjcx_XsCxXqCj.aspx')


s1 = Select(driver.find_element_by_id('ddListXQ'))
s1.select_by_value('下')
driver.find_element_by_id('lbtnQuery').click()

print(driver.find_element_by_id('dgrdList').text)

在中间其实会遇到一个问题,我觉得挺棘手的,就是验证码的获取问题.由于验证码的src并不是静态的,如果重新通过src获取只会获取到新的验证码图片,网上的方法都是采用截图的方法,我看网上的方法感觉很复杂,很绝望.然后随手对img元素打了个.结果索引出了screenshot方法,更流批的是,还可以as_base64,我人都傻了,只能喊句selenium流批!(后面API的调用,使用的就是图片的base64编码)

关于腾讯API的调用源码

# with open("ValidateCode.png","rb") as f:
#     # b64encode是编码,b64decode是解码
#     base64_data = base64.b64encode(f.read())
#     base64_data = str(base64_data,'utf-8')
#     # print(base64_data)
import json
from tencentcloud.common import credential
from tencentcloud.common.profile.client_profile import ClientProfile
from tencentcloud.common.profile.http_profile import HttpProfile
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException 
from tencentcloud.ocr.v20181119 import ocr_client, models
def api(base64_data): 
    base64_data = base64_data
    try: 
        cred = credential.Credential("这里是secretid", "这里是key") 
        httpProfile = HttpProfile()
        httpProfile.endpoint = "ocr.tencentcloudapi.com"

        clientProfile = ClientProfile()
        clientProfile.httpProfile = httpProfile
        client = ocr_client.OcrClient(cred, "ap-guangzhou", clientProfile) 

        req = models.EnglishOCRRequest()
        params = '{\"ImageBase64\":\"'+base64_data+'\"}'
        req.from_json_string(params)

        resp = client.EnglishOCR(req) 
        
        # print(resp.to_json_string()) 

        json1 = json.loads(resp.to_json_string())
        FJM = json1['TextDetections'][0]['DetectedText']
        # print(FJM)
    except TencentCloudSDKException as err: 
        print(err)
    return FJM

这个代码就没啥特别的了…不是简单,我也不会写,这是API的demo,原样复制…我只是加了个json操作方便读取识别结果,然后封装成函数方便调用.

腾讯文字识别API文档
登入账号获取id和key后要在这里实名注册,开通服务,每个月免费1000次识别,理论上够用

感慨:

  • 又是一篇对第三方库调用的操作…调参侠好歹还调调参呢
  • 虽然没搞啥技术,但是selenium是真滴强…现在互联网公司搞得人工智能API也是真滴强…
  • 又划水了一天
  • 还是想知道以前的公众号是怎么解决的验证码问题

下面是失败了的pytesseract尝试,也不算完全没用吧,降噪处理的话,说不定可以提高一下API的识别正确率

#coding = utf -8
from PIL import Image
import pytesseract
import cv2
import numpy as np
import matplotlib.pyplot as plt
import math
from PIL import Image,ImageEnhance,ImageFilter
from PIL import Image


color=[(255,0,0),(211,211,211)]
img = Image.open("ValidateCode.png")#读取系统的内照片
# print (img.size)#打印图片大小
# print (img.getpixel((4,4)))

width = img.size[0]#长度
height = img.size[1]#宽度
for i in range(0,width):#遍历所有长度的点
    for j in range(0,height):#遍历所有宽度的点
        data = (img.getpixel((i,j)))#打印该图片的所有点
        # print (data)#打印每个像素点的颜色RGBA的值(r,g,b,alpha)
        # print (data[0])#打印RGBA的r值
        if (data[0]==105 and data[1]==105 and data[2]==105):#RGBA的r值大于170,并且g值大于170,并且b值大于170
            count=[0,0]
            for t in range(3):
                for q in range(3):
                    if(i+t-1>=0 and j+q-1>=0 and i+t-1<width and j+q-1<height):
                        temp = img.getpixel((i+t-1,j+q-1))
                        if(temp[0]==255):
                            count[0]+=1
                        else:
                            count[1]+=1
            

            img.putpixel((i,j),color[count.index(max(count))])#则这些像素点的颜色改成大红色


img.save('1.png')

im = Image.open("1.png")
text = pytesseract.image_to_string((im))

print (text)

本文地址:https://blog.csdn.net/rglkt/article/details/107498682