历史上的今天

如果要在网页上显示一些随机的语句,获得一些人生的经验,你会选择什么?
也许,一言是一个很好的选择,它可以提供一些动漫中的台词,或是网络上的各种小段子。
在前面的文章有趣的 Linux 命令行工具中提到的 fortune 命令或许也可以满足需求,pure-ftpd 就可以设置在连接成功时显示随机的来自 fortune 的语句。
那除此之外呢?历史上的今天是一个不错的方案。当你访问一些门户网站的首页,有时会看到这样的栏目。它也是一些百科全书网站,比如维基百科的传统。事实上,在 Mac 上就自带了一个小型的「历史上的今天」数据库,执行:

1
cat /usr/share/calendar/calendar.history

就可以看到。
这篇文章将介绍如何搭建一个提供「历史上的今天」信息的 API。

建立数据库

首先,建立 MySQL 数据库和数据表,用于存储爬取的信息。这里数据库和数据表名都以 event 为例。

1
2
3
4
5
6
7
8
9
10
CREATE DATABASE event;
USE event;
CREATE TABLE event (
id int(10) UNSIGNED PRIMARY KEY NOT NULL AUTO_INCREMENT,
type int(1) DEFAULT NULL,
year varchar(6) DEFAULT NULL,
date varchar(6) DEFAULT NULL,
info text DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
QUIT;

获取数据

数据来源是维基百科,使用 Python 爬取数据,并存入数据库中。项目地址:TodayInHistory-Crawler,可以打包下载所有文件。

下载程序源码后,进入目录并安装依赖:

1
pip3 install -r requirements.txt

config.py 中的 usernamepassworddbnametablename 分别是你的登录用户名、密码、数据库名和数据表名。将它们修改成和之前创建的数据库和数据表名一致。

然后,运行 spider.py,程序将会开始爬取数据。程序会用 try except 处理特殊字符(非 UTF-8 范围)的问题,并将失败的项目记录在 failed.txt 中。

查询数据

比较简单的方式是按照 json 格式进行输出,server.py 给出了一种使用 Python 的方案,运行后就可以访问 Flask 创建的服务器了。

当然,用 PHP 也是可以实现的,毕竟只需要进行 MySQL 查询,没有静态文件,很方便。可以使用如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?php
$mysqli = new mysqli("localhost", "username", "password", "dbname");

/* 检查连接 */
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}

$date = $_GET['date'] ? $mysqli->real_escape_string($_GET['date']) : date("m月d日");
$type = $_GET['type'] ? (int)$mysqli->real_escape_string($_GET['type']) : 0;
$count = $_GET['count'] ? (int)$mysqli->real_escape_string($_GET['count']) : 1;
$result = array();

/* 创建一个预编译 SQL 语句 */
if ($stmt = $mysqli->prepare("select * from `event` where `date` = ? and `type` = ? order by RAND() limit ?")) {
/* 对于参数占位符进行参数值绑定 */
$stmt->bind_param("dii", $date, $type, $count);
/* 执行查询 */
$stmt->execute();
/* 将查询结果绑定到变量 */
$stmt->bind_result($id, $type, $year, $date, $info);
/* 获取查询结果值 */
while ($stmt->fetch()) {
$arr = array('year' => $year, 'info' => $info);
$result[] = $arr;
};
echo json_encode($result, JSON_UNESCAPED_UNICODE);
/* 关闭语句句柄 */
$stmt->close();
}
/* 关闭连接 */
$mysqli->close();
?>

笔者搭建的 API:历史上的今天

本文更新于 2021 年 8 月:
利用维基百科的导出页面功能,可以一次性获取所有日期的文本,通过解析 XML 文件也能将内容存入数据库中。