【问题标题】:How do I parse an HTTP date-string in Python?如何在 Python 中解析 HTTP 日期字符串?
【发布时间】:2010-12-01 02:45:42
【问题描述】:

有没有一种简单的方法可以在 Python 中解析 HTTP 日期字符串?根据the standard,有几种格式化HTTP日期字符串的方法;该方法应该能够处理这个问题。

换句话说,我想将“Wed, 23 Sep 2009 22:15:29 GMT”之类的字符串转换为 python 时间结构。

【问题讨论】:

    标签: python http datetime parsing


    【解决方案1】:

    从 Python 3.3 开始,email.utils.parsedate_to_datetime 可以解析 RFC 5322 时间戳(又名 IMF-fixdate,Internet 消息格式固定长度格式,HTTP-dateRFC 7231 的子集)。

    >>> from email.utils import parsedate_to_datetime
    ... 
    ... s = 'Sun, 06 Nov 1994 08:49:37 GMT'
    ... parsedate_to_datetime(s)
    0: datetime.datetime(1994, 11, 6, 8, 49, 37, tzinfo=datetime.timezone.utc)
    

    还有无证的http.cookiejar.http2time可以实现如下:

    >>> from datetime import datetime, timezone
    ... from http.cookiejar import http2time
    ... 
    ... s = 'Sun, 06 Nov 1994 08:49:37 GMT'
    ... datetime.utcfromtimestamp(http2time(s)).replace(tzinfo=timezone.utc)
    1: datetime.datetime(1994, 11, 6, 8, 49, 37, tzinfo=datetime.timezone.utc)
    

    它在 Python 2.4 中作为 cookielib.http2time 引入,用于处理以相同格式表示的 Cookie Expires 指令。

    【讨论】:

      【解决方案2】:
      httplib.HTTPMessage(filehandle).getdate(headername)
      httplib.HTTPMessage(filehandle).getdate_tz(headername)
      mimetools.Message(filehandle).getdate()
      rfc822.parsedate(datestr)
      rfc822.parsedate_tz(datestr)
      
      • 如果您有原始数据流,则可以从中构建 HTTPMessage 或 mimetools.Message。在查询响应对象以获取信息时,它可能会提供额外的帮助
      • 如果您使用的是 urllib2,则您已经在 urlopen 返回的文件处理程序中隐藏了一个 HTTPMessage 对象
      • 它可能可以解析多种日期格式
      • httplib 在核心中

      注意:

      • 查看了实现,HTTPMessage 继承自 mimetools.Message,而 mimetools.Message 继承自 rfc822.Message。您可能感兴趣的两个浮动 defs,parsedate 和 parsedate_tz(在后者中)
      • 来自 email.utils 的 parsedate(_tz) 有不同的实现,虽然看起来有点相似。

      你可以这样做,如果你只有那一段字符串并且你想解析它:

      >>> from rfc822 import parsedate, parsedate_tz
      >>> parsedate('Wed, 23 Sep 2009 22:15:29 GMT')
      (2009, 9, 23, 22, 15, 29, 0, 1, 0)
      >>> 
      

      但让我通过 mime 消息来举例说明:

      import mimetools
      import StringIO
      message = mimetools.Message(
          StringIO.StringIO('Date:Wed, 23 Sep 2009 22:15:29 GMT\r\n\r\n'))
      >>> m
      <mimetools.Message instance at 0x7fc259146710>
      >>> m.getdate('Date')
      (2009, 9, 23, 22, 15, 29, 0, 1, 0)
      

      或通过 http 消息(响应)

      >>> from httplib import HTTPMessage
      >>> from StringIO import StringIO
      >>> http_response = HTTPMessage(StringIO('Date:Wed, 23 Sep 2009 22:15:29 GMT\r\n\r\n'))
      >>> #http_response can be grabbed via urllib2.urlopen(url).info(), right?
      >>> http_response.getdate('Date')
      (2009, 9, 23, 22, 15, 29, 0, 1, 0)
      

      对吗?

      >>> import urllib2
      >>> urllib2.urlopen('https://fw.io/').info().getdate('Date')
      (2014, 2, 19, 18, 53, 26, 0, 1, 0)
      

      好了,现在我们更多地了解日期格式、mime 消息、mime 工具及其 Python 实现 ;-)

      无论如何,看起来比使用 email.utils 解析 http 标头更好。

      【讨论】:

      【解决方案3】:
      >>> import email.utils as eut
      >>> eut.parsedate('Wed, 23 Sep 2009 22:15:29 GMT')
      (2009, 9, 23, 22, 15, 29, 0, 1, -1)
      

      如果你想要一个datetime.datetime 对象,你可以这样做:

      def my_parsedate(text):
          return datetime.datetime(*eut.parsedate(text)[:6])
      

      【讨论】:

      • 是的,parsedate 可能是最好的折衷方案,尽管它的“容错 RFC 2822 解析”与要求“必须”的 RFC 2616'2 不是 100% 兼容——例如,RFC 850 格式的史诗失败,有两个-数字年份,例如Sunday, 06-Nov-94 08:49:37 GMT,但 2616 表示客户端必须能够解析 RFC 850 日期(叹气)。
      • email.utils.parsedate is email.Utils.parsedate -&gt; True 看来 Utils 是一个惰性加载器。
      • 还要注意 email.util.parsedate() 返回一个可以直接传递给 time.mktime() 的元组(这会为您提供计算机上纪元的 int 秒数(本地时间,不是UTC))。
      • @driax:自纪元以来的秒数不依赖于本地时区,例如,0 表示1970-01-01T00:00:00Z——它是世界各地的同一时间实例(本地时钟显示不同的值,但时间戳完全相同)。除非输入时间字符串是 UTC (GMT);你应该use mktime_tz(parsedate_tz()) instead -- 否则时区信息会丢失。
      • 在更新的python版本中你可以使用email.utils.parsedate_to_datetime
      【解决方案4】:
      >>> import datetime
      >>> datetime.datetime.strptime('Wed, 23 Sep 2009 22:15:29 GMT', '%a, %d %b %Y %H:%M:%S GMT')
      datetime.datetime(2009, 9, 23, 22, 15, 29)
      

      【讨论】:

      • 是的,它很容易扩展以处理任何格式。虽然email.utils.parse 更健壮,但它的透明度也较低。
      • +1,谢谢。因为它说要避免这样的cmets。比“utils”命名的模块更清晰
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-06-14
      • 1970-01-01
      • 2018-04-18
      • 1970-01-01
      • 2019-08-26
      • 1970-01-01
      相关资源
      最近更新 更多