美文网首页
2018-03-02

2018-03-02

作者: Warms_c948 | 来源:发表于2018-03-02 21:35 被阅读0次

    项目名称:爬取正方教务网课表及成绩信息

    所需主要库文件:

    • requests
    • BeautifulSoup
    • openpyxl

    项目需求:

    • 利用代码登陆教务网
    • 爬取课程信息
    • 爬取成绩信息

    以浙江农林大学教务网为例

    0.打开教务网->审查元素->NetWork->刷新教务网
    image.png
    image.png
    可以看到default2.aspxCheckCode.aspx这两个链接
    通过观察请求头可以发现,二者的Cookie值是一样的,
    所以可以通过生成一个requests.session()对象来保留cookie信息
    先请求default2.aspx保留cookie信息,再请求CheckCode.aspx两次请求cookie值相同,从而确保登陆
    1、创建一个session对象访问default2.aspx记录cookie信息
        s = requests.session()#相当于一个浏览器 记录所有信息
        #eg.msgbox('正在连接教务网....',image='wait.gif')
        try:
            response = s.get("http://115.236.84.162/default2.aspx",headers=headers,timeout=5)
            #print(response.status_code)
        except ReadTimeout:
            eg.msgbox('超时了,教务网好像蹦了。。。再试试。。(Timeout)','作者:Warms QQ:769737584',image='pawd.gif')
            #print('Timeout')
            return 0
        except ConnectionError:
            eg.msgbox('请检查你的网络!','作者:Warms QQ:769737584',image='pawd.gif')
            #print('Connection error')
            return 0
        except RequestException:
            eg.msgbox('教务网蹦了。。。。(HTTPerror)','作者:Warms QQ:769737584',image='pawd.gif')
            #print('Error')
            return 0
    
    2、使用上一步的session对象访问CheckCode.aspx获取验证码
    res = s.get('http://115.236.84.162/CheckCode.aspx',headers=headers)
    with open('验证码.gif','wb') as f:
        f.write(res.content)
    #os.system('验证码.gif')
    msg = '请输入验证码(看不清请点击"Cancel"):'
    img = '验证码.gif'
    while True:
        Code = eg.enterbox(msg,'作者:Warms QQ:769737584',image=img)
        if Code == '':
            msg = '验证码不能为空!'
            continue
        elif Code==None:
            res = s.get('http://115.236.84.162/CheckCode.aspx', headers=headers)
            with open('验证码.gif', 'wb') as f:
                f.write(res.content)
            continue
        else:
            break
    

    上面已经通过代码访问了教务网首页,下一步就是登陆

    浏览器打开教务网输入用户名、密码、验证码->登陆

    审查元素->NetWork->查看网络请求
    image.png
    在拦截的网络请求中可以看到default2.aspxRequest Method变为了post请求,再来查看一下Form data
    image.png
    Form data中有__VIEWSTATE这个键,其值时可变的,在post数据中也是必不可少的,下一步是怎样获取这个值,打开教务网登陆首页->查看源代码->Ctrl+F搜索.

    image.png

    在源代码中找到了__VIEWSTATE它在一个input标签中 属性value及为需要的数据,利用BeautifulSoup解析库可以方便的提取出__VIEWSTATE

    soup = BeautifulSoup(response.text,'lxml')
    value =soup.find('input')['value']
    

    Form data中还有一个键为RadioButtonList1,搜索登陆页源代码可知这是URL编码后的学生 两字(这里是以学生身份登陆所以是学生)

    image.png

    requests库会自动进行URL编码 也可以从 urllib.parse库中引入urlencode方法进行编码
    构建post_data

    def get_post_data(number,passward,Code,value):
        data = {
        '__VIEWSTATE':value,
        'txtUserName':number,
        'Textbox1':'',
        'TextBox2':passward,
        'txtSecretCode':Code,
        'RadioButtonList1': '学生',
        'Button1':'',
        'lbLanguage':'',
        'hidPdrs':'',
        'hidsc':'',
         '__EVENTVALIDATION':''
        }
        return data
    
    3、发送post请求完成登陆
    try:
        response =s.post('http://115.236.84.162/default2.aspx',data=get_post_data(number=students_number,passward=passward, Code=Code,value=value),headers=headers)#登陆首页 响应
    except ReadTimeout:
        eg.msgbox('超时了,教务网好像蹦了。。。(Timeout)''作者:Warms QQ:769737584',image='pawd.gif')
        #print('Timeout')
        return 0
    except ConnectionError:
        eg.msgbox('请检查你的网络!''作者:Warms QQ:769737584',image='pawd.gif')
        #print('Connection error')
        return 0
    except RequestException:
        eg.msgbox('教务网蹦了。。。。(HTTPerror)''作者:Warms QQ:769737584',image='pawd.gif')
        #print('Error')
        return 0
    
    3、判断是否登陆成功

    由于登录后defaut.aspx2的状态码是302 重定向,requests库后会自动跳转到重定向后的网址,如需关闭请将allow_redirects参数设为False这里不关闭,由于会切换网页所以response的URL会改变,这里通过判断URL是否切换来判断是否登陆成功

    if  'xs_main.aspx'in response.url :#if 'xs_main.aspx'in response.url :6671
        #print('login Success!')
        choices = ['最新学年课表','成绩单']
        while True:
            choice = eg.indexbox('请选择查询类型:','作者:Warms',image='success.gif',choices=choices)
            if choice == 0:
                class_html = get_class_infor(s,response.text).replace(r'<br>', '\n')
                code= save_class_infor(class_html)
                return code
            elif choice == 1:
                grades_html = get_grates_infor(s,response.text).replace('&nbsp;',' ')
                code=save_grades_infor(grades_html)
                return code
    else :
        return 4#输入信息有误
    
    4、拉取课表框架代码->BeaufulSoup库解析->存储到excel

    这里还是用之前创建的requests.session()对象来访问课表URL,即需要保持相同的cookie值,否则会出现302 错误无法获取框架代码,注意这里的header一定要加上Referer:http://115.236.84.162/xs_main.aspx?xh=' + students_number (登录后的URL加上学生学号)否则会出错

        def get_class_infor(s,text):
            header = {
                'Referer': 'http://115.236.84.162/xs_main.aspx?xh=' + students_number,
                'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36'
            }
            params = get_params_data(text)#获取get请求参数
            class_url = 'http://115.236.84.162/xskbcx.aspx'
            response = s.get(class_url, headers=header, params=params )#课程信息 响应体
            return response.text
    
        def get_params_data(text):
            soup = BeautifulSoup(text, 'lxml')
            name = soup.find(id="xhxm").string[:2]
            params = {
                'xh': students_number,
                'xm': name,
                'gnmkdm': 'N121603'
            }
            return params
    
    5、拉取成绩框架->BeautifulSoup解析->存储到excel
    def get_grates_infor(s,text):
        header = {
            'Referer': 'http://115.236.84.162/xs_main.aspx?xh=' + students_number,
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36'
        }
        payload = {
            '__EVENTTARGET':'',
            '__EVENTARGUMENT':'',
            '__VIEWSTATE': '',
            'hidLanguage':'',
            'ddlXN':'',
            'ddlXQ':'',
            'ddl_kcxz':'',
            'btn_zcj':'历年成绩'
        }
        params = get_params_data(text)  # 获取get请求参数
        grades_url = 'http://115.236.84.162/xscjcx.aspx'
        response = s.get(grades_url, headers=header, params=params)  # 成绩信息 响应体
        #print(response.url)
        soup = BeautifulSoup(response.text, 'lxml')
        value = soup.input. find_next_sibling(). find_next_sibling()['value']
        #print(value)
        payload['__VIEWSTATE']=value
        #print(response.url)
        response = s.post(response.url,headers=header,data=payload)
        #print(response.text)
        return response.text
    

    网页分析和上面第二步分析类似
    总结一下:分析请求方式post或者get->分析Form data 查看网页源代码查找所需数据是否存在-->提取所需数据(用解析库或者正则表达式)->构建Form data ->用对应的请求方式进行请求->得到所需要的网页源代码->提取数据->存储

    源代码

    如有帮助请帮忙点个星
    githubhttps://github.com/pythonFCG/Access-to-the-course-information

    7、效果图

    加上了easygui 并对excel进行了美化


    image.png

    image.png

    image.png

    image.png

    image.png

    相关文章

      网友评论

          本文标题:2018-03-02

          本文链接:https://www.haomeiwen.com/subject/vyxzxftx.html