以前专门搞java的,现在发现python相比于更加方便,python底层做了更多的工作。
用python爬取教务系统获取成绩课表等信息。过程中遇到的问题,怎么解决。现在做一个总结。
#encoding:utf-8
import tornado.ioloop
import tornado.web
from tornado.escape import json_decode
import edu #自己后台处理的python文件
#用来接收前端请求 并响应 json格式
class login(tornado.web.RequestHandler):
def get(self):
"""get请求"""
#前后端使用json
uid = self.get_body_argument('user')
pwd = self.get_body_argument('password')
openid = self.get_body_argument('openId')
week = self.get_body_argument('week')
result = edu.login(uid, pwd, openid, week)
respon_json = tornado.escape.json_encode(result)
self.write(respon_json)
def post(self):
print(self.request.body)
data = json_decode(self.request.body)
uid = data['user']
pwd = data['password']
openid = data['openId']
week = data['week']
result = edu.login(uid, pwd, openid, week)
respon_json = tornado.escape.json_encode(result)
self.write(respon_json)
#启动服务端 localhost:8888/edu/login
application = tornado.web.Application([(r"/edu/login", login)])
if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()#操作数据库相关的
获取一个连接
def getCur():
connect = pymysql.connect(
host='',
port=,
user='',
passwd=',
db='',
charset='utf8'
)
return connect
# # 使用 cursor() 方法创建一个游标对象 cursor
# cursor = connect.cursor()
#
# # 使用 execute() 方法执行 SQL 查询
# cursor.execute("SELECT VERSION()")
#
# # 使用 fetchone() 方法获取单条数据.
# data = cursor.fetchone()
#后端逻辑处理模块
#需要导入的模块
#https
import ssl
#可以处理表格的那种欣喜
import pandas as pd
from http import cookiejar
from urllib import request,parse
import urllib
import pymysql
#用于解析
from bs4 import BeautifulSoup
#请求
import requests
#可以用于处理pdf文件
import fitz
#多线程模块
import _thread
#这些url 打开chorme 调试着模式获取到相应的地址
eduURL = ""
loginURL = ""
scopeURL = ""
timetableURL = ""
#模拟登录测试模块 保存一个会话
#声明一个CookieJar对象实例来保存cookie
cookie = cookiejar.CookieJar()
#利用urllib.request库的HTTPCookieProcessor对象来创建cookie处理器,也就CookieHandler
handler=request.HTTPCookieProcessor(cookie)
#通过CookieHandler创建opener
opener = request.build_opener(handler)
#此处的open方法打开网页
# 不验证https 请求https时会验证ssl证书等
ssl._create_default_https_context = ssl._create_unverified_context# 登录方法
def login(username, password, openid, week):
print("登录中")
# 构造请求参数 post的方式
loging_data = parse.urlencode([
("j_username", username),
("j_password", password)
])
# 构造请求头
headers = {
"User-Agent": " Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Mobile Safari/537.36",
}
#发起请求
req = request.Request(url=loginURL,
data=loging_data.encode(encoding='utf-8'),
headers=headers)
try:
result = opener.open(req) # 访问请求的链接
soup = BeautifulSoup(result.read().decode('utf-8'), "html.parser")
#具体的成功页面自己判断 我这边失败的话 回调到登录页面 我验证下是否有form标签来判断是否成功
ans = soup.find_all("form")
if ans:
print("登录失败....")
return False
else:
print("登录成功....")
# 连接数据库
connect = getCur()
cur = connect.cursor()
selectSql = "select * from user where openid = '%s'"%(openid)
print(selectSql)
cur.execute(selectSql)
data = cur.fetchall()
if data:
print(data)
else:
sql = "insert into user(uid,pwd,openid) values('%s' ,'%s','%s')" % (username, password, openid)
print(sql)
cur.execute(sql)
print("插入数据成功")
#获取成绩 课表 异步化处理 减小响应时间
_thread.start_new_thread(getTimeTable, (week, username),)
_thread.start_new_thread(getCourse, (openid,))
connect.commit()
connect.close()
return True
except urllib.error.HTTPError:
print("connect failed")获取成绩(表格或者pdf形式) 获取课表(网页中是表格) 将网页中的数据获取并存储到数据库中
#获取课表
def getTimeTable(week, username):
try:
print("开始爬取课表")
timetableURL = ""
headers = {
"User-Agent": " Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Mobile Safari/537.36",
}
req = request.Request(url=timetableURL,
headers=headers)
result = opener.open(req) # 进入教务系统
#获取一个数据库的连接 实现在上面的代码中
con = getCur()
cur = con.cursor()
#读取获取的页面中的数据 并用pandas模块将表格提取出来
df = pd.read_html(result.read().decode('utf-8'))[0]
list = ["Mon", "Tue", "Wed", "Thu", "Fri","Sat"]
// 遍历 这块如果有什么不懂可以私聊我 一次探讨下
for index, row in df.iterrows():
for item in list:
if not (pd.isna(row[item])):
insertSql = "insert into timetable(course,weekday,period,week,username) values('%s','%s','%s','%s','%s')" % (row[item],
list.index(item)+1, index+1, week, username)
print(insertSql)
cur.execute(insertSql)
con.commit()
con.close()
print("爬取课表成功 并且存入数据库")
except urllib.error.HTTPError:
print("error")#获取成绩
def getCourse(openid):
try:
print("开始爬取成绩")
courseURL = ""
courseTime1=""
req = request.Request(url=courseURL,
headers=headers,
data=loging_data.encode(encoding='utf-8'))
# 因为我这个教务系统的成绩是pdf文件形式的 获取pdf文件流 将数据流写入到文件中注意是 wb b代表二进制的形式
result1 = opener.open(req1) # 进入教务系统
f = open("/root/workspace/pdf/course.pdf", 'wb')
block_sz = 8192
while True:
buffer = result1.read(block_sz)
if not buffer:
break
f.write(buffer)
doc = fitz.open('/root/workspace/pdf/course.pdf')
# 这一步就是将pdf文件解析成多张图片 你要从pdf文件中解析出对应的成绩不太容易,因为pdf中无法按照什么规则去解析 显示在前端可以用多张图片 图片就更容易 我是用nginx做图片服务器
for pg in range(doc.pageCount):
page = doc[pg]
rotate = int(0)
# 每个尺寸的缩放系数为2,这将为我们生成分辨率提高四倍的图像。
zoom_x = 3.0
zoom_y = 2.0
trans = fitz.Matrix(zoom_x, zoom_y).preRotate(rotate)
pm = page.getPixmap(matrix=trans, alpha=False)
pm.writePNG('/root/workspace/static/%s%s.png' % (openid, pg + 1))
except urllib.error.HTTPError:
print("error")分享自己写的python的启动脚本
#!/bin/sh
NAME=python
echo $NAME
ID=`ps -ef | grep "$NAME" | grep -v "$0" | grep -v "grep" | awk '{print $2}'`
echo $ID
echo "---------------"
for id in $ID
do
kill -9 $id
echo "killed $id"
done
echo "---------------"
#! kill之前的python程序 重新启动后台程序 启动对应的程序 输出日志到这个文件中
nohup python3 -u server.py > /root/workspace/edu/out.log 2>&1 &
echo "启动成功"
















