能通過python向mac的日曆添加事件么?

寫了爬蟲爬下了課表的信息,但是不知道通過什麼辦法把 課表 按照 添加事件的辦法 添加到日曆中?


http://stackoverflow.com/questions/16065162/calling-applescript-from-python-without-using-osascript-or-appscript

要學會合理使用必應搜索引擎


2016.12.02 更新: 乾貨之前先來一點碎碎念。

0. 請合理使用各種搜索引擎+關鍵字。

1. 當你覺得百度上已經沒有好資料的時候,不妨試一下必應和谷歌。

2. 當你覺得谷歌上沒有好資料的時候,不妨換一下搜索關鍵字。

3. 是時候該找一個快一點的代理伺服器,訪問國外網站儘可能的快。

4. 請多看英文原文文檔

5. 做程序,最後一步才是寫代碼,之前大部分時間在看文檔?做設計?喵 ~

6. 我的代碼很爛,請各位隨便吐槽。python 新手。

7. 暫時沒有閑功夫吃語法糖優化簡略一下代碼。

8. 項目基於GPLv3 GNU General Public License 開源

9. GitHub 源代碼地址: acbetter/cqut_student_schedule_py

10. 這是一個完整的項目,從模擬登陸到抓取網頁,把課程表數據轉換成日曆。

11. 以下內容截取自我個人博客的文章 喵課表 原理與實現 by python 3

12. 由於文章還沒有寫完。。。難免會出紕漏。。。見諒。。。

13. 效果怎麼樣:有圖有真相。

電腦端 (macOS)

手機端 (iOS)

我用的 Fantastical 2 ... For iOS and macOS ... 感覺效果還好 ......

---

以下是乾貨

---

  • 首先看一下 @yulanggong 對 日曆標準格式的研究


    BEGIN:VCALENDAR #日曆開始

    PRODID:-//Google Inc//Google Calendar 70.9054//EN #軟體信息

    VERSION:2.0 #遵循的 iCalendar 版本號

    CALSCALE:GREGORIAN #曆法:公曆

    METHOD:PUBLISH #方法:公開 也可以是 REQUEST 等用於日曆間的信息溝通方法

    X-WR-CALNAME:yulanggong@gmail.com #這是一個通用擴展屬性 表示本日曆的名稱

    X-WR-TIMEZONE:Asia/Shanghai #通用擴展屬性,表示時區

    BEGIN:VEVENT #事件開始

    DTSTART:20090305T112200Z #開始的日期時間

    DTEND:20090305T122200Z #結束的日期時間

    DTSTAMP:20140613T033914Z #有Method 屬性時表示 實例創建時間,沒有時表示最後修訂的日期時間

    UID:9r5p7q78uohmk1bbt0iedof9s4@google.com #UID

    CLASS:PRIVATE #保密類型

    CREATED:20090305T092105Z #創建的日期時間

    DESCRIPTION:test #描述

    LAST-MODIFIED:20090305T092130Z #最後修改日期時間

    LOCATION:test #地址

    SEQUENCE:1 #排列序號

    STATUS:CONFIRMED #狀態 TENTATIVE 試探 CONFIRMED 確認 CANCELLED 取消

    SUMMARY: test #簡介 一般是標題

    TRANSP:OPAQUE #對於忙閑查詢是否透明 OPAQUE 不透明 TRANSPARENT 透明

    END:VEVENT #事件結束

    END:VCALENDAR #日曆結束

  • 所以,我們只需要按照這個標準格式把我們的課程錶轉換成 *.ics 文件就好了。之前不是已經獲取了課程表嗎,快把它傳進來。標準格式可以查看這個文檔 Internet Calendaring and Scheduling Core Object Specification (iCalendar))

    from icalendar import Calendar
    from datetime import date
    def get_ics(schedule):
    cal = Calendar()
    cal["version"] = "2.0"
    cal["prodid"] = "-//CQUT//Syllabus//CN" # *mandatory elements* where the prodid can be changed, see RFC 5445
    start_monday = date(2016, 8, 29) # 開學第一周星期一的時間
    dict_week = {"一": 0, "二": 1, "三": 2, "四": 3, "五": 4, "六": 5, "日": 6}
    dict_day = {1: relativedelta(hours=8, minutes=20), 3: relativedelta(hours=10, minutes=20),
    5: relativedelta(hours=14, minutes=0), 7: relativedelta(hours=16, minutes=0),
    9: relativedelta(hours=19, minutes=0)}

  • 然後遵循規則把課程表的數據改成 iCalendar 格式就好了。首先呢要有一個 日曆:cal = Calendar() 然後向 cal 添加 事件:event = Event() 這些用法主要參考 iCalendar package 的 用法: Internet Calendaring and Scheduling (iCalendar) for Python

    from uuid import uuid1
    from icalendar import Event
    from datetime import datetime
    from dateutil.relativedelta import relativedelta
    for line in schedule:
    event = Event()
    print(line)
    # line should be like this: ["彙編語言程序設計", "周三第7,8節", "第10-10周|雙周", "第1實驗樓B403-A", "劉小洋(劉小洋)"]

    info_day = re.findall(r"周(.*?)第(d+),(d+)節", line[1], re.S | re.M)
    info_day = info_day[0]
    print(info_day)
    # info_day should be like this: ("三", "7", "8")

    info_week = re.findall(r"第(d+)-(d+)周", line[2], re.S | re.M)
    info_week = info_week[0]
    print(info_week)
    # info_week should be like this: ("10", "10")

    dtstart_date = start_monday + relativedelta(weeks=(int(info_week[0]) - 1)) + relativedelta(
    days=int(dict_week[info_day[0]]))
    dtstart_datetime = datetime.combine(dtstart_date, datetime.min.time())
    dtstart = dtstart_datetime + dict_day[int(info_day[1])]
    dtend = dtstart + relativedelta(hours=1, minutes=40)
    # 我們的課持續一小時四十分鐘(中間有十分鐘課間時間)
    if int(info_day[1]) == 9:
    dtend = dtend - relativedelta(minutes=5)
    # 我們晚上的課要少五分鐘課間時間

    event.add("uid", str(uuid1()) + "@CQUT")
    event.add("summary", line[0])
    event.add("dtstamp", datetime.now())
    event.add("dtstart", dtstart)
    event.add("dtend", dtend)

    if line[2].find("|") == -1:
    interval = 1
    else:
    interval = 2
    # 如果有單雙周的課 那麼這些課隔一周上一次

    event.add("rrule",
    {"freq": "weekly", "interval": interval,
    "count": int(info_week[1]) - int(info_week[0]) + 1})
    # 設定重複次數

    event.add("location", line[3])
    # 設定重複地點

    cal.add_component(event)
    return cal

  • 其中,我們的課有一些是每周重複,有一些課分單雙周,這些就可以參考 Recurrence Rule ~ 不得不說,這些例子通俗易懂,是非常好的學習材料。


    Daily for 10 occurrences:

    DTSTART;TZID=US-Eastern:19970902T090000

    RRULE:FREQ=DAILY;COUNT=10

    ? (1997 9:00 AM EDT)September 2-11

    Daily until December 24, 1997:

    DTSTART;TZID=US-Eastern:19970902T090000

    RRULE:FREQ=DAILY;UNTIL=19971224T000000Z

    ? (1997 9:00 AM EDT)September 2-30;October 1-25

    ? (1997 9:00 AM EST)October 26-31;November 1-30;December 1-23

    Every other day - forever:

    DTSTART;TZID=US-Eastern:19970902T090000

    RRULE:FREQ=DAILY;INTERVAL=2

    ? (1997 9:00 AM EDT)September2,4,6,8…24,26,28,30;

    ? October 2,4,6…20,22,24

    ? (1997 9:00 AM EST)October 26,28,30;November 1,3,5,7…25,27,29;

    ? Dec 1,3,…

  • 得到了一個 cal 之後,我想在控制台中看一下這個玩意兒。於是就用到了 dispaly() 這貨。

    def display(cal):
    return cal.to_ical().decode("utf-8").replace("
    ", "
    ").strip()
    def print_cal:
    print(display(cal))

  • 得到了下面的輸出。於是我新建了一個文本文檔,把這些內容拷貝進去,保存,然後把文件後綴改成 ics 完美!得到了這個文件,感覺整個人都是萌萌噠的,又可以為所欲為了!

    BEGIN:VCALENDAR

    VERSION:2.0

    PRODID:-//CQUT//Syllabus//CN

    BEGIN:VEVENT

    SUMMARY:大學物理學【Ⅱ(2)】

    DTSTART;VALUE=DATE-TIME:20160829T082000

    DTEND;VALUE=DATE-TIME:20160829T100000

    DTSTAMP;VALUE=DATE-TIME:20161202T211058Z

    UID:c3bc4522-b890-11e6-a852-a45e60ef9ad5@CQUT

    RRULE:FREQ=WEEKLY;COUNT=10;INTERVAL=1

    LOCATION:1教0516

    END:VEVENT

    BEGIN:VEVENT

    SUMMARY:Linux基礎與應用

    DTSTART;VALUE=DATE-TIME:20160830T082000

    DTEND;VALUE=DATE-TIME:20160830T100000

    DTSTAMP;VALUE=DATE-TIME:20161202T211058Z

    UID:c3bd2e58-b890-11e6-9618-a45e60ef9ad5@CQUT

    RRULE:FREQ=WEEKLY;COUNT=10;INTERVAL=1

    LOCATION:4教0209

    END:VEVENT

    BEGIN:VEVENT

    SUMMARY:彙編語言程序設計

    DTSTART;VALUE=DATE-TIME:20161115T102000

    DTEND;VALUE=DATE-TIME:20161115T120000

    DTSTAMP;VALUE=DATE-TIME:20161202T211058Z

    UID:c3bd68d0-b890-11e6-8db4-a45e60ef9ad5@CQUT

    RRULE:FREQ=WEEKLY;COUNT=5;INTERVAL=1

    LOCATION:3教0406

    END:VEVENT

    BEGIN:VEVENT

    SUMMARY:大學物理學【Ⅱ(2)】

    DTSTART;VALUE=DATE-TIME:20160831T102000

    DTEND;VALUE=DATE-TIME:20160831T120000

    DTSTAMP;VALUE=DATE-TIME:20161202T211058Z

    UID:c3bd717a-b890-11e6-b0e2-a45e60ef9ad5@CQUT

    RRULE:FREQ=WEEKLY;COUNT=10;INTERVAL=1

    LOCATION:1教0516

    END:VEVENT

    BEGIN:VEVENT

    SUMMARY:線性代數【理工】

    DTSTART;VALUE=DATE-TIME:20161115T140000

    DTEND;VALUE=DATE-TIME:20161115T154000

    DTSTAMP;VALUE=DATE-TIME:20161202T211058Z

    UID:c3bd940c-b890-11e6-9fbf-a45e60ef9ad5@CQUT

    RRULE:FREQ=WEEKLY;COUNT=2;INTERVAL=1

    LOCATION:5教0306

    END:VEVENT

    END:VCALENDAR

    賊長我就不全部複製了。。。

macOS 下雙擊 ics 文件就可以導入到 日曆.app 當中了。其他平台不多贅述自行百度必應谷歌。

當然你也可以直接用 python 把這些保存到文件當中,我的 GitHub 源代碼地址: acbetter/cqut_student_schedule_py 有這些代碼,不多講了。

答案很長,廢話連篇。毫無乾貨,全是套路。歡迎去我個人博客的文章 喵課表 原理與實現 by python 3 吐槽。

---

以下是原答案:最近剛好在做這個,先挖個坑,以後再填。


大一剛好弄過這個。

你可以看看 wikipedia 上關於 iCalendar 的說明,一種用於保存各種日曆信息的文件格式。雖然每種日曆有添加自己的東西但是基本的標準都有支持,對著現在的標準把事件擼進文件就可以了。

Mac 的日曆,google calendar 和 outlook 都可以導入,如果需要在手機端用可以先用谷歌日曆導入再同步(有些手機,比如小米,自帶日曆無法導入這種文件)。


如果添加一些簡單的,可以試試 IFFT


推薦閱讀:

在使用OmniFocus的過程中如何搭配使用日曆?

TAG:Mac | macOS | Python | 爬蟲計算機網路 | 日曆類應用 |