python爬取学校教务系统

写这个爬虫的缘由

以前用java写过一个爬取学校的教务系统的爬虫 https://blog.csdn.net/ygdxt/article/details/81158321,最近痴迷Python爬虫,了解到许多强大的库,想再一次用学校的教务系统做下测试。

这一次我首先想到的是新的教务系统,这个难度更大,因为有了验证码识别反爬,由于我是用的tessocr库识别验证码,(具体配置过程可以参考我之前的博客 python填坑之路:tesserocr配置)
用Requests.get方法把验证码下载下来识别之后,同时因为我爬取网页是用的selenium做的模拟网页动作,这里就有一个同步性的问题,不能保证selenium请求网页上的验证码和requests请求的验证码是同一个,相当于selenium、requests分别请求了一次登陆网页,两个网页上的验证码显然是不同的。所以

怎么保证请求登录界面得到的网页上的验证码
和我们请求验证码服务器返回的验证码是同一个验证码是同一个是一个很迷人的问题,
我开始还以为可以从网页源代码上直接定位到这个验证码,结果显示这个验证码在登录界面的  
的存在形式不是一个..png/jpg,而是通过src=“验证码服务器”来实现异步加载

同时,由于tessocr识别验证码的成功率可能只有50%,要提高验证率可能还要对接云打码,果断放弃了爬取新教务系统的想法,还是爬取原来的没有验证码的旧教务系统,
其实新旧教务系统最大的区别就是登陆界面不一样,登陆之后都一样,貌似用了重定向
ps:如果你对这个问题有什么好的解决办法,请不吝赐教

运行结果预览

20181128201749396.png

编码过程

详细的代码解释就看注释吧,有什么问题欢迎交流

执行爬虫的主程序csu.py,里面有许多测试用的注释代码,就不删了

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.select import Select

from config import *

import time
broswer = webdriver.Chrome()
wait = WebDriverWait(broswer, 10)

def search():
    try:
        broswer.get("http://csujwc.its.csu.edu.cn/jsxsd/kscj/yscjcx_list")
        account = wait.until(
            EC.presence_of_element_located((By.CSS_SELECTOR, "#userAccount"))
        )
        password = wait.until(
            EC.presence_of_element_located((By.CSS_SELECTOR, "#userPassword"))
        )

        submit = wait.until(
            EC.element_to_be_clickable((By.CSS_SELECTOR, "#btnSubmit"))
        )
    except TimeoutException:
        return search()

    #登录
    account.send_keys(ACCOUNT)
    password.send_keys(PASSWORD)
    submit.click()

   #进入我的成绩界面
    my_score = wait.until(
        EC.presence_of_element_located((By.CSS_SELECTOR,"body > div.wap > a:nth-child(3) > div"))
    )
    my_score.click()


#成绩和平均分
    # my_rank = wait.until(
    #     EC.presence_of_element_located((By.CSS_SELECTOR, "#LeftMenu1_divChildMenu > ul > li:nth-child(4) > a"))
    # )
    # my_rank.click()
    #
    # rank = wait.until(
    #     EC.presence_of_element_located((By.CSS_SELECTOR, "#dataList > tbody > tr:nth-child(2) > td:nth-child(3)"))
    # )
    # #http://www.w3school.com.cn/cssref/selector_nth-child.asp nth-child(n)的用法
    # average_score = wait.until(
    #     EC.presence_of_element_located((By.CSS_SELECTOR, "#dataList > tbody > tr:nth-child(2) > td:nth-child(4)"))
    # )
    #
    # print('您的平均成绩是:'+average_score.text+"\n排名:"+rank.text)


#逐次展示 我的成绩八个子项
    # css_selector = "#LeftMenu1_divChildMenu > ul > li:nth-child({0}) > a"
    # for i in range(8):
    #     # 将滚动条移动到页面的顶部
    #     js = "var q=document.documentElement.scrollTop=0"
    #     broswer.execute_script(js)
    #     time.sleep(2)
    #
    #     aviable_score = wait.until(
    #         EC.presence_of_element_located((By.CSS_SELECTOR, css_selector.format(str(i+1))))
    #     )
    #     aviable_score.click()
    #
    #
    #     #将滚动条移动到页面的底部
    #     for j in range(8):
    #         js="var q=document.documentElement.scrollTop="+str(j*200)
    #         broswer.execute_script(js)
    #         time.sleep(1)


    #处理select https://www.cnblogs.com/imyalost/p/7846653.html
    yxcj = wait.until(
        EC.element_to_be_clickable((By.CSS_SELECTOR, "#LeftMenu1_divChildMenu > ul > li:nth-child(1) > a"))
    )
    select_score_element = broswer.find_element_by_css_selector("#xnxq01id")
    select_score = Select(select_score_element)

    #得到下拉列表的所有子项
    select_score_items = broswer.find_elements_by_css_selector("#xnxq01id option")
    select_score_items_text = []
    for item in select_score_items:
        select_score_items_text.append(item.text)
        #print(item.text)

    scores_dic = {}
    for i in range(len(select_score.options)):
        #不加这两行会报错,原因: https://blog.csdn.net/ulebo/article/details/52128033
        print("*****************************************************"+select_score_items_text[i]+
              "*****************************************************")
        select_score_element = broswer.find_element_by_css_selector("#xnxq01id")
        select_score = Select(select_score_element)
        select_score.select_by_index(i)
        time.sleep(1)
        score_table = broswer.find_element_by_css_selector("#dataList")
        data = score_table.text.replace("+","")
        data = data.split("\n")
        datalist = []
        for line in data:
            datalist.append(line.split())
        scores_dic[select_score_items_text[i]] = datalist

    return scores_dic[select_score_items_text[0]]





def main():
    search()

if __name__ =="__main__":
    main()

ui.py程序的gui,直接运行这个就好,它会调用csu.py

    #coding=utf-8
import wx
import wx.grid
import csu

class UI(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self,parent=None,title="成绩查询",size=(1050,560))


        grid = wx.grid.Grid(self,pos=(10,0),size=(1050,500))
        grid.CreateGrid(100,9)
        for i in range(100):
            for j in range(9):
                grid.SetCellAlignment(i,j,wx.ALIGN_CENTER,wx.ALIGN_CENTER)
        grid.SetColLabelValue(0, "序号") #第一列标签
        grid.SetColLabelValue(1, "初修学期")
        grid.SetColLabelValue(2, "获得学期")
        grid.SetColLabelValue(3, "课程")
        grid.SetColLabelValue(4, "成绩")  # 第一列标签
        grid.SetColLabelValue(5, "学分")
        grid.SetColLabelValue(6, "课程属性")
        grid.SetColLabelValue(7, "课程性质")
        grid.SetColLabelValue(8, "获得方式")  # 第一列标签

        grid.SetColSize(0,50)
        grid.SetColSize(1,100)
        grid.SetColSize(2,100)
        grid.SetColSize(3,350)
        grid.SetColSize(4,50)
        grid.SetColSize(5,50)
        grid.SetColSize(6,50)
        grid.SetColSize(7,100)
        grid.SetColSize(8,100)


        grid.SetCellTextColour("NAVY")
        data = csu.search()
        data.remove(data[0])
        print(data)
        for i,item1 in enumerate(data):
            for j,item2 in enumerate(item1):
                grid.SetCellValue(i,j,data[i][j])

        pass


app = wx.App()
frame = UI()
frame.Show()
app.MainLoop()

想要运行代码,具体的配置过程请参考readme

源代码地址https://github.com/inspurer/PythonSpider/tree/master/csu

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容