最近在学习爬虫,看了一些入门的教程,也找了一些别人的案例自己跟着做了一下,但还是觉得不过瘾,想自己做出个东西来。正好一天在查学术章的时候,我有了想法--何不利用爬虫技术做一个查询学术章的软件?于是就开始了这个软件的制作。现在它已经在我的桌面上了(下图是它的样子),每次查学术章的时候只要双击一下它就会告诉我最近有没有新的学术章“到账”,一共刷了几次。本文就介绍该软件的制作过程。
首先,得介绍一下什么是学术章。学术章由每次听讲座前后刷学生卡获得,我们上海大学研究生的毕业要求之一:在研究生期间学硕得刷满30个学术章,专硕要刷满25个学术章。这个硬性指标必须要完成,所以每周如果有时间,哪里有可以刷学术章的讲座是肯定要去刷的。可以登录上海大学会议签到系统(http://qd.shu.edu.cn/),在“参会信息”中查看自己实际刷到了几次学术章。
可以看到参会信息存储在一张表格里面,爬取出表格里的所有信息即可。但直接爬取肯定是不行的,因为先要进行登陆。
该系统的登陆地址为http://qd.shu.edu.cn/Account/LogOn,界面如下图所示,要求填入学号和密码。
绝大多数网站都是利用cookie技术来实现用户登陆的,cookie相当于服务器发给用户具有标识作用的通行证,所以得先获得cookie。在填入学号和密码之后,网站会返回一个cookie。先查看登陆后提交到网站的数据,在LogOn页面的Form Data下可看到,提交的数据就是我的学号和密码,以及是否保存账号(可以忽略)。
用以下代码实现登陆过程。
s=requests.session()
loginurl = 'http://qd.shu.edu.cn/Account/LogOn'
postdata = {
'UserName': '*****',
'Password': '*****',
}
s = requests.session()
s.post(loginurl, postdata)
c = requests.cookies.RequestsCookieJar() # 利用RequestsCookieJar获取cookies
s.cookies.update(c)
先创建一个会话(session),接着使用post方法在登陆页面提交自己的学号密码,利用RequestsCookieJar获取cookie,最后将获得的cookie传入s.cookies.update()方法中就实现登陆了。
接着就可以转到“参会信息”页面http://qd.shu.edu.cn/Attendance/MyIndex,进入下一步的信息提取工作。
参会信息的提取比较简单,因为所有信息都存在一张表格里,只需找出table标签下所有td标签里的信息,代码如下。
html= s.get('http://qd.shu.edu.cn/Attendance/MyIndex',headers=headers,timeout=5).text
bs = BeautifulSoup(html,"lxml")
table=bs.find('table').find_all('td')
然后对提取到的信息进行处理。
info=[]
for t in table:
s=t.text.strip()
if s:
info.append(s)
conference=[]
for i in range(len(info)//3):
if info[i*3]=='系统测试(不算入学术章)':
continue
con={}
con['会议名称']=info[i*3]
con['会议时间']=info[i*3+1]
con['会议地点'] = info[i * 3 +2]
conference.append(con)
这里将系统测试那一次的信息去掉,最后得到的是一个列表,列表里的每一个元素都是包含会议名称,会议时间以及会议地点的字典。
我的目标是想每次运行该软件得到最新的学术章信息,我的实现思路是每次运行程序时将得到的信息存在文件中,下次运行时将爬取的信息与之前存的信息比较就可以得到最新的学术章信息。
def save_info(conference):
with open(r'D:\Users\yh951\con_info.txt','w') as f:
f.write(str(conference))
sava_info()函数直接将爬取的信息以字符串形式存入.txt文件。
def check_new(conference):
with open(r'D:\Users\yh951\con_info.txt','r') as f:
conference_old=eval(f.read())
new_info=[con for con in conference if con not in conference_old]
if new_info:
print('{}条新消息'.format(len(new_info)))
for con in new_info:
print('会议名称:', con['会议名称'])
print('会议时间:', con['会议时间'])
print('会议地点:', con['会议地点'])
print('-' * 30)
save_info(conference)
else:
print('没有最新信息')
print('已刷{}次学术章'.format(len(conference)))
check_new()函数中,使用eval()方法还原上次的信息(字典的列表),与当前信息做比对,即可知道新的参会信息,接着打印出新信息和已经刷的学术章的次数。注意,在有新的参会信息情况下要将新的参会信息保存,以做到同步更新。
以下是完整的代码:
import requests
from bs4 import BeautifulSoup
info_save_path="D:/Users/yh951/"
def get_info():
loginurl = 'http://qd.shu.edu.cn/Account/LogOn'
postdata = {
'UserName': '*****',
'Password': '*****',
}
headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/'
'537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36'}
s = requests.session()
s.post(loginurl, postdata)
c = requests.cookies.RequestsCookieJar() # 利用RequestsCookieJar获取cookies
s.cookies.update(c)
html= s.get('http://qd.shu.edu.cn/Attendance/MyIndex',headers=headers,timeout=5).text
bs = BeautifulSoup(html,"lxml")
table=bs.find('table').find_all('td')
info=[]
for t in table:
s=t.text.strip()
if s:
info.append(s)
conference=[]
for i in range(len(info)//3):
if info[i*3]=='系统测试(不算入学术章)':
continue
con={}
con['会议名称']=info[i*3]
con['会议时间']=info[i*3+1]
con['会议地点'] = info[i * 3 +2]
conference.append(con)
return conference
def save_info(conference):
with open(info_save_path+'con_info.txt','w') as f:
f.write(str(conference))
def check_new(conference):
try:
with open(info_save_path+'con_info.txt','r') as f:
conference_old=eval(f.read())
except:
with open(info_save_path+'con_info.txt','w') as f:
f.write("[]")
conference_old=[]
new_info=[con for con in conference if con not in conference_old]
if new_info:
print('{}条新消息'.format(len(new_info)))
for con in new_info:
print('会议名称:', con['会议名称'])
print('会议时间:', con['会议时间'])
print('会议地点:', con['会议地点'])
print('-' * 30)
save_info(conference)
else:
print('没有最新信息')
print('已刷{}次学术章'.format(len(conference)))
print("\n历史信息:")
if conference_old:
for con in conference_old:
print('会议名称:', con['会议名称'])
print('会议时间:', con['会议时间'])
print('会议地点:', con['会议地点'])
print('-' * 30)
else:
print("没有历史信息")
if __name__ == '__main__':
try:
conference=get_info()
check_new(conference)
except requests.exceptions.Timeout:
print('相应超时。请连接校园网后重试')
input()
最后,为了方便,将.py程序打包成一个独立的.exe文件。要实现该操作需要先在python中安装pyinstaller和pywin32两个包,具体细节请参考https://blog.csdn.net/qq_35203425/article/details/78568141。在cmd中输入pyinstaller -F xxx.py 就可以得到.exe文件了,就是本文第一幅图的样子。
至此,大功告成,成功开发出自己的第一个软件,还是挺开心的。它不仅是我最近的学习成果,而且非常实用,至少还会用两年吧。再次感受到爬虫的强大,接下来要继续学习利用爬虫,使它成为学习生活中的帮手,争取做出更多有意义的项目与大家分享交流。