【问题标题】:Datetime and RegEx Dates日期时间和正则表达式日期
【发布时间】:2019-02-26 23:44:53
【问题描述】:

我正在从包含日期的 HTML 元素中抓取字符串。我要做的是使用正则表达式提取日期,然后使用 datetime 模块将它们转换为不同的格式。字符串遵循以下格式:

Date first available at Amazon.ca: Nov. 23 2017
Date first available at Amazon.ca: March 27 2017
Date first available at Amazon.ca: March 6 2018

这方面的棘手之处在于,只有名字长的月份才会被缩写。

Jan.
Feb.
March
April
May
June
July
Aug.
Sept.
Oct.
Nov.
Dec.

我的第一个想法是选择除Date first available at Amazon.ca: 之外的所有内容,但显然这比我最初想象的要困难一些。

我的下一个想法类似于r'^(J|F|M|A|S|O|De)',但这显然行不通,因为月份不在字符串的开头。

现在我被想法困住了。

显然像下面这样的正则表达式会起作用,但它似乎过于冗长。

r'(Jan.|Feb.|March|April|May|June|July|Aug.|Sept.|Oct.|Nov.|Dec.)[\d\s]+'

【问题讨论】:

  • 查看模块 dateutil。它有一个日期解析器,可以做你想做的事,而不必摆弄正则表达式。

标签: python regex python-3.x datetime web-scraping


【解决方案1】:

您可以通过搜索可能带有"." 的字母来搜索月、日和年:

import re, datetime
months = {b:a for a, b in enumerate(['Jan.', 'Feb.', 'March', 'April', 'May', 'June', 'July', 'Aug.', 'Sept.', 'Oct.', 'Nov.', 'Dec.'], 1)}
def convert_date(d:str) -> str:
  month, day, year = d.split()
  return datetime.datetime(int(year), months[month], int(day))

data = ['Date first available at Amazon.ca: Nov. 23 2017', 'Date first available at Amazon.ca: March 27 2017', 'Date first available at Amazon.ca: March 6 2018']
new_data = [re.findall('[a-zA-Z]+\.*\s\d+\s\d+$', i) for i in data]
final_results = [convert_date(i[0]) for i in new_data if i]

输出:

[datetime.datetime(2017, 11, 23, 0, 0), datetime.datetime(2017, 3, 27, 0, 0), datetime.datetime(2018, 3, 6, 0, 0)]

时间安排:

import time
def timeit(f):
  _t1 = time.time()
  _ = f()
  print(f'{f.__name__}: completed in {time.time()-_t1}')

@timeit
def ajax1234():
  new_data = [re.findall('[a-zA-Z]+\.*\s\d+\s\d+$', i) for i in data]

@timeit
def anthony():
  t = [re.findall('(Jan.|Feb.|March|April|May|June|July|Aug.|Sept.|Oct.|Nov.|Dec.)[\d\s]+', i) for i in data]

输出:

ajax1234: completed in 4.982948303222656e-05
anthony: completed in 3.314018249511719e-05

【讨论】:

  • 立即尝试。你在我另一个帖子上的回答完全被打破了嗯?
  • 要么输出空列表,要么抛出错误:/
  • @Anthony 你能澄清一下吗?你在什么输入上测试它?有哪些错误?输入字符串是否可能不包含日期?
  • 我上面列出的完全相同的输入。 “列表索引超出范围”,所以它必须返回一些东西。我所做的只是first_available = [re.findall('[a-zA-Z]+\.*\s\d+\s\d+$', i)[0] for i in first_available[0].text],然后是print(first_available)。正则表达式在浏览器测试器中工作,所以我的代码出了点问题
  • @Anthony Strange,当我在您发布的输入上运行代码时,我没有收到任何错误。复制我上面的例子并测试它。它会给您带来错误吗?
【解决方案2】:

你可以试试这个:

import re
dlist = [
"Date first available at Amazon.ca: Nov. 23 2017",
"Date first available at Amazon.ca: March 27 2017",
"Date first available at Amazon.ca: March 6 2018"]
print([re.search(r"(?<=\: )[a-zA-Z]+\.*[0-9 ]+" , each).group(0) for each in dlist])

【讨论】:

  • (?&lt;=\: ) 到底是做什么的?
  • 匹配以: 开头的字符串
【解决方案3】:

所以这是我的完整解决方案。

first_available = ff.find_elements(By.XPATH, '//li[contains(., "Date first available")]')
regex_first_available = re.compile(r'(Jan|Feb|March|April|May|June|July|Aug|Sept|Oct|Nov|Dec)[\d\s]+')

if len(first_available) > 0:
    first_available = regex_first_available.search(first_available[0].text).group(0)
else:
    first_available = ff.find_element(By.XPATH, '//td[text()="Date First Available"]/following-sibling::td[1]').text.replace('.', '')

try:
    first_available = datetime.datetime.strptime(first_available, '%b %d %Y').strftime('%Y-%m-%d')
except ValueError:
    first_available = datetime.datetime.strptime(first_available, '%B %d %Y').strftime('%Y-%m-%d')

如果有人改进了这种方法,我会选择你的解决方案作为答案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-02-18
    • 1970-01-01
    • 1970-01-01
    • 2021-09-09
    • 1970-01-01
    • 2011-03-09
    • 1970-01-01
    相关资源
    最近更新 更多