正则表达式在我爬虫开发中用的很频繁。尤其是当XPath和cssSelector 有心无力的时候。
现在,我遇到了一个这样的问题。我要爬取几十个网站的文章页,但是可能每个网站有自己的格式,我要汇总各种网站格式,然后将时间戳抽取出来。网站时间格式大致如下:
年月日:
2017-09-25 2017/09/25 2017.09.25 2017年09月25日
年月日 时分:
2017-09-25 18:59 2017/09/25 18:59
年月日 时分秒:
2017-09-25 18:59:48 2017年09月25日18:59:54
xx时间前:
1分钟前 1 小时前 1天前 (这里暂时不考虑英文,其实差不多)
先把正则表达式放出来
(20\d{2}([\.\-/|年月\s]{1,3}\d{1,2}){2}日?(\s?\d{2}:\d{2}(:\d{2})?)?)|(\d{1,2}\s?(分钟|小时|天)前)然后是结果
接下来我们就来构造这正则表达式
咋一看,挺复杂的正则表达式,但是无非就是那些语法构成,只要耐心点就很容易写出来
首先,我们要匹配日期,日期无非就 xxxxxx 这种格式,我们要主义的是三串数字之间的字符 比如 2017-09-25 2017/09/25 2017.09.25 这种无非就是分隔符的微弱区别。而我要抓的也仅是20xx年以后的东西,所以我可以这样写:
20\d{2}
表示年份 d{1,2}
表示月日 因为月份有 2 和02 两种情况
而中间的符号,常见的有 . \ 空格 中文
这几种情况,根据自己需求可以酌情添加。
这样我们就把中间符号正则写出来了- [\.\-/|年月\s]
.和- 需要转义,
还要注意的是 中文的时间后边可能会有个 日 字 所以也要匹配上,当然你可以选择用 * 但是我感觉效率应该没有固定了的高
接下来我们就该匹配时间了,时间这个相对简单,因为格式相对固定,区别在于有没有秒数。
根据之前的规则,我们可以很轻易写出 (\s\d{2}:\d{2}(:\d{2})?)?
这里不再赘述。
然后是匹配 某个xx之前,这里需要注意的是,数字有一位或者两位之分以及数字和文字之间是否有空格,根据需求写出\d{1,2}\s?(分钟|小时|天)前
剩下的就是拼接了,日期和时间点之间是或的关系,所以需要 | 符号,
就这样一个正则表达式就写出来了
补上测试代码:
time_test = ['2017年09月25日', '2017-09-25','2017/09/25','2017 09 25', '2017年09月25日19:13:33', '2017-09-25 19:13:40','1小时前','1 天前'] for i in time_test: post_time = re.search( '(20\d{2}([\.\-/|年月\s]{1,3}\d{1,2}){2}日?(\s?\d{2}:\d{2}(:\d{2})?)?)|(\d{1,2}\s?(分钟|小时|天)前)',i) print(post_time)正文结束,接下来是怎样将时间转换为时间戳,这里我用到了一个第三方库dateparser
附上相关代码
#!/usr/bin/env python # -*- coding: utf-8 -*- import re import dateparser import time import random time_re = re.compile('[年月日\s]') def generate_timestamp(post_time): now = in()) date_time = da(' ', post_time)) if date_time: time_stamp = in()) else: return now if time_stamp > now: time_stamp = now - random.randint(0, 600) return time_stamp