jfinal获取url链接上面传来的string类型的值_Python爬虫案例——正方教务学生成绩获取(自动识别验证码)...

91881dabe3d592763b81163bbc6087ff.png

刚刚进入假期,学校开放了期末成绩查询,奈何正方教务的各种卡顿。很多学弟学妹问有没有好办法能够解决,闲来无事写了一段自动获取的爬虫程序练练手。

环境

  • Python3.7
  • Jupyter

主要库

  • requests
  • BeautifulSoup
  • PIL
  • pandas

be71c82242d148dc83c4ad2dcc53b6b1.png
老气的登录界面...

一、分析及获取登录提交数据

首先观察网页,由于这个地方比较简单,我们就使用Chrome的开发者工具中的Network抓包。

88bdea8318dae9c13d2bbfb3cb198cb4.png

把css 图片之类的过滤掉,发现了包含学号、密码等内容的表单被提交到default2.aspx

335b7ff655659488364fc6bbb94030ce.png

分析POST过去的字段

86c674908703077ad90e09294a5addc9.png

总共提交了9个参数(因学校而异,不过关键字段都差不多),其中txtUserName是学号、TextBox2是密码、RadioButtonList1是学生选项(登录身份选项),还有个txtSecretCode是验证码。

除了这些常规数据外,我发现还有__VIEWSTATE这种特殊字段,这里做一个简要介绍。

__VIEWSTATE:
ViewState是 http:// ASP.NET 中用来保存WEB控件回传时状态值一种机制。在WEB窗体(FORM)的设置为runat="server",这个窗体(FORM)会被附加一个隐藏的属性_VIEWSTATE。_VIEWSTATE中存放了所有控件在ViewState中的状态值。
ViewState是类Control中的一个域,其他所有控件通过继承Control来获得了ViewState功能。它的类型是system.Web.UI.StateBag,一个名称/值的对象集合。
当请求某个页面时, http:// ASP.NET 把所有控件的状态序列化成一个字符串,然后做为窗体的隐藏属性送到客户端。当客户端把页面回传时, http:// ASP.NET 分析回传的窗体属性,并赋给控件对应的值。

现在我们知道这个字段肯定是不可缺少的,那么它们可以从哪获取到呢?

我们右键查看网页的源代码,在源代码中发现了type为hidden的输入框,它们的值正是我们所需要的

751e600094e2f85bdcaebde9025733e4.png

在这个地方,我们可以构造一个login_info字段作为登录数据:

    # post的登录数据
    login_info = {
        "__VIEWSTATE": viewState,
        "txtUserName": user, 
        "TextBox2": pwd,
        "txtSecretCode": checkCode,
        "RadioButtonList1": "%D1%A7%C9%FA",#学生选项
        "Button1": "",
        "lbLanguage": ""
    }

对于值的获取这里采用BeautifulSoup这个库来解析

re 

这样我们就获得了能够提交的数据字段,可以进行登录操作了,验证码部分我们在后面单独介绍。

二、学生个人成绩信息获取

我们将获取好的字段作为登录数据提交至http://******/default2.a0spx,这里中间是每个学校有所不同,需要进行修改。

头部部分构建

5f0476c5b6feec954b9e2888b5bb8123.png
#头部部分构建
header = {
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
    "Accept-Encoding": "gzip, deflate",
    "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
    "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36",
    "Referer": "http://218.56.144.61/",
    "Host": "218.56.144.61",
    "Cache-Control": "max-age=0"
}

现在我们可以获取到学生个人页面的html信息

    req = requests.session().post(url='http://******/default2.a0spx', data=data, headers=header)
    geren_html = req.text
    #print(geren_html)

用简单的正则写了一个欢迎语来表示登录成功(常规骚操作)

        z_name = re.compile('<span id="xhxm">(.*?)</span></em>',re.S)
        name = re.findall(z_name,geren_html)
        print('登录成功!'+name[0],'欢迎您')

672e858d477207f50f1be4e78450a4df.png

之后观察个人成绩这个位置的源码和抓取的包

a764b1cdbf2a69aa3c1c511af6dfc841.png

d8b39d79dfb7302b088a4f855efe6728.png

这里虽然有链接但是如果用header的话...

bc8d769f7e33087572cbaf2ae84e5e32.png

就会这样,所以我们还是老老实实一步步来。

还是先分析包

531798675016aecb8a6492120b214aa1.png

我们可以直接找到成绩查询的url:http://*******/xscjcx.aspx?xh=xxxxxx&xm=xxx&gnmkdm=N121605

此URL中xh是学号,xm是经过URL编码的学生姓名。

f283f07bc1b6ac6ced4859a65cdf2747.png

后面我们要做的和前面所讲的差不多,首先要通过GET方法获取页面源代码,从中取得__VIEWSTATE的值,然后再次POST过去。

    data={
        'btn_zcj':'%C0%FA%C4%EA%B3%C9%BC%A8',#学年成绩:btn_xn 历年成绩:btn_zcj
        'ddlXN':'',
        'ddlXQ':'',
        '__EVENTVALIDATION': '',
        '__EVENTTARGET':'',   
        '__EVENTARGUMENT' :'',
        '__VIEWSTATE':'',
        'hidLanguage':'',
        'ddl_kcxz':'',
    }
    
    #生成绩页面获取关键字段
    cj_html_1=S.get('http://*****/xscjcx.aspx?xh='+xh+'&xm='+xm+'&gnmkdm=N121605',headers=header)
    soup=BeautifulSoup(cj_html_1.text,'lxml')
    #print(soup)
    value3=soup.find('input', attrs={'name': '__VIEWSTATE'})['value']
    data['__VIEWSTATE']=value3
    
    cj_html_2 = S.post('http://218.56.144.61/xscjcx.aspx?xh='+xh+'&xm='+xm+'&gnmkdm=N121605',data=data,headers=header)
    #print (cj_html_2.text)

我们就获取到了包含学生的个人成绩信息的网页源码

8a673c90186b8e75f88bf5b20074ee35.png

之后进行简单的清洗和处理就OK,这部分是一个见仁见智的问题,我们就不展开说明了。

处理之后进行下步分析或者直接导出都没问题

a92b036b20cc1d6ba06af0e707b0f915.png

7dfca5df59f17c21c0ca78f869e4adb9.png

在使用爬虫访问的时候记得一定要留一点余地

import time
time.sleep(1)

毕竟就算着急也尽量不要给别人添麻烦嘛~

三、验证码自动处理

验证码自动识别这一块,第三方的pytesseract库很方便,但是识别率感人。

import pytesseract
from PIL import Image
image = Image.open('vcode.png')
vcode = pytesseract.image_to_string(image)
print (vcode)

因此我们使用百度提供的文字识别api

此处特别感谢本专业一位学长的提醒、指导以及提供的部分源码。

具体实现方式参考

python调用百度通用文字识别接口进行验证码识别 - IT技术讨论 - CSDN博客

在进行识别前要先对图片进行预处理,提高识别效率。

二值化

# 二值化算法
def binarizing(img,threshold):
    pixdata = img.load()
    w, h = img.size
    for y in range(h):
        for x in range(w):
            if pixdata[x, y] < threshold:
                pixdata[x, y] = 0
            else:
                pixdata[x, y] = 255
    return img

转化为灰度图

    # 转化为灰度图
    image = image.convert('L')

去线

# 去除干扰线算法
def depoint(img):   #input: gray image
    pixdata = img.load()
    w,h = img.size
    for y in range(1,h-1):
        for x in range(1,w-1):
            count = 0
            if pixdata[x,y-1] > 245:
                count = count + 1
            if pixdata[x,y+1] > 245:
                count = count + 1
            if pixdata[x-1,y] > 245:
                count = count + 1
            if pixdata[x+1,y] > 245:
                count = count + 1
            if count > 2:
                pixdata[x,y] = 255
    return img

处理完毕后使用接口即可获得准确率较高一些的识别结果

7ad82df33eff6b8a1734cc4957346f95.png

总结

1、由于已经过了查询成绩的高峰期,因此没能进行登录崩溃的情况测试。具体思路大概是提取崩溃提示页面中的关键词然后返回进行继续访问。

2、由于时间有限,验证码识别方面仅仅考虑了便捷性。在后期可以考虑使用有监督的学习方式训练一个自己的模型。

3、本案例只是一个小实验,之后进行小规模的调整即可完成抢课等更多元的功能。

最后,

爬虫有风险,使用需谨慎~

以上

有帮助的话点个赞再走吧~

完整源码Github地址:

Vinne6/zfjw_pro​github.com
3cf309b5312f2b62ff41cc4c9ced960b.png

相关引用:

用 Python 实现模拟登录正方教务系统抢课​blog.csdn.net Python模拟登陆正方教务系统并抓取成绩单 - lovealways - 博客园​www.cnblogs.com
6f9201f7c715e5ffeb4b9b9f172fdbdd.png
利用Python获取正方教务系统在校成绩 - mgsky1的博客 - CSDN博客​blog.csdn.net
4c092c07986faff13301ec3d3ec0b349.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值