侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

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

Go  /  管理员 发布于 5年前   252

前言

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

最近工作中有个需求,就是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.诗词句子查找

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

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

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

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

//已知newFind的PreString,求BlankString和PostStringfunc 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和PreStringfunc 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、 前赤壁赋

2、 离骚


项目地址:AncientPoetryFillBlank (本地下载)

总结

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


  • 上一条:
    Go之interface的具体使用
    下一条:
    Go语言中你不知道的Interface详解
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • 近期文章
    • 智能合约Solidity学习CryptoZombie第二课:让你的僵尸猎食(0个评论)
    • 智能合约Solidity学习CryptoZombie第一课:生成一只你的僵尸(0个评论)
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2017-09
    • 2020-03
    • 2020-05
    • 2020-06
    • 2020-07
    • 2020-12
    • 2021-01
    • 2021-05
    • 2021-06
    • 2021-07
    • 2021-08
    • 2021-10
    • 2021-11
    • 2021-12
    • 2022-01
    • 2022-02
    • 2022-03
    • 2022-04
    • 2022-05
    • 2022-06
    • 2022-07
    • 2022-08
    • 2022-09
    • 2022-10
    • 2022-11
    • 2022-12
    • 2023-01
    • 2023-02
    • 2023-03
    • 2023-04
    • 2023-05
    • 2023-06
    • 2023-07
    • 2023-08
    • 2023-09
    • 2023-10
    • 2023-11
    • 2023-12
    • 2024-01
    • 2024-02
    • 2024-03
    • 2024-04
    • 2024-05
    • 2024-06
    • 2024-07
    • 2024-08
    • 2024-11
    • 2025-02
    • 2025-04
    • 2025-05
    • 2025-06
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客