脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服务器之家 - 脚本之家 - Golang - Go语言实现自动填写古诗词实例代码

Go语言实现自动填写古诗词实例代码

2020-05-14 10:00FengY Golang

这篇文章主要给大家介绍了关于Go语言实现自动填写古诗词的相关资料,这是最近在项目中遇到的一个需求,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面随着小编来一起学习学习吧。

前言

“白日依山尽,___”。下句自然填黄河入海流,那么“日月忽其不淹兮,___,___,恐美人之迟暮”,中间两句怎么填呢?

最近工作中有个需求,就是1500道语文诗词填空题没有答案,现在需要给这些题目大爷们匹配它们对应的答案,好在题目信息都很完整,指出了诗词出处、作者信息。自然想到到网上爬取对应文章信息然后字符串匹配答案。目前做完,效果还可以,基本上所有题目的答案都有了,现把操作流程记录下,做个总结。

1. 文章信息获取

网上找了很久,目前发现百度汉语对古诗词收录的比较好,格式也比较规范,整个爬取过程还是比较简单,浏览器分析网站,找到它们的搜索接口:http://hanyu.baidu.com/hanyu/ajax/sugs只需要传一个参数:mainkey,是一个urlencode格式的字符串。接口会返回一个匹配列表,再用作者名称对这个列表做筛选,详细代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
baseUrl := "http://hanyu.baidu.com/hanyu/ajax/sugs?"
client := &http.Client{
}
u, _ := url.Parse(baseUrl)
q := u.Query()
q.Set("mainkey", name)
u.RawQuery = q.Encode()
 
//添加Header
req, _ := http.NewRequest("GET", u.String(), nil)
req.Header.Add("User-Agent", `Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36`)
req.Header.Add("DNT", "1")
req.Header.Add("Host", "hanyu.baidu.com")
req.Header.Add("Accept-Language", "zh-CN,zh;q=0.8")
req.Header.Add("Referer", "http://hanyu.baidu.com/shici/detail?pid=be520db056da43238035dc18bb1e1798&tn=sug_click")
 
resp, errDo := client.Do(req)

拿到返回值以后,筛选出对应的作者信息。

?
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
//如果有多个搜索结果,比对author是否正确
 respJson.ForEach(func(key, value gjson.Result) bool {
 //先看看有没有display_name
 displayName := value.Get("display_name.0").String()
 sid := value.Get("sid.0").String()
 if len(displayName) == 0 {
 //不是这条记录
 return true
 }
 
 //看看type
 typeStr := value.Get("type.0").String()
 if typeStr == "poemline"{
 //取Source
 displayName = value.Get("source_poem.0").String()
 sid = value.Get("source_poem_sid.0").String()
 }
 
 literatureAuthor := value.Get("literature_author.0").String()
 //author是否一致
 if literatureAuthor == author {
 searchResult.Sid = sid
 searchResult.DisplayName = displayName
 searchResult.Author = literatureAuthor
 return false
 }
 return true // keep iterating
 })

SearchResult保存了搜索到的结果,根据sid拿到文章页面,解析出其中的文章。

?
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
func GetContent(sid string) (content string, err error) {
 baseUrl := "http://hanyu.baidu.com/shici/detail"
 
 result := make([]string, 0, 0)
 client := &http.Client{
 }
 
 u, _ := url.Parse(baseUrl)
 q := u.Query()
 q.Set("pid", sid)
 u.RawQuery = q.Encode()
 
 req, _ := http.NewRequest("GET", u.String(), nil)
 req.Header.Add("User-Agent", `Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36`)
 req.Header.Add("DNT", "1")
 req.Header.Add("Host", "hanyu.baidu.com")
 req.Header.Add("Accept-Language", "zh-CN,zh;q=0.8")
 req.Header.Add("Referer", "http://hanyu.baidu.com/shici/detail?pid=be520db056da43238035dc18bb1e1798&tn=sug_click")
 
 resp, errDo := client.Do(req)
 
 if errDo != nil || resp.StatusCode != 200 {
 err = errors.New("无法连接百度汉语 " + errDo.Error())
 return
 }
 
 docm, errDoc := goquery.NewDocumentFromResponse(resp)
 
 if errDoc != nil {
 err = errors.New("解析Doc错误 " + errDoc.Error())
 return
 }
 
 //诗词信息都保存在 body_p 的div中,可以通过PuerkitoBio/goquery库获取
 pSelect := docm.Find("#body_p")
 pSelect.Each(func(pos int, selection *goquery.Selection) {
 content := strings.TrimSpace(selection.Text())
 result = append(result, content)
 })
 
 content = strings.Join(result, "")
 return
}

目前会爬取百度汉语、古诗词两个网站的数据,如果有更好的数据源,只需要实现Spider接口,在MapSpiderManifest()方法中注册即可。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
type Spider interface {
 GetContent(SearchResult) (string, error)
 FindContent(string, string) (SearchResult, error)
}
 
func MapSpiderManifest() map[string]Spider {
 //初始化并且注册所有的Spider
 spiderMap := make(map[string]Spider)
 
 //百度
 baiduSpider := new(BaiduSpider)
 spiderMap["baiduSpider"] = baiduSpider
 
 //古诗文网
 gushiwenSpider := new(GushiwenSpider)
 spiderMap["gushiwenSpider"] = gushiwenSpider
 return spiderMap
}

2.诗词句子查找

古诗文默写,以前上学的时候做的多了,把一句话抠出来,随机选其中几段话让学生默写。一般可以归类为一下几种模式:

开头留空 :_,[_,...],何人不起故园情。
末尾留空:俱往矣,_,[_,...]。
中间留空:月出于东山之上,_,白露横江,

不管是什么样的模式,就每个填空处来看,只有它前面或者后面有提示句,我们才能知道这个空的答案是什么。也就是说,这样的填空可以自主的找到答案,姑且称之为自主空。而前后都没有提示句的空,只能等待附近有自主空找到了答案,才能找到它本身的答案,用一个图说明更加清晰:

Go语言实现自动填写古诗词实例代码

图中灰色的块因为有提示句,所以可以通过步骤一种爬取下来的文章内容找到对应的答案,填入Blank中,具体的查找算法如下代码所示:

?
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
//已知newFind的PreString,求BlankString和PostString
func makeWithPreContent(contentsSplit []string, newFind *Find) {
 for l := range contentsSplit {
 if isEqual(contentsSplit[l], newFind.PreString) && l < len(contentsSplit)-1 {
 newFind.BlankString = contentsSplit[l+1]
 if l < len(contentsSplit)-2 {
 newFind.PostString = contentsSplit[l+2]
 }
 newFind.BlankFinish = true
 }
 }
}
 
//已知newFind的PostString,求BlankString和PreString
func makeWithPostContent(contentsSplit []string, newFind *Find) {
 for l := range contentsSplit {
 if isEqual(contentsSplit[l], newFind.PostString) && l > 0 {
 newFind.BlankString = contentsSplit[l-1]
 if l-1 > 0 {
 newFind.PreString = contentsSplit[l-2]
 }
 newFind.BlankFinish = true
 }
 }
}
 
// 按标点符号分隔内容
func SplitByPunctuation(s string) ([]string, []string) {
 regPunctuation, _ := regexp.Compile(`[,,。.??!!;;::]`)
 //匹配标点符号,保存下来。 然后分割字符串
 toPun := regPunctuation.FindAllString(s, -1)
 result := regPunctuation.Split(s, -1)
 
 if len(result[len(result)-1]) == 0 {
 result = result[:len(result)-1]
 }
 
 //去掉前后空格,去掉引号
 for i := range result {
 result[i] = strings.TrimSpace(result[i])
 regQuoting := regexp.MustCompile("[“”‘'']")
 result[i] = regQuoting.ReplaceAllString(result[i], "")
 }
 return result, toPun
}

所有的自主块都找到答案后,可以把每个自主块看作一个双向链表的表头,我们所要做的就是遍历每个双向链表,把其中每个节点的答案都通过查找算法找出来。当下一个节点是NULL,或者下个节点是一个自主块时,就停止遍历,处理下一个双向链表。这样,无论给出的需要填空的内容多么复杂,都可以顺利的完整自动填写工作。

3.效果

一些常用的文言文或诗词:

1、 前赤壁赋

Go语言实现自动填写古诗词实例代码

2、 离骚

Go语言实现自动填写古诗词实例代码

项目地址:AncientPoetryFillBlank

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对服务器之家的支持。

原文链接:https://juejin.im/post/5a9f33ee518825558a0620d3

延伸 · 阅读

精彩推荐
  • GolangGO语言字符串处理Strings包的函数使用示例讲解

    GO语言字符串处理Strings包的函数使用示例讲解

    这篇文章主要为大家介绍了GO语言字符串处理Strings包的函数使用示例讲解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步早日升职加...

    Jeff的技术栈6882022-04-14
  • GolangGo语言range关键字循环时的坑

    Go语言range关键字循环时的坑

    今天小编就为大家分享一篇关于Go语言range关键字循环时的坑,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来...

    benben_20154202020-05-23
  • GolangGo语言实现自动填写古诗词实例代码

    Go语言实现自动填写古诗词实例代码

    这篇文章主要给大家介绍了关于Go语言实现自动填写古诗词的相关资料,这是最近在项目中遇到的一个需求,文中通过示例代码介绍的非常详细,需要的朋...

    FengY5862020-05-14
  • GolangGo语言基础单元测试与性能测试示例详解

    Go语言基础单元测试与性能测试示例详解

    这篇文章主要为大家介绍了Go语言基础单元测试与性能测试示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助祝大家多多进步...

    枫少文7812021-12-05
  • GolangGolang 语言极简类型转换库cast的使用详解

    Golang 语言极简类型转换库cast的使用详解

    本文我们通过 cast.ToString() 函数的使用,简单介绍了cast 的使用方法,除此之外,它还支持很多其他类型,在这没有多多介绍,对Golang 类型转换库 cast相关知...

    Golang语言开发栈6112021-12-02
  • Golanggo语言获取系统盘符的方法

    go语言获取系统盘符的方法

    这篇文章主要介绍了go语言获取系统盘符的方法,涉及Go语言调用winapi获取系统硬件信息的技巧,具有一定参考借鉴价值,需要的朋友可以参考下 ...

    无尽海3862020-04-24
  • Golang深入浅析Go中三个点(...)用法

    深入浅析Go中三个点(...)用法

    这篇文章主要介绍了深入浅析Go中三个点(...)用法,需要的朋友可以参考下...

    踏雪无痕SS6472021-11-17
  • GolangGolang实现四种负载均衡的算法(随机,轮询等)

    Golang实现四种负载均衡的算法(随机,轮询等)

    本文介绍了示例介绍了Golang 负载均衡的四种实现,主要包括了随机,轮询,加权轮询负载,一致性hash,感兴趣的小伙伴们可以参考一下...

    Gundy_8442021-08-09