历史上的今天

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

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

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

建立数据库

首先,建立 MySQL 数据库,用于存储爬取的信息。

1
2
3
4
5
6
7
8
9
10
11
CREATE DATABASE dbname;
# 建立数据库,dbname 保持一致即可
USE dbname;
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 varchar(300) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
QUIT;

获取数据

数据来源是维基百科,使用 Python 爬取数据,并存入数据库中。代码中的 usernamepassworddbname 分别是你的登录用户名、密码和数据库名。数据表名默认是 event,也可以自行修改。

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#!/usr/bin/env python3
import pymysql
import requests
from bs4 import BeautifulSoup
import datetime
import re

typeList = ["大事记", "出生", "逝世"]

def savedb(data):
conn = pymysql.connect(host = "127.0.0.1", user = "username", password = "password", db = "dbname", charset = "utf8")
print(conn)
cur = conn.cursor()
try:
cur.execute("insert into event values(null,%s,%s,%s,%s)", data)
except pymysql.err.InternalError:
print("\033[31mERROR: Incorrect string value.\033[0m", data)
with open("failed.txt", "a") as myfile:
myfile.write(str(data) + "\n")
except pymysql.err.DataError:
print("\033[31mERROR: Data too long.\033[0m", data)
with open("failed.txt", "a") as myfile:
myfile.write(str(data) + "\n")
cur.connection.commit()
cur.close()
conn.close()

def getDateList():
list = []
date = datetime.date(2016, 1, 1)
for i in range(366):
date_str = str(date.month) + "月" + str(date.day) + "日"
list.append(date_str)
date += datetime.timedelta(days = 1)
return list

def getInfo(html, type, date):
flag = re.compile("(<h2><span id=.*<span class=\"mw-headline\"id=.*?" + typeList[type] + "[\s\S]*?</ul>\s*?)<h2>").search(html)
if flag:
bsObj = BeautifulSoup(flag.group(1), "html.parser").findAll("li")
for li in bsObj:
match = re.compile("((^ 前 |^)\d{1,4} 年):([\s\S]*$)").match(li.get_text())
if match:
year = match.group(1)
info = re.sub("\[\d{1,}\]", "", match.group(3).strip())
data = (type, year, date, info)
print(data)
savedb(data)

def main():
list = getDateList()
for date in list:
print(date)
url = "https://zh.wikipedia.org/zh-cn/%s" % date
#url ="https://api.galaxymimi.com/proxy/?url=https://zh.wikipedia.org/zh-cn/%s"% date
r = requests.get(url)
getInfo(r.text, 0, date) # 大事记
getInfo(r.text, 1, date) # 出生
getInfo(r.text, 2, date) # 逝世

if __name__ == '__main__':
main()

这里的两个 except 分别处理的是特殊字符(非 UTF-8 范围)和内容长度超出的问题。

查询数据

比较简单的方式是按照 json 格式进行输出,这里给出一种使用 PHP 的方案。

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
<?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();
?>

同样将 usernamepassworddbname 根据情况替换,就可以访问了。

项目地址:TodayInHistory-Crawler,可以打包下载所有文件。

博主搭建的 API:历史上的今天

🍭支持一根棒棒糖!
0%