维基百科在生产服务器被阻断,改用百度百科开放接口:
- 端点 /cms/home/eventsOnHistory/{MM}.json,按月返回结构化 JSON
- 12 次请求替代原 366 次,大幅减负
- type 直接映射 event/birth/death,festival 字段提取节假日
- 清洗 title/desc 中的 HTML 标签
- 2 月无 29 日,全年 365 天
- 本地验证:365 天 4805 条,12/12 月全成功
This commit is contained in:
@@ -1,43 +1,31 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// 取自 zh.wikipedia.org「8月10日」页面的真实片段
|
||||
const sampleWikitext = `'''8月10日'''是[[阳历]]年的第222天。
|
||||
// 取自百度百科 /cms/home/eventsOnHistory/08.json 的真实片段(8月12日/13日)
|
||||
const sampleBaikeJSON = `{"08":{
|
||||
"0812":[
|
||||
{"year":"-30","title":"埃及艳后<a target=\"_blank\" href=\"https://baike.baidu.com/item/x\">克利奥帕特拉七世</a>逝世","festival":"","link":"https://baike.baidu.com/item/x","type":"death","desc":"克利奥帕特拉七世"},
|
||||
{"year":"1848","title":"英国著名小说家<a target=\"_blank\" href=\"x\">乔治·艾略特</a>出生","festival":"","link":"x","type":"birth","desc":"x"},
|
||||
{"year":"1848","title":"英国著名小说家乔治·艾略特出生","festival":"","link":"x","type":"birth","desc":"x"},
|
||||
{"year":"1905","title":"挪威音乐家<a href=\"x\">某</a>指挥首演","festival":"","link":"x","type":"event","desc":"x"}
|
||||
],
|
||||
"0813":[
|
||||
{"year":"604","title":"隋文帝<a href=\"x\">杨坚</a>逝世","festival":"国际左撇子日","link":"x","type":"death","desc":"x"},
|
||||
{"year":"1926","title":"古巴革命领导人<a href=\"x\">卡斯特罗</a>出生","festival":"国际左撇子日","link":"x","type":"birth","desc":"x"},
|
||||
{"year":"1910","title":"某事件<a href=\"x\">发生</a>","festival":"国际左撇子日","link":"x","type":"event","desc":"x"},
|
||||
{"year":"abc","title":"年份非法的<a href=\"x\">事件</a>条目","festival":"国际左撇子日","link":"x","type":"event","desc":"x"}
|
||||
]
|
||||
}}`
|
||||
|
||||
== 大事记 ==
|
||||
=== 19世紀以前 ===
|
||||
* [[前612年]]:[[亚述]]最后一位君主[[辛·沙里施昆]]死于[[尼尼微]],王国灭亡。
|
||||
* [[955年]]:[[鄂圖一世 (神聖羅馬帝國)|鄂圖一世]]麾下的軍隊在[[第二次萊希菲爾德之戰 (955)|萊希菲爾德之戰]]中取得勝利。<ref>注释</ref>
|
||||
=== 20世紀 ===
|
||||
* [[1912年]]:[[威廉·布利斯]]出版了第一本关于[[童子军]]的书。
|
||||
* [[1945年]]:{{le|蒙古}}对日宣战。
|
||||
* [[2002年]]:-{zh-hans:凯尔·斯科特;zh-hk:卡爾·史葛;zh-tw:凱爾·斯科特;}-,英國職業足球運動員。
|
||||
* 年份不详:某件无法确定年份的事情发生了。
|
||||
|
||||
== 出生 ==
|
||||
* [[前156年]]:[[汉武帝]]刘彻,[[西汉]]皇帝([[前87年]]逝世)
|
||||
* [[前156年]]:[[汉武帝]]刘彻,[[西汉]]皇帝([[前87年]]逝世)
|
||||
* [[1874年]]:[[赫伯特·胡佛]],美国第31任[[总统]]([[1964年]]逝世)
|
||||
|
||||
== 逝世 ==
|
||||
* [[258年]]:[[羅馬的聖老楞佐]],基督教殉道者
|
||||
|
||||
== 节假日和习俗 ==
|
||||
* {{flag|厄瓜多尔}}:独立日
|
||||
* 世界[[狮子]]日
|
||||
|
||||
==参考资料==
|
||||
{{Commonscat}}
|
||||
`
|
||||
|
||||
func TestParseDayPage(t *testing.T) {
|
||||
items := parseDayPage(sampleWikitext)
|
||||
func TestParseBaikeMonth(t *testing.T) {
|
||||
items, err := parseBaikeMonth([]byte(sampleBaikeJSON), 8)
|
||||
if err != nil {
|
||||
t.Fatalf("parseBaikeMonth 失败: %v", err)
|
||||
}
|
||||
|
||||
count := func(kind string) int {
|
||||
n := 0
|
||||
@@ -49,65 +37,78 @@ func TestParseDayPage(t *testing.T) {
|
||||
return n
|
||||
}
|
||||
|
||||
if got := count("event"); got != 6 {
|
||||
t.Errorf("event 条目数 = %d, 期望 6", got)
|
||||
// 0812: 1 death + 2 birth(重复去重后1) + 1 event = 3;0813: 1 death + 1 birth + 2 event = 4
|
||||
if got := count("death"); got != 2 {
|
||||
t.Errorf("death 条目数 = %d, 期望 2", got)
|
||||
}
|
||||
if got := count("birth"); got != 2 { // 重复条目应去重
|
||||
if got := count("birth"); got != 2 { // 0812 重复出生条目应去重
|
||||
t.Errorf("birth 条目数 = %d, 期望 2", got)
|
||||
}
|
||||
if got := count("death"); got != 1 {
|
||||
t.Errorf("death 条目数 = %d, 期望 1", got)
|
||||
if got := count("event"); got != 3 {
|
||||
t.Errorf("event 条目数 = %d, 期望 3", got)
|
||||
}
|
||||
if got := count("festival"); got != 2 {
|
||||
t.Errorf("festival 条目数 = %d, 期望 2", got)
|
||||
// 国际左撇子日只在 0813,去重后 1 条 festival
|
||||
if got := count("festival"); got != 1 {
|
||||
t.Errorf("festival 条目数 = %d, 期望 1", got)
|
||||
}
|
||||
|
||||
// 校验具体条目的年份与文本清洗
|
||||
assertItem := func(kind string, wantYear int, wantContent string) {
|
||||
// 校验具体条目
|
||||
assertItem := func(kind string, day, wantYear int, wantContent string) {
|
||||
for _, it := range items {
|
||||
if it.Kind == kind && it.Content == wantContent {
|
||||
if it.Kind == kind && it.Day == day && it.Content == wantContent {
|
||||
if it.Year != wantYear {
|
||||
t.Errorf("%q 年份 = %d, 期望 %d", wantContent, it.Year, wantYear)
|
||||
}
|
||||
if it.Month != 8 {
|
||||
t.Errorf("%q 月份 = %d, 期望 8", wantContent, it.Month)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
t.Errorf("未找到条目: kind=%s content=%q", kind, wantContent)
|
||||
t.Errorf("未找到条目: kind=%s day=%d content=%q", kind, day, wantContent)
|
||||
}
|
||||
assertItem("event", -612, "亚述最后一位君主辛·沙里施昆死于尼尼微,王国灭亡。")
|
||||
assertItem("event", 955, "鄂圖一世麾下的軍隊在萊希菲爾德之戰中取得勝利。")
|
||||
assertItem("event", 0, "某件无法确定年份的事情发生了。")
|
||||
assertItem("event", 2002, "凯尔·斯科特,英國職業足球運動員。")
|
||||
assertItem("festival", 0, "厄瓜多尔:独立日")
|
||||
assertItem("birth", -156, "汉武帝刘彻,西汉皇帝(前87年逝世)")
|
||||
assertItem("festival", 0, "世界狮子日")
|
||||
assertItem("death", 12, -30, "埃及艳后克利奥帕特拉七世逝世")
|
||||
assertItem("birth", 12, 1848, "英国著名小说家乔治·艾略特出生")
|
||||
assertItem("event", 13, 0, "年份非法的事件条目") // 非法年份应为 0
|
||||
assertItem("festival", 13, 0, "国际左撇子日")
|
||||
|
||||
// 不应包含 wiki 语法残留
|
||||
// 不应残留 HTML 标签
|
||||
for _, it := range items {
|
||||
if strings.Contains(it.Content, "[[") || strings.Contains(it.Content, "{{") ||
|
||||
strings.Contains(it.Content, "<ref") {
|
||||
t.Errorf("条目残留 wiki 语法: %q", it.Content)
|
||||
if strings.Contains(it.Content, "<a") || strings.Contains(it.Content, "href") ||
|
||||
strings.Contains(it.Content, "</a>") {
|
||||
t.Errorf("条目残留 HTML 标签: %q", it.Content)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseRealPage 若本地存在真实抓取的样本文件则验证(可选)
|
||||
func TestParseRealPage(t *testing.T) {
|
||||
data, err := os.ReadFile("/tmp/wiki_810.json")
|
||||
if err != nil {
|
||||
t.Skip("无真实样本文件,跳过")
|
||||
func TestParseBaikeYear(t *testing.T) {
|
||||
cases := map[string]int{
|
||||
"1912": 1912,
|
||||
"-30": -30,
|
||||
"0": 0,
|
||||
"abc": 0,
|
||||
"": 0,
|
||||
" 77 ": 77,
|
||||
}
|
||||
var d struct {
|
||||
Parse struct {
|
||||
Wikitext string `json:"wikitext"`
|
||||
} `json:"parse"`
|
||||
for in, want := range cases {
|
||||
if got := parseBaikeYear(in); got != want {
|
||||
t.Errorf("parseBaikeYear(%q) = %d, 期望 %d", in, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizeKind(t *testing.T) {
|
||||
if normalizeKind("event") != "event" || normalizeKind("birth") != "birth" ||
|
||||
normalizeKind("death") != "death" || normalizeKind("other") != "" ||
|
||||
normalizeKind(" EVENT ") != "event" {
|
||||
t.Error("normalizeKind 映射异常")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCleanHTMLText(t *testing.T) {
|
||||
in := `埃及艳后<a target="_blank" href="x">克利奥帕特拉七世</a> 逝世 test`
|
||||
want := "埃及艳后克利奥帕特拉七世 逝世 test"
|
||||
if got := cleanHTMLText(in); got != want {
|
||||
t.Errorf("cleanHTMLText = %q, 期望 %q", got, want)
|
||||
}
|
||||
if err := json.Unmarshal(data, &d); err != nil {
|
||||
t.Fatalf("样本解析失败: %v", err)
|
||||
}
|
||||
items := parseDayPage(d.Parse.Wikitext)
|
||||
if len(items) < 20 {
|
||||
t.Errorf("真实页面解析条目过少: %d", len(items))
|
||||
}
|
||||
t.Logf("真实页面共解析 %d 条", len(items))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user