前期爬取了网上的一些文章,并存储到 PostgreSQL 中。但是当时用以提取发布日期的方法不太好,提取成功率很低。幸好观察存储的 URL,似乎其中包含了发布日期。格式大概是:
'/2020/0909/random_numbers/page.htm'
# 或
'/_t147/2020/0909/random_numbers/page.htm'
便想到在 PostgreSQL 中调用 Python 实现日期提取。
安装 plpython3u 扩展
环境:
- PostgreSQL 13.2
- Python 3.8.5
PostgreSQL 的扩展性很好。曾经在 《PostgreSQL 服务端编程》中了解过这种对不同语言插件的扩展性,今天便来试一试。我的 pg 是运行在 Debian 上的,可以使用 apt 命令安装:
apt install postgresql-plpython3-13 postgresql-plpython3-13-dbgsym
网上的资料多是 Redhat 那一类系统的,可能因为 PostgreSQL 官方在下载页给出了 rpm 包。我是使用 apt search 搜索的:
root@KiteAgentEnv:~# apt search postgresql-plpython
Sorting... Done
Full Text Search... Done
(省略)
postgresql-plpython3-13/focal-pgdg,now 13.2-1.pgdg20.04+1 amd64 [installed]
PL/Python 3 procedural language for PostgreSQL 13
postgresql-plpython3-13-dbgsym/focal-pgdg,now 13.2-1.pgdg20.04+1 amd64 [installed]
debug symbols for postgresql-plpython3-13
root@KiteAgentEnv:~#
如果没有配置 PostgreSQL 的 apt 源,需要事先设置一下,设置方法见 官方 Wiki 或 我的上一篇博客。
一般来说不需要重启服务器,就可以在可用扩展列表中看到了:
SELECT name FROM pg_available_extensions;
然后执行以在当前数据库中启用扩展:
CREATE EXTENSION plpython3u;
编写函数
简单地编写函数如下:
CREATE OR REPLACE FUNCTION try_parse_date(path text)
RETURNS text
AS $$
import re
r = re.search(r'/(20[012]\d/\d{4})/', path)
if r:
date_str = r.group(1)
year = date_str[:4]
month = date_str[-4:-2]
day = date_str[-2:]
return f'{year}-{month}-{day}'
$$ LANGUAGE plpython3u;
然后执行:
SELECT try_parse_date('/2020/0909/c12570a187683/page.htm')::date;
瞅着可以,拿去试试——对于约 12 万条文章,用时 5 m 22 s 605 ms。执行过程中CPU占用在单核且 10% 左右,但是对于用时来说这个效率有点低。可能的原因是每次都加载了 re 模块,并且正则表达式较普通的字符串处理更慢。不过,对于这样的小任务来说,用时足够短了。
参考资料
- 第 45 章 PL/Python - Python 过程语言, PostgreSQL 官方文档
- PostgreSQL: how to install plpythonu extension, StackOverflow