文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

使用 Jupyter 改善你的时间管理

2024-12-03 09:23

关注

在 Jupyter 里使用 Python 来分析日历,以了解你是如何使用时间的。

Python 在探索数据方面具有令人难以置信的可扩展性。利用 Pandas 或 Dask,你可以将 Jupyter 扩展到大数据领域。但是小数据、个人资料、私人数据呢?

JupyterLab 和 Jupyter Notebook 为我提供了一个绝佳的环境,可以让我审视我的笔记本电脑生活。

我的探索是基于以下事实:我使用的几乎每个服务都有一个 Web API。我使用了诸多此类服务:待办事项列表、时间跟踪器、习惯跟踪器等。还有一个几乎每个人都会使用到:日历。相同的思路也可以应用于其他服务,但是日历具有一个很酷的功能:几乎所有 Web 日历都支持的开放标准 —— CalDAV。

在 Jupyter 中使用 Python 解析日历

大多数日历提供了导出为 CalDAV 格式的方法。你可能需要某种身份验证才能访问这些私有数据。按照你的服务说明进行操作即可。如何获得凭据取决于你的服务,但是最终,你应该能够将这些凭据存储在文件中。我将我的凭据存储在根目录下的一个名为 .caldav 的文件中:

  1. import os
  2. with open(os.path.expanduser("~/.caldav")) as fpin:
  3.     username, password = fpin.read().split()

切勿将用户名和密码直接放在 Jupyter Notebook 的笔记本中!它们可能会很容易因 git push 的错误而导致泄漏。

下一步是使用方便的 PyPI caldav 库。我找到了我的电子邮件服务的 CalDAV 服务器(你可能有所不同):

  1. import caldav
  2. client = caldav.DAVClient(url="https://caldav.fastmail.com/dav/", username=username, password=password)

CalDAV 有一个称为 principal(主键)的概念。它是什么并不重要,只要知道它是你用来访问日历的东西就行了:

  1. principal = client.principal()
  2. calendars = principal.calendars()

从字面上讲,日历就是关于时间的。访问事件之前,你需要确定一个时间范围。默认一星期就好:

  1. from dateutil import tz
  2. import datetime
  3. now = datetime.datetime.now(tz.tzutc())
  4. since = now - datetime.timedelta(days=7)

大多数人使用的日历不止一个,并且希望所有事件都在一起出现。itertools.chain.from_iterable 方法使这一过程变得简单:

  1. import itertools
  2.  
  3. raw_events = list(
  4.     itertools.chain.from_iterable(
  5.         calendar.date_search(start=since, end=now, expand=True)
  6.         for calendar in calendars
  7.     )
  8. )

将所有事件读入内存很重要,以 API 原始的本地格式进行操作是重要的实践。这意味着在调整解析、分析和显示代码时,无需返回到 API 服务刷新数据。

但 “原始” 真的是原始,事件是以特定格式的字符串出现的:

  1. print(raw_events[12].data)
  1.     BEGIN:VCALENDAR
  2.     VERSION:2.0
  3.     PRODID:-//CyrusIMAP.org/Cyrus
  4.      3.3.0-232-g4bdb081-fm-20200825.002-g4bdb081a//EN
  5.     BEGIN:VEVENT
  6.     DTEND:20200825T230000Z
  7.     DTSTAMP:20200825T181915Z
  8.     DTSTART:20200825T220000Z
  9.     SUMMARY:Busy
  10.     UID:
  11.      1302728i-040000008200E00074C5B7101A82E00800000000D939773EA578D601000000000
  12.      000000010000000CD71CC3393651B419E9458134FE840F5
  13.     END:VEVENT
  14.     END:VCALENDAR

幸运的是,PyPI 可以再次使用另一个辅助库 vobject 解围:

  1. import io
  2. import vobject
  3.  
  4. def parse_event(raw_event):
  5. data = raw_event.data
  6. parsed = vobject.readOne(io.StringIO(data))
  7. contents = parsed.vevent.contents
  8. return contents
  1. parse_event(raw_events[12])
  1. {'dtend': [<DTEND{}2020-08-25 23:00:00+00:00>],
  2. 'dtstamp': [<DTSTAMP{}2020-08-25 18:19:15+00:00>],
  3. 'dtstart': [<DTSTART{}2020-08-25 22:00:00+00:00>],
  4. 'summary': [<SUMMARY{}Busy>],
  5. 'uid': [<UID{}1302728i-040000008200E00074C5B7101A82E00800000000D939773EA578D601000000000000000010000000CD71CC3393651B419E9458134FE840F5>]}

好吧,至少好一点了。

仍有一些工作要做,将其转换为合理的 Python 对象。第一步是 拥有 一个合理的 Python 对象。attrs 库提供了一个不错的开始:

  1. import attr
  2. from __future__ import annotations
  3. @attr.s(auto_attribs=True, frozen=True)
  4. class Event:
  5.     start: datetime.datetime
  6.     end: datetime.datetime
  7.     timezone: Any
  8.     summary: str

是时候编写转换代码了!

第一个抽象从解析后的字典中获取值,不需要所有的装饰:

  1. def get_piece(contents, name):
  2. return contents[name][0].value
  3. get_piece(_, "dtstart")
  4. datetime.datetime(2020, 8, 25, 22, 0, tzinfo=tzutc())

日历事件总有一个“开始”、有一个“结束”、有一个 “持续时间”。一些谨慎的解析逻辑可以将两者协调为同一个 Python 对象:

  1. def from_calendar_event_and_timezone(event, timezone):
  2.     contents = parse_event(event)
  3.     start = get_piece(contents, "dtstart")
  4.     summary = get_piece(contents, "summary")
  5.     try:
  6.         end = get_piece(contents, "dtend")
  7.     except KeyError:
  8.         end = start + get_piece(contents, "duration")
  9.     return Event(start=start, end=end, summary=summary, timezone=timezone)

将事件放在 本地 时区而不是 UTC 中很有用,因此使用本地时区:

  1. my_timezone = tz.gettz()
  2. from_calendar_event_and_timezone(raw_events[12], my_timezone)
  3. Event(start=datetime.datetime(2020, 8, 25, 22, 0, tzinfo=tzutc()), end=datetime.datetime(2020, 8, 25, 23, 0, tzinfo=tzutc()), timezone=tzfile('/etc/localtime'), summary='Busy')

既然事件是真实的 Python 对象,那么它们实际上应该具有附加信息。幸运的是,可以将方法添加到类中。

但是要弄清楚哪个事件发生在哪一天不是很直接。你需要在 本地 时区中选择一天:

  1. def day(self):
  2. offset = self.timezone.utcoffset(self.start)
  3. fixed = self.start + offset
  4. return fixed.date()
  5. Event.day = property(day)
  1. print(_.day)
  2. 2020-08-25

事件在内部始终是以“开始”/“结束”的方式表示的,但是持续时间是有用的属性。持续时间也可以添加到现有类中:

  1. def duration(self):
  2. return self.end - self.start
  3. Event.duration = property(duration)
  1. print(_.duration)
  2. 1:00:00

现在到了将所有事件转换为有用的 Python 对象了:

  1. all_events = [from_calendar_event_and_timezone(raw_event, my_timezone)
  2.               for raw_event in raw_events]

全天事件是一种特例,可能对分析生活没有多大用处。现在,你可以忽略它们:

  1. # ignore all-day events
  2. all_events = [event for event in all_events if not type(event.start) == datetime.date]

事件具有自然顺序 —— 知道哪个事件最先发生可能有助于分析:

  1. all_events.sort(key=lambda ev: ev.start)

现在,事件已排序,可以将它们加载到每天:

  1. import collections
  2. events_by_day = collections.defaultdict(list)
  3. for event in all_events:
  4.     events_by_day[event.day].append(event)

有了这些,你就有了作为 Python 对象的带有日期、持续时间和序列的日历事件。

用 Python 报到你的生活

现在是时候编写报告代码了!带有适当的、列表、重要内容以粗体显示等等,有醒目的格式是很意义。

这就是一些 HTML 和 HTML 模板。我喜欢使用 Chameleon

  1. template_content = """
  2. item items">
  3. item[0]">Day

    • event item[1]">event">Thing
  • """
  • Chameleon 的一个很酷的功能是使用它的 html 方法渲染对象。我将以两种方式使用它:

    1. def __html__(self):
    2. offset = my_timezone.utcoffset(self.start)
    3. fixed = self.start + offset
    4. start_str = str(fixed).split("+")[0]
    5. summary = self.summary
    6. if summary != "Busy":
    7. summary = "<REDACTED>"
    8. return f"{summary[:30]} -- {start_str} ({self.duration})"
    9. Event.__html__ = __html__

    为了简洁起见,将该报告切成每天的:

    1. import chameleon
    2. from IPython.display import HTML
    3. template = chameleon.PageTemplate(template_content)
    4. html = template(items=itertools.islice(events_by_day.items(), 3, 4))
    5. HTML(html)

    渲染后,它将看起来像这样:

    2020-08-25

    Python 和 Jupyter 的无穷选择

    通过解析、分析和报告各种 Web 服务所拥有的数据,这只是你可以做的事情的表面。

    为什么不对你最喜欢的服务试试呢? 

    来源:Linux中国内容投诉

    免责声明:

    ① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

    ② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

    软考中级精品资料免费领

    • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

      难度     813人已做
      查看
    • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

      难度     354人已做
      查看
    • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

      难度     318人已做
      查看
    • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

      难度     435人已做
      查看
    • 2024年上半年系统架构设计师考试综合知识真题

      难度     224人已做
      查看

    相关文章

    发现更多好内容

    猜你喜欢

    AI推送时光机
    位置:首页-资讯-后端开发
    咦!没有更多了?去看看其它编程学习网 内容吧
    首页课程
    资料下载
    问答资讯