go语言爬虫 - TapTap用户都喜欢些什么游戏

前面的废话

说到爬虫,首先想到的当然是python~ 它在机器学习、爬虫数据分析领域可谓是如日中天,十分热门。但我最近在学习go语言,所以就用go写了

TapTap社区

这是一个高品质的游戏分享社区,可以说是手机上的steam。上面的用户质量非常高,核心玩家多,看到他们那么用心的写那么多长评论,让我惊叹,所以这次打算拿它来爬取数据练练手,下面先看看成果

先看效果,这里的玩家,都喜欢玩啥类型游戏呀?

根据 下载榜 里游戏标签的词频统计出:

发现单机、二次元、MOBA、策略等标签比较突出

让我们加入玩家评分的权重,评分是根据数以万计的玩家打的分数来的,多个游戏相同标签会求平均值。
看看有什么变化?

词云完全不一样了呢,视觉错位、脑洞、哲理等标签的评分较高,这些才是玩家真实的喜好,为啥加入评分权重变化这么大呢,让我们看一下究竟是哪些游戏评分这么高!

原来是纪念碑谷、猿骑、艾希等游戏。而纪念碑谷(tag:视觉错位)的评分竟然达到了10分!!(7951条评价)

不过这款游戏也确实让我服气,连我妈妈、老婆她们不太玩游戏的,都很喜欢这款游戏呢~


那么下面就都把评分权重加进去,看看玩家心里的真实需求

接着分析新品榜

游戏名称(根据排名权重+评分权重)

看看我们分析出来的跟榜单上的有什么不一样?

可以看到,加入评分权重后,像《我叫MT4》、《王牌战争:代号英雄》这种虽然排名靠前,但是口碑很差的游戏,几乎在我们的分析图上就看不见啦。(所以在taptap上,就算你花钱刷榜上去了,也并没有太多用,玩家的眼睛是雪亮的,哈哈哈)

预约榜


游戏名称(根据排名权重+评分权重)

这里可以看出未来市场的玩家需求,《全职觉醒》、《堡垒之夜》等都是期待比较高的

热玩榜

游戏名称(根据排名权重+评分权重)

《绝地求生、刺激战场》也是突出游戏之一,看来taptap的玩家,也是很喜欢吃鸡的

实现方式

goquery解析html
iconv-go进行编码转换
sego用来中文分词
wordart实现词云效果

现在先做了个简单的版本,完整版是还想实现抓取某个游戏的玩家评论,进行分词,情感分析的。

先分析html结构,找到一个游戏信息里包含哪些html元素,然后用goquery解析

使用谷歌浏览器,按F12可以很方便的找到元素哦

然后定义一个结构体,用来存放数据

type GameInfo struct {Rank     int      //排名TapTapID string   //游戏IDName     string   //游戏名Company  string   //公司名Score    float64  //游戏评分IconUrl  string   //图标地址Type     string   //游戏类型tags     []string //标签
}

分析单个游戏信息

//解析一个游戏信息
func ParseGameInfoCell(selection *goquery.Selection) {gameInfo := GameInfo{}nameA := selection.Find(".card-middle-title ")gameInfo.TapTapID = nameA.AttrOr("href", "")gameInfo.TapTapID = gameInfo.TapTapID[strings.LastIndex(gameInfo.TapTapID, "/")+1:]gameInfo.Name = nameA.Find("h4").Text()gameInfo.Company = selection.Find(".card-middle-author").Find("a").Text()score, _ := strconv.ParseFloat(selection.Find(".middle-footer-rating").Find("span").Text(), 64)gameInfo.Score = scoregameInfo.IconUrl = selection.Find(".card-left-image").Find("img").AttrOr("src", "")tempRank, _ := strconv.ParseInt(selection.Find(".top-card-order-text").Text(), 10, 32)gameInfo.Rank = int(tempRank)gameInfo.Type = selection.Find(".card-middle-footer").Find("a").Text()tagsAList := selection.Find(".card-tags").Find("a")tagsAList.Each(func(i int, selectionA *goquery.Selection) {gameInfo.tags = append(gameInfo.tags, selectionA.Text())})GameInfoList = append(GameInfoList, gameInfo)//fmt.Printf("%v\n", gameInfo)
}

但是很快就遇到了问题,因为排行榜的数据是分页的,我们请求一次只能得到30条数据,于是我们找到了“更多”按钮,发现里面通过ajax异步的请求了一条链接获取数据。

https://www.taptap.com/ajax/top/played?page=2&total=30

page就代表的页数,根据排行榜总数量150,每页30条可以得出一共有5页。这样我们就可以循环5次去请求所有的数据了

func ReqRankPage(page int) {res, err := http.Get("https://www.taptap.com/ajax/top/" + rankTypeName + "?page=" + strconv.Itoa(page))if err != nil {log.Fatal(err)}defer res.Body.Close()if res.StatusCode != 200 {log.Fatalf("status code error: %d %s", res.StatusCode, res.Status)}jsonBs, err := ioutil.ReadAll(res.Body)tPageJson := TPageJson{}err = json.Unmarshal(jsonBs, &tPageJson)if err != nil {fmt.Println("解析json错误", err)}var htmlRead io.Reader = strings.NewReader(tPageJson.Data.Html)doc, err := goquery.NewDocumentFromReader(htmlRead)if err != nil {log.Fatal(err)}doc.Find(".taptap-top-card").Each(func(i int, selection *goquery.Selection) {ParseGameInfoCell(selection)})
}

全部代码

package mainimport ("bytes""encoding/json""fmt""github.com/PuerkitoBio/goquery""io""io/ioutil""log""net/http""strconv""strings""math"
)type TPageJson struct {Success bool          `json:"success"`Data    TPageDataJson `json:"data"`
}type TPageDataJson struct {Html string `json:"html"`Next string `json:"next"`
}type GameInfo struct {Rank     int      //排名TapTapID string   //游戏IDName     string   //游戏名Company  string   //公司名Score    float64  //游戏评分IconUrl  string   //图标地址Type     string   //游戏类型tags     []string //标签
}var GameInfoList []GameInfo
var rankTypeName = "reserve"var rankTypes = []string{"download", "new", "reserve", "sell", "played"}func main() {for _, typeName := range rankTypes {GameInfoList = []GameInfo{}rankTypeName = typeName//每个排行榜有5页数据(根据总数150条,每页30条得出)for i := 1; i <= 5; i++ {ReqRankPage(i)}//生成标签词典GenerateTags()GenerateGameNames()fmt.Println("生成排行榜:", rankTypeName, "完毕")}
}func GenerateGameNames() {var tagsBuffer bytes.BuffertagsBuffer.WriteString("word;weight\n")for _, gameInfo := range GameInfoList {//weightSize := 150 - gameInfo.Rank //把排名的权值加上//weightSize := int(math.Ceil(float64(150-gameInfo.Rank) * gameInfo.Score)) //把排名的权值加上weightSize := int(math.Ceil(gameInfo.Score*100)) //把排名的权值加上tagsBuffer.WriteString(gameInfo.Name)tagsBuffer.WriteString(";")tagsBuffer.WriteString(strconv.Itoa(weightSize))tagsBuffer.WriteString("\n")}WriteFile(rankTypeName+"_names_score.csv", tagsBuffer.String())
}func GenerateTags() {tagsCountDic := make(map[string]int)tagsScoreDic := make(map[string]float64)var tagsBuffer bytes.BuffertagsBuffer.WriteString("word;weight;")for _, gameInfo := range GameInfoList {for _, tag := range gameInfo.tags {tagsCountDic[tag]++tagsScoreDic[tag] += gameInfo.Score*100}}for key, value := range tagsCountDic {tagsBuffer.WriteString(key)tagsBuffer.WriteString(";")//tagsBuffer.WriteString(strconv.Itoa( value))tagsBuffer.WriteString(strconv.Itoa( int(tagsScoreDic[key]/float64(value))))tagsBuffer.WriteString("\n")}WriteFile(rankTypeName+"_tags_score.csv", tagsBuffer.String())
}func WriteFile(name, content string) {data := []byte(content)if ioutil.WriteFile(name, data, 0644) == nil {fmt.Println("写入文件成功:", name)}
}func ReqRankPage(page int) {res, err := http.Get("https://www.taptap.com/ajax/top/" + rankTypeName + "?page=" + strconv.Itoa(page))if err != nil {log.Fatal(err)}defer res.Body.Close()if res.StatusCode != 200 {log.Fatalf("status code error: %d %s", res.StatusCode, res.Status)}jsonBs, err := ioutil.ReadAll(res.Body)tPageJson := TPageJson{}err = json.Unmarshal(jsonBs, &tPageJson)if err != nil {fmt.Println("解析json错误", err)}var htmlRead io.Reader = strings.NewReader(tPageJson.Data.Html)doc, err := goquery.NewDocumentFromReader(htmlRead)if err != nil {log.Fatal(err)}doc.Find(".taptap-top-card").Each(func(i int, selection *goquery.Selection) {ParseGameInfoCell(selection)})
}//解析一个游戏信息
func ParseGameInfoCell(selection *goquery.Selection) {gameInfo := GameInfo{}nameA := selection.Find(".card-middle-title ")gameInfo.TapTapID = nameA.AttrOr("href", "")gameInfo.TapTapID = gameInfo.TapTapID[strings.LastIndex(gameInfo.TapTapID, "/")+1:]gameInfo.Name = nameA.Find("h4").Text()gameInfo.Company = selection.Find(".card-middle-author").Find("a").Text()score, _ := strconv.ParseFloat(selection.Find(".middle-footer-rating").Find("span").Text(), 64)gameInfo.Score = scoregameInfo.IconUrl = selection.Find(".card-left-image").Find("img").AttrOr("src", "")tempRank, _ := strconv.ParseInt(selection.Find(".top-card-order-text").Text(), 10, 32)gameInfo.Rank = int(tempRank)gameInfo.Type = selection.Find(".card-middle-footer").Find("a").Text()tagsAList := selection.Find(".card-tags").Find("a")tagsAList.Each(func(i int, selectionA *goquery.Selection) {gameInfo.tags = append(gameInfo.tags, selectionA.Text())})GameInfoList = append(GameInfoList, gameInfo)//fmt.Printf("%v\n", gameInfo)
}

这样就可以把爬取下来的数据,写成文件,生成出一张张的词云进行分析啦

总结

第一次玩爬虫,所以写的不是很好,爬虫还有很多技术,本文里都没有涉及。如防止反爬,账号登陆等。写这个也是想多写一点go代码,以后可能会把go作为我的主语言进行开发

接下来研究下爬取网易云音乐~ 嘿嘿嘿

posted @ 2018-07-30 00:11 李嘉的博客 阅读(...) 评论(...) 编辑 收藏

go语言爬虫 - TapTap用户都喜欢些什么游戏相关推荐

  1. 为什么多迪技术人员都喜欢用python写爬虫?

    有更加成熟的一种爬虫脚本语言,而非框架.是通用的爬虫软件ForeSpider,内部自带了一套爬虫脚本语言.很多同学学php的,但是也自学过python,对php了解还是比较深的,为什么多迪技术人员都喜 ...

  2. Java语言开发在线音乐推荐网 音乐推荐系统 网易云音乐爬虫 基于用户、物品的协同过滤推荐算法 SSM(Spring+SpringMVC+Mybatis)框架 大数据、人工智能、机器学习项目开发

    Java语言开发在线音乐推荐网 音乐推荐系统 网易云音乐爬虫 基于用户.物品的协同过滤推荐算法 SSM(Spring+SpringMVC+Mybatis)框架 大数据.人工智能.机器学习项目开发Mus ...

  3. 使用Java语言开发在线电影推荐网 电影推荐系统 豆瓣电影爬虫 基于用户、物品的协同过滤推荐算法实现 SSM(Spring+SpringMVC+Mybatis)开发框架 机器学习、人工智能、大数据开发

    使用Java语言开发在线电影推荐网 电影推荐系统 豆瓣电影爬虫 基于用户.物品的协同过滤推荐算法实现 SSM(Spring+SpringMVC+Mybatis)开发框架 机器学习.人工智能.大数据开发 ...

  4. html歌曲朋友圈,为何有的人喜欢在朋友圈里分享歌曲,他们都是些什么人?长见识了...

    Hi,老铁们!感谢你们能点开小编的文章,希望大家喜欢小编写的文章.可以的话,动动手指点点关注把文章转发出去,支持一下小编.在此祝各位老铁们天天好心情,事事都如意. 为何有的人喜欢在朋友圈里分享歌曲,他 ...

  5. 招聘java是什么意思_java程序员,一般招聘都要求些啥

    原标题:java程序员,一般招聘都要求些啥 java程序员,一般招聘都要求些啥?某位企业领导说,他不能确认什么样的人一定是他想要的,因为优秀的程序员精通的点并不完全相同,项目也千差万别,但至少要有几个 ...

  6. 《互联网+ 电商平台设计与运营》一一2.1 你的用户在想些什么

    本节书摘来自异步社区出版社<互联网+ 电商平台设计与运营>一书中的第2章,第2.1节,作者: 郝宪玮 , 卢文隆,更多章节内容可以访问云栖社区"异步社区"公众号查看. ...

  7. 程序员们平时都喜欢逛什么论坛呢?

    职业经理人 看到有人问程序员都喜欢逛哪些论坛,那我就来总结一下. 0. GitHub - 开发者最最最重要的网站:https://github.com 这个不用多说了吧,代码托管网站,上面有很多资源, ...

  8. [No0000197]Windows用户都应该知道的运行命令

    通过"运行"命令,运行Windows丰富工具的方法.如果您知道工具或任务的相应"运行"命令,那么您就知道访问所述工具或任务的最快方法. 以下是我们最喜欢的Run ...

  9. 线程库 c语言实现,130行C语言实现个用户态线程库——后续(一)

    130行C语言实现个用户态线程库--后续(1) ezCoroutine协程原型库只是个原型库,但是已经能够支持1000K以上数量的协程运行,而且是stackful模式.基本的对外接口有两类,一类是类似 ...

  10. python 今日头条 微头条_今日头条微头条范文-头条号的微头条你们都发些什么,该如何写?...

    头条号的微头条你们都发些什么,该如何写? 心灵相约头条号.呼唤着,努力着,拼搏着,它属于努力地人们,是传播正能量的家园.今天起要根扎头条号,写出优秀地原创作品.头条号的朋友们努力吧!用心血和汗水浇灌头 ...

最新文章

  1. 深度解析AIoT背后的发展逻辑
  2. C++11系列学习之四----auto
  3. 33:计算分数加减表达式的值
  4. 小程序如何传数组数据到vs后台中
  5. 【LeetCode笔记】剑指 Offer 26-. 树的子结构 (Java、双重dfs、二刷)
  6. python中dtype什么意思_浅谈python 中的 type(), dtype(), astype()的区别
  7. 25linux运行级别26如何找到root密码?27linux下面帮助指令
  8. 三星Galaxy S22或放弃Exynos 2200?假消息!依旧双版本
  9. 木兰许可证专业解读及首批采用“木兰”开源项目列表
  10. 进销存excel_excel进销存管理系统
  11. 计算机软件故障排除ppt,计算机基础知识及常见故障排除.ppt
  12. Vmware虚拟机桥接模式设置
  13. 如何解决VMware Workstation上ubuntu出现Host SMbus controller not enabled
  14. SAP 中的货币(Currencies)
  15. 2、SpringBoot接口Http协议开发实战8节课(7-8)
  16. 后疫情时代品牌何去何从:营销机会就藏在百度的这些搜索大数据里
  17. 一个很精致的HelloWorld,你看得懂么?
  18. Echarts折线图X轴Y轴图例位置调整
  19. spark进行数据清洗时,如何读取xlsx表格类型文件
  20. Jmeter之事务控制器

热门文章

  1. 想你的风还是吹到了长沙
  2. 伺服舵机匀加速和匀减速运动Demo
  3. 各种dns:百度DNS/阿里DNS/114DNS/腾讯DNS/谷歌DNS/OpenDNS 对比评测
  4. php怎么触发js函数,如何从PHP调用JavaScript函数?
  5. JAVA中Long与Integer踩的坑
  6. 动物基因组测序基础分析流程总结(GWAS全流程第一部分:WGS基础流程)
  7. vim - 格式化JSON
  8. mac 微信不能设置代理服务器,mac微信能用但是浏览器上不了网
  9. 95后00后音乐人群已成原创音乐创作主力军;全球游戏品类App留存率下滑10% | 美通社头条...
  10. php未来发展前景如何