欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-03-07 08:06:58
前言 “白日依山尽,___”。下句自然填黄河入海流,那么“日月忽其不淹兮,___,___,恐美人之迟暮”,中间两句怎么填呢? 最近工作中有个需求,就是1500道语文诗词...

前言

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

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

1. 文章信息获取

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

 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)

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

//如果有多个搜索结果,比对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拿到文章页面,解析出其中的文章。

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()方法中注册即可。

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中,具体的查找算法如下代码所示:

//已知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 (本地下载

总结

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