python爬虫抓取正方教务系统信息

学校用的正方教务系统,参考了一些网上的例子,写了一个抓取学生信息和课表的爬虫。这里主要用到了requests发送请求和bs4解析页面。数据库用的mysql,用peewee操作数据库。

网上有说可以绕过验证码,但是那个bug貌似被修复了,就把验证码图片保存到本地,需要手动输入。

往数据库存储的麻烦了点,主要课程表那个表格有个上午下午,上午归到第一节那一行,下午归到下午第一节那一行,这样表的格式就乱了,也没想到好的方法,就先这样了。

import requests
from lxml import etree
import urllib.parse
from bs4 import BeautifulSoup
from peewee import CharField, Model, MySQLDatabase, OperationalError


db = MySQLDatabase(
    host='127.0.0.1',
    user='root',
    passwd='root',
    database='blog',
    port=3306
)
db.connect()


class Student(Model):
    stu_num = CharField()
    name = CharField()
    stu_class = CharField()
    faculty = CharField()
    major = CharField()

    class Meta:
        database = db


class Class(Model):
    name = CharField(max_length=100, null=True)
    type = CharField(max_length=10, null=True)
    mon = CharField(null=True)
    the = CharField(null=True)
    wed = CharField(null=True)
    thu = CharField(null=True)
    fri = CharField(null=True)
    sat = CharField(null=True)
    sun = CharField(null=True)

    class Meta:
        database = db

try:
    db.create_tables([Student, Class])
except OperationalError:
    pass


class Qlu:
    def __init__(self):
        self.base_url = 'http://210.44.159.22/default2.aspx'
        self.session = requests.session()

    def login(self):

        response = self.session.get(self.base_url)
        selector = etree.HTML(response.content)
        __VIEWSTATE = selector.xpath('//*[@id="form1"]/input/@value')[0]

        username = input('输入学号')
        password = input('输入密码')

        # 保存验证码图片
        check_img_url = 'http://210.44.159.22/CheckCode.aspx'
        img_resp = self.session.get(check_img_url, stream=True)
        image = img_resp.content
        with open('check.jpg', 'wb') as f:
            f.write(image)
        txtSecretCode = input('输入验证码')

        data = {
            '__VIEWSTATE': __VIEWSTATE,
            'txtUserName': username,
            'TextBox2': password,
            'txtSecretCode': txtSecretCode,
            'RadioButtonList1': '(unable to decode value)',
            'Button1': '',
            'lbLanguage': '',
            'hidPdrs': '',
            'hidsc': '',
        }
        loginResp = self.session.post(self.base_url, data=data)
        # 登录后的url
        info_url = 'http://210.44.159.22/xs_main.aspx?xh={}'.format(username)
        self.session.headers['Referer'] = info_url

        # 登陆后页面信息
        login_page = self.session.get(info_url)
        soup = BeautifulSoup(login_page.text, 'lxml')

        # 学生姓名
        name = soup.select('#xhxm')[0].get_text()[:-2]
        self.get_schedule(username, name)

    def get_stu_info(self, soup):
        stu_num = soup.select('#Label5')[0].get_text()  # 学号
        name = soup.select('#Label6')[0].get_text()  # 姓名
        faculty = soup.select('#Label7')[0].get_text()  # 院系
        major = soup.select('#Label8')[0].get_text()  # 专业
        class1 = soup.select('#Label9')[0].get_text()  # 班级
        Student.create(stu_num=stu_num, name=name, stu_class=class1, faculty=faculty, major=major)

    # 得到学生课表
    def get_schedule(self, username, name):
        # 把学生名字编码
        name = urllib.parse.quote_plus(name.encode('gb2312'))
        # 请求课表的url
        req_url = 'http://210.44.159.22/xskbcx.aspx?xh=' + username + '&xm=' + name + '&gnmkdm=N121603'
        response = self.session.get(req_url)
        soup = BeautifulSoup(response.text, 'lxml')
        # 学生基本信息
        self.get_stu_info(soup)

        __VIEWSTATE = soup.select('#xskb_form input')[2].get('value')

        xnd = input('输入学年(例如输入2016,查询2016-2017学年的)')
        xqd = input('输入学期(1或2)')

        data = {
            '__EVENTTARGET': 'xnd',
            '__EVENTARGUMENT': '',
            '__VIEWSTATE': __VIEWSTATE,
            'xnd': str(xnd) + '-' + str(int(xnd)+1),         # 学年 2015-2016
            'xqd': xqd          # 学期
        }

        self.session.headers['Referer'] = 'http://210.44.159.22/xs_main.aspx?xh={}'.format(username)
        resp = self.session.post(req_url, data=data)
        soup = BeautifulSoup(resp.text, 'lxml')
        tr = soup.select('tr')

        year = str(xnd) + '-' + str(int(xnd)+1) + '学年'
        term = '第' + str(xqd) + '学期'
        # 数据表名
        table_name = year + '/' + term

        # 第1、2节
        fir = tr[4].select('td')
        Class.create(name=table_name, type='1、2节', mon=fir[2].get_text(), the=fir[3].get_text(), wed=fir[4].get_text(), thu=fir[5].get_text(), fri=fir[6].get_text(), sat=fir[7].get_text(), sun=fir[8].get_text())

        # 第3、4节
        sec = tr[6].select('td')
        Class.create(mon=sec[1].get_text(), type='3、4节', the=sec[2].get_text(), wed=sec[3].get_text(), thu=sec[4].get_text(), fri=sec[5].get_text(), sat=sec[6].get_text(), sun=sec[7].get_text())

        # 第5、6节
        thi = tr[8].select('td')
        Class.create(mon=thi[2].get_text(), type='5、6节', the=thi[3].get_text(), wed=thi[4].get_text(), thu=thi[5].get_text(), fri=thi[6].get_text(), sat=thi[7].get_text(), sun=thi[8].get_text())

        # 第7、8节
        fou = tr[10].select('td')
        Class.create(mon=fou[1].get_text(), type='7、8节', the=fou[2].get_text(), wed=fou[3].get_text(), thu=fou[4].get_text(), fri=fou[5].get_text(), sat=fou[6].get_text(), sun=fou[7].get_text())

        # 第9、10节
        fiv = tr[12].select('td')
        Class.create(mon=fiv[2].get_text(), type='9、10节', the=fiv[3].get_text(), wed=fiv[4].get_text(), thu=fiv[5].get_text(), fri=fiv[6].get_text(), sat=fiv[7].get_text(), sun=fiv[8].get_text())

        # 第11节
        sev = tr[14].select('td')
        Class.create(mon=sev[1].get_text(), type='11节', the=sev[2].get_text(), wed=sev[3].get_text(), thu=sev[4].get_text(), fri=sev[5].get_text(), sat=sev[6].get_text(), sun=sev[7].get_text())


spi = Qlu()
spi.login()


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

推荐阅读更多精彩内容