chapter12-实战成绩通知短信系统(下)

注意!成绩短息通知服务的源码共分为两种:第一种为线性的程序,逻辑简单,但是格式杂乱;第二种为以类作为基础,封装了各种函数,逻辑较为复杂,但是格式清晰。建议新手先学习第一种代码风格,了解代码逻辑后,尝试自己完成第二种开发
上节课,我们成功的登录了某方的教务系统,同时已经得到了我们想要获取的成绩页面。这节课,我们将首先提取成绩页面中的有效信息,然后将相关信息保存至数据库中,最后,使用短信接口发送成绩通知。相关的代码,你仍然可以在本课程对应的Github页面获取,欢迎各位同学在讨论区进行讨论!

提取信息

首先让我们分析一下成绩页面的HTML格式:

学年学期课程代码课程名称课程性质课程归属学分绩点成绩辅修标记补考成绩重修成绩学院名称备注重修标记
2016-201721310040ASP.NET应用开发1专业选修课 3.51.9690 计算机与软件工程学院 0
2016-201722011536形势与政策Ⅵ通识必修课 0.03.5良好0 马克思主义学院 0

从上面的HTML源码中,我们可以清晰的看到,所有的信息都存在于id为Datagrid1的表格中。因此,我们首先要提取Datagrid1表格中的所有tr

soup = BeautifulSoup(score_text.content, "lxml",from_encoding="gb18030")
trs = soup.find(id="Datagrid1").findAll("tr")

上述代码和我们之前遇到的用法不太一样,因此我们要详细说明一下上述代码中的相应参数:

soup = BeautifulSoup(score_text.content, "lxml",from_encoding="gb18030")

首先是score_text.content,在以前的开发中,我们使用的是text方式获取网页信息,这里我们使用了’content’方式的原因是,某方返回的数据是gb2312格式的内容,因此我们需要直接用二进制的方式来传递内容,同时,我们也通过from_encoding来进一步的向BeautifulSoup说明我们的原始参数。
接下来我们要解析tr中的所有数据:

Grades = []
for tr in trs:
    tds = tr.findAll("td")
    tds = tds[:2] + tds[3:5] + tds[6:9]
    oneGradeKeys = ["year", "term", "name", "type", "credit","gradePonit","grade"]
    oneGradeValues = []
    for td in tds:
        oneGradeValues.append(td.string)
    oneGrade = dict((key, value) for key, value in zip(oneGradeKeys, oneGradeValues))
    Grades.append(oneGrade)

上述代码中,我们遍历了所有tr中的td内容。需要指出的是,我们获取成绩,仅仅需要成绩所对应的年份学期,课程名,课程性质,学分,绩点,成绩。因此在获取到td中的数据库后,我们需要剔除一些无用的数据。具体的,原始数据为:

[2016-2017, 2, 1310040, ASP.NET应用开发1, 专业选修课,  , 3.5, 3.7, 87, 0,  ,  , 计算机与软件工程学院,  , 0]

整理后的数据为:

[2016-2017, 2, ASP.NET应用开发1, 专业选修课, 3.5, 3.7, 87]

接下来,让我们打印一下我们的成果

注意:因为传递的内容编码为gb2312格式,因此我们需要定义python程序的默认格式

# coding=gbk
for score in Grades:
    year = score["year"]
    term = score["term"]
    gradepoint = score["gradePonit"]
    grade = score['grade']
    print(gradepoint,end='\t')
    print(grade,end='\t')
    name = score["name"]
    print(name)

chapter12-实战成绩通知短信系统(下)_第1张图片

Bingo!我们已经获取到了相关的成绩信息!接下来让我们将数据存入数据库中

保存数据到数据库

因为数据库的操作,我们在之前的章节中就已经学习过,因此本文直接给出对应的代码。

  1. 创建数据表
CREATE TABLE SCORE(
id INT AUTO_INCREMENT PRIMARY KEY,
year_ varchar(12),
term_ VARCHAR(12),
name_ VARCHAR(12),
type_ VARCHAR(10),
credit_ VARCHAR(10),
gradePoint_ VARCHAR(10),
grade_ VARCHAR(10)
)ENGINE=INNODB;
  1. 在Python操作数据库
import pymysql
db = pymysql.connect("localhost","root","654321","mysql" )
cursor = db.cursor()
def insert_info(year, term, name, type, credit,gradePonit,grade):
 sql = "INSERT INTO score(year_, term_, name_, type_, credit_,gradePoint_,grade_) VALUES('"+str(year)+"','"+str(term)+"','"+str(name)+"','"+str(type)+"','"+str(credit)+"','"+str(gradePonit)+"','"+str(grade)+"')"
 print(sql)
 cursor.execute(sql)
 db.commit()

####判别是否发送短信
3. 从数据库中判断
为了精确的发送短信,我们在获取到信息之后,从数据库中查询是否存在对应的课程名称,如果存在,则不发送;如果数据库中不存在该门课程的信息,则发送短息:

 int result = select_info(name)
 if result!=0:
     time.sleep(60*60)
 else:
     send_mail(year,term,name,type,credit,gradePoint,grade)
  1. 从数组中判断
    从数据库中获取信息,经过数据库连接、数据库关闭等操作,不仅浪费了时间,而且还消耗了大量的系统资源。因此,我们可以定义一个全局变量,将相关信息保存在变量中。判断新的课程是否存在变量中:
juage=[]
if name not in juage:
 send_mail(year, term, name, type, credit, gradePoint, grade)
 juage.append(name)
else:
 print("已经存在,不发送短信")

####发送短信
发送短息我们已经学习了很多的方法。因此本文并不指定大家选择哪个方法。课题提供的代码中,使用的是通过139信箱发送短信,大家可以使用其他的方法进行操作。
####系统说明
5. 为了保证该系统全天为我们服务,我们可以将主函数一直运行,每次运行后使用time.sleep()函数,使服务休眠1小时或者你指定的时间;
6. 因为验证码目前需要手动输入,因此建议使用Windows服务器配置环境。(后续将会提供自动识别验证码服务,大家以后可以迁移至Linux服务中)

系统测试

在运行之前,请确你已经配置好下面的参数:

  • 用户名

  • 用户密码

  • 教务网地址

  • 教务网验证码地址

  • 查询成绩地址

  • 数据库连接相关信息

  • 邮件发送的相关信息
    配置好上述参数的信息后,你的手机肯定会收到这样一条短信:
    chapter12-实战成绩通知短信系统(下)_第2张图片

    没错!你已经完成了成绩通短信通知服务!那么,为什么不参考之前文章中的知识,让它在云服务器中为你服务呢?

    总结
  1. 本文存在着大量的编码转化、数据存储操作。希望大家有问题一定要去讨论区进行讨论,我会第一时间为大家解答;
  2. 还是要提醒大家:项目需要配置的信息很多,希望同学们能够静下心来,耐心的跟着文章学习;
  3. 自动识别验证码目前的准确率已经达到了90%,我将会尽快更新相关代码。可能你看到这篇文章的时候,就不需要人工识别验证码了。

你可能感兴趣的:(Python,爬虫从入门到精通,python,爬虫,后端,实战,beautifulsoup)