高级技巧¶
这一部分提供了使用 hfut 的一些高级技巧.
注解
例子仅作为学习的参考或者为你的使用提供思路, 我只能确保在自己的环境下能够正常工作. 如果你想提供修改意见或者添加例子可以 在 GitHub 上提交 Issue 或者直接提交 Pull Request.
使用 hfut 下载全校学生证件照¶
# -*- coding:utf-8 -*-
"""
抓取全校学生的照片
"""
from __future__ import unicode_literals
import logging
import os
import sys
import threading
import requests
import six
from hfut import Guest, XC, HF
from hfut.util import cal_term_code
# 文件保存路径
DIR_NAME = 'img'
# 起始年份
START_YEAR = 2012
# 结束年份
END_YEAR = 2015
# 校区
campus = XC
# 所有人都上的课程 # 军事训练
if campus == HF:
COURSE_CODE = '52000020'
else:
COURSE_CODE = '5200023B'
# 设置日志
logger = logging.Logger('hfut_img', level=logging.WARNING)
sh = logging.StreamHandler()
fh = logging.FileHandler('hfut_img.log', encoding='utf-8')
fmt = logging.Formatter('%(threadName)s %(levelname)s %(lineno)s行: - %(asctime)s\n\t %(message)s', '%d %H:%M')
sh.setFormatter(fmt)
fh.setFormatter(fmt)
logger.addHandler(sh)
logger.addHandler(fh)
logger.setLevel(logging.INFO)
# 初始化 session
shortcuts = Guest(campus)
# 初始化文件夹
def setup_dir():
if not os.path.isdir(DIR_NAME):
os.mkdir(DIR_NAME)
logger.info('成功创建目录 {}'.format(DIR_NAME))
for i in range(START_YEAR, END_YEAR + 1):
path = os.path.join(DIR_NAME, six.text_type(i))
if not os.path.isdir(path):
os.mkdir(path)
logger.info('成功创建目录 {}'.format(path))
# 下载照片
def fetch_img(term_code):
file_suffix = '.jpg'
stu_sum = 0
success_sum = 0
fail_sum = 0
error_sum = 0
exist_sum = 0
# 获取该学期的所有教学班
klass = shortcuts.search_course(term_code, COURSE_CODE)
if klass:
logger.info('{} 学期共有 {} 个教学班'.format(term_code, len(klass)))
for k in klass:
# 获取教学班学生
class_stus = shortcuts.get_class_students(term_code, COURSE_CODE, k['教学班号'])
if class_stus is None:
logger.critical('没有获取到 {} 学期的教学班'.format(term_code))
sys.exit(0)
stu_num = len(class_stus['学生'])
logger.info('{} 班共有 {} 名学生'.format(class_stus['班级名称'], stu_num))
stu_sum += stu_num
for stu in class_stus['学生']:
year = str(stu['学号'] // 1000000)
code = str(stu['学号'])
img_url = six.moves.urllib.parse.urljoin(shortcuts.session.host, ''.join(
['student/photo/', year, '/', code, file_suffix]))
sex = '男'
stu_name = stu['姓名']
if stu['姓名'].endswith('*'):
sex = '女'
stu_name = stu_name[:-1]
full_name = ''.join([code, '-', sex, '-', stu_name])
filename = os.path.join(DIR_NAME, year, ''.join([full_name, file_suffix]))
if os.path.isfile(filename):
logger.warning('{} 的照片已下载过'.format(full_name))
exist_sum += 1
continue
try:
res = requests.get(img_url)
if res.status_code == 200:
with open(filename, 'wb') as fp:
fp.write(res.content)
logger.info('下载 {} 的照片成功'.format(full_name))
success_sum += 1
elif res.status_code == 404:
logger.warning('下载 {} 的照片失败'.format(full_name))
fail_sum += 1
except Exception as e:
logger.error('下载 {} 的照片出错\n\t{}'.format(full_name, e))
error_sum += 1
logger.info('{} 学期共有 {} 名学生'.format(term_code, stu_sum))
logger.info('{} 学期下载完成,成功 {},失败 {},错误 {}, 已存在 {}'.format(
term_code, success_sum, fail_sum, error_sum, exist_sum))
else:
logger.critical('没有获取到第 {} 的教学班级'.format(term_code))
sys.exit(0)
if __name__ == '__main__':
setup_dir()
for year in range(START_YEAR, END_YEAR + 1):
term_code = cal_term_code(year)
t = threading.Thread(target=fetch_img, name=year, args=(term_code,))
t.start()
在全平台使用 hfut 编写课表工具¶
# -*- coding:utf-8 -*-
# qpy:webapp
# qpy://127.0.0.1:8080
"""
使用 bottle 编写的一个简单课表查看页面, 可以筛选每周的课程, 可以在手机上安装 qpython 并安装好依赖后在手机上运行
"""
from bottle import Bottle, template
import hfut
index_tpl = """
<!DOCTYPE html>
<html lang="cn">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="initial-scale=1.0">
<title>第{{week}}周课表</title>
<style>
table{margin: 0 auto;border-collapse:collapse;}
table, th, td{border: 1px solid;}
thead{background-color: #EFC363;}
tbody{background-color: #D6D3CE;}
caption{margin-bottom:0.5em;}
.index-td{text-align:center}
</style>
</head>
<body onload="document.getElementById('opt_' + '{{week}}').selected = true">
<table>
<caption>
<select id="week" onchange="window.location=document.getElementById('week').value">
%for i in range(start, end+1):
<option id="opt_{{i}}" value="{{i}}">
第{{i}}周
</option>
%end
</select>
</caption>
<thead>
<tr>
<th></th>
<th>周一</th>
<th>周二</th>
<th>周三</th>
<th>周四</th>
<th>周五</th>
<th>周六</th>
<th>周日</th>
</tr>
</thead>
<tbody>
%for i in range(11):
<tr>
<td class="index-td">{{i+1}}</td>
%for j in range(7):
%if curriculum[j][i]:
<td>
%for c in curriculum[j][i]:
{{c[u'课程名称']}}:{{c[u'课程地点']}}/
%end
</td>
%else:
<td></td>
%end
%end
</tr>
%end
</tbody>
</table>
</body>
</html>
"""
app = Bottle()
session = hfut.Student('你的学号', '密码', '校区')
curriculum = session.get_my_curriculum()
start = curriculum[u'起始周']
end = curriculum[u'结束周']
filtered = [None] * (end - start + 1)
@app.route('/')
@app.route('/<week:int>')
def index(week=1):
idx = week - 1
filtered[idx] = filtered[idx] or hfut.util.filter_curriculum(curriculum[u'课表'], week)
return template(index_tpl, curriculum=filtered[idx], week=week, start=start, end=end)
if __name__ == '__main__':
app.run(host='localhost', port=8080, debug=True)
将课表导出为日历文件¶
# -*- coding:utf-8 -*-
"""
将课表导出为日历文件
"""
from __future__ import unicode_literals
from datetime import datetime
import icalendar
import hfut
def schedule2calendar(schedule, name='课表', using_todo=True):
"""
将上课时间表转换为 icalendar
:param schedule: 上课时间表
:param name: 日历名称
:param using_todo: 使用 ``icalendar.Todo`` 而不是 ``icalendar.Event`` 作为活动类
:return: icalendar.Calendar()
"""
# https://zh.wikipedia.org/wiki/ICalendar
# http://icalendar.readthedocs.io/en/latest
# https://tools.ietf.org/html/rfc5545
cal = icalendar.Calendar()
cal.add('X-WR-TIMEZONE', 'Asia/Shanghai')
cal.add('X-WR-CALNAME', name)
cls = icalendar.Todo if using_todo else icalendar.Event
for week, start, end, data in schedule:
# "事件"组件更具通用性, Google 日历不支持"待办"组件
item = cls(
SUMMARY='第{:02d}周-{}'.format(week, data),
DTSTART=icalendar.vDatetime(start),
DTEND=icalendar.vDatetime(end),
DESCRIPTION='起始于 {}, 结束于 {}'.format(start.strftime('%H:%M'), end.strftime('%H:%M'))
)
now = datetime.now()
# 这个状态"事件"组件是没有的, 对于待办列表类应用有作用
# https://tools.ietf.org/html/rfc5545#section-3.2.12
if using_todo:
if start < now < end:
item.add('STATUS', 'IN-PROCESS')
elif now > end:
item.add('STATUS', 'COMPLETED')
cal.add_component(item)
return cal
if __name__ == '__main__':
session = hfut.Student('你的学号', '密码', '校区')
curriculum = session.get_my_curriculum()
first_day = datetime(2016, 8, 29)
schedule = hfut.util.curriculum2schedule(curriculum['课表'], first_day, compress=True)
print(len(hfut.util.curriculum2schedule(curriculum['课表'], first_day)), len(schedule))
cal = schedule2calendar(schedule)
with open('curriculum.ics', 'wb') as fp:
fp.write(cal.to_ical())