Skip to content

多设备同步订阅课程表,适用于iOS与Android

关键词:iCloud日历同步,RFC 2445,iCalendar,Outlook,GMail

摘要 🔑

知识准备

  • RFC 2445标准:1998由微软公司发布的标准的互联网日历标准,让用户能够在各种计算机和各种程序之间创建和共享电子日历。
  • iCloud同步:在多台支持iCloud的Apple设备中,只需在任意一个设备中进行某项设置或工作内容,其他设备均可同步得到此项设置或工作内容。
  • ics文件:后缀为ics的文件,是RFC 2445标准下的日历文件,使用此文件可以直接向日历中添加日程时间表。
  • 订阅:在不打开某项链接的前提下,自动获取此链接的最新内容。

前提 🚩

​ 本文均以iOS为例说明,目前,所有流行日历工具比如:Lotus Notes、Outlook、GMail 和 Apple 的 iCal 都支持RFC 2445标准,故Android也适用。

​ 在过去的两年,博主在每学期初一直坚持将自己的课程表手动输入到自己的iCloud日历中,通过iCloud提供的多设备同步,可以做到MacBook、iPad、iPhone、Apple Watch都有课程表信息,利用iOS提供的小组件以及Apple Watch的先天便捷性,可以非常方便地了解到自己当天及本周甚至本学期的所有课程名称,时间,上课地点及任课教师。

​ 但是上述做法有如下已知缺点:

  • 课程不会自动更新:每逢节假日调休,需手动调整课程表
  • 课表错误率高:手动输入极大可能会导致人工错误,检查过程繁琐
  • 每个学期均需手动录入一次课程信息:过程繁琐

​ 于是,在上学期期末复习时突发奇想,有了如下想法。

想法💡

使用爬虫获取课程表信息,生成ics文件,产生此ics文件订阅,使用MacBook订阅日历地址。爬虫定期爬取课程表,更新ics文件。

可行性验证 ⚖️

  • 爬虫可用性:此项因学校而异,需要自己去尝试。本人尝试成功,不再赘述。
  • ics文件生成:博主用MacBook导出了自己已有的日历日程后用文本编辑打开了此ics文件,结合RFC 2445标准与网上现有博客得知,可行。
  • 生成ics订阅:博主在网络上查了一下,未查到ics订阅生成方法。于是自己随便找了一个已有的订阅地址,发现地址路径末尾为ics文件名,猜测是ics文件下载地址,将此地址放入浏览器中,回车直接下载到了此ics日历文件,得知可行。
  • 爬虫定期爬取:学校教务处不更新,就一直能行。

如果读者想要实现如上步骤,另需满足如下前置要求:

  • 一台拥有固定IP的服务器
  • Python的基本阅读调试技能

想法验证可行,开始实现想法。

想法实现 🔨

爬虫编写

注:此过程因学校而异,本人就不放出此爬虫的Python代码,只给出用于后续步骤的数据样本使步骤连贯。

数据样本下载

ics文件生成

经过观察学习,ics文件的格式模版如下所示:

# -*- coding: UTF-8 -*- 
BEGIN:VCALENDAR
# 下面是一个日程
BEGIN:VEVENT
CREATED:20191203T142408Z
UID:20200831T10250020200831T12000024231812
DTEND;TZID=Asia/Shanghai:20200831T120000 #日程结束时间
TRANSP:OPAQUE
X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC
SUMMARY:标题
LAST-MODIFIED:20191227T060829Z
DTSTAMP:20191203T142417Z
DTSTART;TZID=Asia/Shanghai:20200831T102500 #日程开始时间
LOCATION:地点
DESCRIPTION:备注
SEQUENCE:0
END:VEVENT
# 上面是一个日程
# 顺序排列多个日程
END:VCALENDAR

上述中文内容已经把一个日程在存在形式描述清楚,未描述的可以先不理会,不影响最终的使用效果。

编写Python代码:

python
import random

# 创建日历文件
def createCalender(filename, data):
    file = open(filename + ".ics", "a")
    file.write("# -*- coding: UTF-8 -*- 
BEGIN:VCALENDAR
")
    file.close()
    for w in data:
        data1 = w['classes']
        for d in data1['classes']:
            for c in d.values():
                for course in c:
                    createCourse(course, filename + ".ics", data1['weekdays'])
    file = open(filename + ".ics", "a")
    file.write("END:VCALENDAR")
    file.close()
# 为每个课程创建对应的日历信息
def createCourse(course, file_name, weekdays):
    courseDay = weekdays[course['weekday'] - 1].replace('-', '') + 'T'
    courseTime = course['course_time'].split('~')
    startTime = courseDay + courseTime[0].replace(':', '') + '00'
    endTime = courseDay + courseTime[1].replace(':', '') + '00'
    uid = startTime + endTime + str(course['credit']) + str(random.randint(0, 9999999))
    coursename = course['course_name']
    location = course['location'] + ' ' + course['teacher']
    description = '课程号:' + course['course_id'] + '\n' + '学分:' + str(course['credit'])
    file = open(file_name, "a")
    file.write("BEGIN:VEVENT
CREATED:20191203T142408Z
")
    file.write('UID:{}
'.format(uid))
    file.write("DTEND;TZID=Asia/Shanghai:{}
".format(endTime))
    file.write("TRANSP:OPAQUE
X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC
")
    file.write("SUMMARY:{}
".format(coursename))
    file.write("LAST-MODIFIED:20191227T060829Z
DTSTAMP:20191203T142417Z
")
    file.write("DTSTART;TZID=Asia/Shanghai:{}
".format(startTime))
    file.write("LOCATION:{}
".format(location))
    file.write("DESCRIPTION:{}
".format(description))
    file.write("SEQUENCE:0
END:VEVENT
")
    file.close()
if __name__ == '__main__':
		createCalender("course.ics", data) #data使用上面的数据样本,使用eval()转换为dict

运行此代码,可以得到course.ics文件。

生成ics日历订阅

由上文分析,生成ics日历订阅也就等价于生成ics文件的下载链接,博主使用的是Nginx,所以方法如下。其他http服务器如tomcat自行百度相关方法。

  • 找到nginx的index.html所在目录,在此目录下的一切文件及递归文件均可直接下载。

假设nginx的index.html路径为/home/nginx/html/index.html

在日常访问域名https://xxx.com时,浏览器下载得到index.html并打开,就是我们看到的网页。

所以如果访问https://xxx.com/ics/xxx.ics,浏览器就会下载/home/nginx/html/ics/xxx.ics得到xxx.ics,如果没有找到,那就是404 Not Found。

  • 将ics文件放置在nginx的index.html所在目录下或其子文件夹下即可。
  • 订阅地址就自然是https://xxx.com/ics/xxx.ics了。

爬虫定期爬取数据

在CentOS下,编辑/etc/crontab增加相应定时任务即可。

最终效果示例 📽

ios12-macos-mojave-macbook-ipad-pro-iphone-x-icloud-calendar-subscriptions-hero

分析与结论 📝

  • 解决了上述提出的缺点
  • 若教务处网站不进行防爬虫更新,理论上可一直使用
  • 简化了生活流程,使其更加条理化

帮助链接

使用 iCloud 日历订阅 --Apple 支持

通过 iCloud 将“日历”保持为最新状态 --Apple 支持