很多小伙伴发私信问我爬虫具体怎么写。
其实R的爬虫是比较简单的一种,而且效率也很高的。
爬虫初学者对于静态网页无脑爬虫比较熟悉,这种动态网页爬虫,确实需要一些额外的思考在里面。
这篇文章就手把手告诉你如何爬到pubg.op.gg上的非常有用的一些数据。
首先两个爬虫包XML, RCurl先装好。
install.packages("XML")
install.packages("RCurl")
library(XML)
library(RCurl)
之后的工作就是考察玩家页面。还是拿我最喜欢的17_shou举例。
https://pubg.op.gg/user/17_shou?server=sea代表的是17_shou在东南亚服的数据。
所以该网页的格式为:https://pubg.op.gg/user+ "userid" + "?server=" + "serverid"
其中sea就是东南亚服。
话不多说先把静态网页抓下来
Nickname = "17_shou"
server = "sea"
uu <- paste("https://pubg.op.gg/user/",Nickname,"?server=",server,sep = "")
ww <- getURL(uu)
pagetree <- htmlTreeParse(ww, error=function(...){}, useInternalNodes = TRUE, encoding = "UTF-8")
如果你只关心玩家的基本数据,如K/D之类,那一个简单的静态网页爬虫就搞定了,轻松愉快。然而对于这么多有用数据的一个网页如弱水三千,你只取一瓢,有点太不够意思了。
op.gg之所以为用户推崇就是因为他有单场比赛的详细数据,具体到击杀信息和击杀坐标;而其他网站和app都是笼统的数据,甚至把几场比赛合一起算平均,然而那些我在游戏里也能查到,我用你app干啥呢?
所以写这个网站的爬虫,你如果能把单场比赛的数据都搞到,那剩下的场均击杀啊伤害啊什么的还不是手到擒来?
所以。我们的目标是——爬到所有单场比赛的数据。
首先我们发现他这个静态页面只显示20场比赛,我们必然是不答应的,很多人一个赛季几百场比赛你就给我看20场那还不够我做塞牙缝的数据分析。
所以首先要知道比赛的场数。恰恰比赛场数在静态页面上显示,所以也就比较容易了。
直接查看源代码,发现比赛场数存在div节点的名为"game-server__wrap"下。那么爬虫就这么写:
num_of_game <- xpathSApply(pagetree,"//div[@class = game-server__wrap]", xmlValue)
输出的结果显示了所有服务器的比赛信息,格式为:
"\n \n SEA\n SEA\n \n 56 Games\n Pre:\n 42 Games\n \n "
信息里包含了服务器名,当前赛季比赛场数,之前赛季比赛场数。
这里用一下R里的strsplit函数(分割函数),grepl函数(例如上一段信息包含"SEA",那么函数输出就是TRUE)
if (server == "krjp"){
server0 <- "KR/JP"
} else {
server0 <- toupper(server)
}
num_of_game <- as.numeric(gsub([^0-9],,unlist(strsplit(num_of_game[grepl(server0,num_of_game)],split = "Pre"))[1]))
> num_of_game
[1] 56
这样我们就得到了比赛场数56场。(如果要历史所有场次的话,Pre前后两段数据都截出来相加就行)
下面的工作就是这56场比赛的所有信息。
这里就涉及到了动态网页,要借助Google Chrome的开发者工具
在打开的网页点击F12,切换到Network一栏,点击clear清空。
我们首先想打开所有场次,不止局限于20场,所以我们点击一下网页上的"More",
这样观察开发者工具,发现一个Request URL为
https://pubg.op.gg/api/users/59fdb68aafa25600018ca704/matches/recent?server=sea&queue_size=&mode=&after=eyJfaWQiOiI1YTc3ZjQ3OTdiN2Y0YTAwMDExZGJkMWUiLCJzdGFydGVkX2F0IjoxNTE3ODA4ODM4LCJzZWFzb24iOiIyMDE4LTAyIn0%3D
的一个信息。我们当然就可以联想到这是动态网页所连接的静态网页信息。打开该网页,赫然发现了规律记录的各场次的基本信息,包括比赛模式,第一/第三人称,击杀,助攻,治疗数,击杀距离等等等。而且通过比赛数据比较,发现该网页记录的就是第21场 - 第40场的数据。
网页倒是找到了,但这个URL的信息非常杂,似乎完全没有规律,但记住,在web开发里是不存在没有规律的东西的,只要用心去探索。
首先是这一串数59fdb68aafa25600018ca704
我们在原静态网页源代码里搜索这段数,发现它恰恰是"data-u-user-id"的节点名称,那么我们可以想到,这一串看似不规则的数,就是这个玩家在系统里的id表示。提取这一段id的代码为
user_id <- unique(unlist(xpathSApply(pagetree,"//div", xmlGetAttr,data-u-user_id)))
下面就是最后那一串数eyJ......3D" 如何破译了,很多人可能也会卡到这里,很多人可能会考虑RSA加密什么什么的。
其实并不用。
首先我们把这一串数全删了,打开网页
https://pubg.op.gg/api/users/59fdb68aafa25600018ca704/matches/recent?server=sea&queue_size=&mode=&after=
可以发现非常有趣的事实:这恰好是1-20场的场次数据。配合前面的after可以想到,那一大串数应该是第20场比赛的某一个代号,而恰恰好,第20场比赛的offset" 代码,和这一串数完全相同。相似地,如果你把这一串数换成第一场的offset,网页显示就是2-21场的数据集。
到此,这个看似乱七八糟的URL就被我们找到了非常完美的一个规律。
有了这个规律,所有场次信息可以轻松获取(摘取信息过程省略,非常简单)(PS:时间用的是我这里的当地时间,和国内时间13小时时差):
> head(general_data)
player_id score offset
1 17_shou 1663.685 eyJfaWQiOiI1YTdhOGNmNzdlN2I3MjAwMDFmMGIwMDYiLCJzdGFydGVkX2F0IjoxNTE3OTc4OTQ2LCJzZWFzb24iOiIyMDE4LTAyIn0=
2 17_shou 1688.024 eyJfaWQiOiI1YTdhOGIxMjU3N2NhZjAwMDEyMThhZDMiLCJzdGFydGVkX2F0IjoxNTE3OTc4NDM0LCJzZWFzb24iOiIyMDE4LTAyIn0=
3 17_shou 1688.024 eyJfaWQiOiI1YTdhODdmMGQyMDM0YjAwMDFiNDI4NmIiLCJzdGFydGVkX2F0IjoxNTE3OTc3Nzk3LCJzZWFzb24iOiIyMDE4LTAyIn0=
4 17_shou 1719.484 eyJfaWQiOiI1YTdhODdmMDY0ODJlYjAwMDEyYWRhYmMiLCJzdGFydGVkX2F0IjoxNTE3OTc3NTQyLCJzZWFzb24iOiIyMDE4LTAyIn0=
5 17_shou 1731.739 eyJfaWQiOiI1YTdhODUyODJhNDQ4MzAwMDFjNzY5NjkiLCJzdGFydGVkX2F0IjoxNTE3OTc3MDE2LCJzZWFzb24iOiIyMDE4LTAyIn0=
6 17_shou 1754.707 eyJfaWQiOiI1YTdhODNkNjU3N2NhZjAwMDEyMGNkNDgiLCJzdGFydGVkX2F0IjoxNTE3OTc2NzQ1LCJzZWFzb24iOiIyMDE4LTAyIn0=
match_id match_mode queue_size
1 Svg7Thpx__N3LAxphvieh7RnsU2LLRxYsNcygPRHqLjLKVo7JgqiTg3hV3XfRvN_eJtjCrg_4eYonEvwW7b76wXwosiDi3WCSTEvKP16FFY= tpp 1
2 Svg7Thpx__N3LAxphvieh0qCD5Sc-6bWZdku6NeFwz5PK7Al-dJf0-8aaqjeUN5bYL2E-bX57VOFv2GDvfR0yMu01Fx7wp8wMVE4YddF1qw= tpp 1
3 Svg7Thpx__N3LAxphvieh-xkDJj3AH9oSl1JuVSWY8CKbSATl6xhIYUWHh_jezlbR8n9cAZ9ENH47xQB7f0S64EsohYMF9y-V5dcuSg1i2k= tpp 1
4 Svg7Thpx__N3LAxphvieh-xkDJj3AH9osDqgEzg3SA5GDAPypAkzxfQiq9sRU3HC_OgRg3jFy-m3kI1KCOMwJ8V5_OHkkkyNoge8r3sfR00= tpp 1
5 Svg7Thpx__N3LAxphvieh9vlo6cM0gJIBqw8xDxMXE1O_jjLgSiE3r8kcLOwGl6Kgbn-K4o3cajreJosgXKZH7qC6xhalLWl1nEWJ6JXrtI= tpp 1
6 Svg7Thpx__N3LAxphviehxkmJikvCpMZ6W2dRf5Px5VfCeZpjepk6oRGYvw1-EnCn9Ryn-f-PuGbhv4BkP6Lxec1XOajW32RZdA0kk2xwio= tpp 1
gametime score_diff total_rank player_rank damage kill headshot_kill longest_kill assist survive_time walk_distance ride_distance
1 2018-02-07 04:49:06 -9.959851 96 53 460.56076 5 0 125.213753 0 286.500 414.53674 0.0000
2 2018-02-07 04:40:34 -24.339095 97 61 0.00000 0 0 0.000000 0 317.807 330.93740 912.9656
3 2018-02-07 04:29:57 0.000000 87 86 99.99999 1 0 4.314449 0 86.090 0.00000 0.0000
4 2018-02-07 04:25:42 -31.459985 92 85 0.00000 0 0 0.000000 0 116.516 61.01707 0.0000
5 2018-02-07 04:16:56 -12.255245 87 47 686.06494 7 2 49.049400 0 366.950 337.03137 0.0000
6 2018-02-07 04:12:25 -22.968219 93 68 189.23682 3 0 35.508377 0 156.993 133.78761 0.0000
到此,一个完整的本赛季玩家各场次基本信息就完成了。
下面就是更好玩的数据了,各场次玩家击杀信息数据。当然了,此处也涉及到动态网页爬虫技巧。
回到最开始的网页,F12打开开发者工具,清空,之后点击第一场右侧对应的展开图标(就是能看具体击杀信息那个),然后还是查看network,发现其定向链接到了几个Request URL上。
我们这里有两个信息关联于本场比赛。一个是
https://pubg.op.gg/api/matches/Svg7Thpx__N3LAxphvieh7RnsU2LLRxYsNcygPRHqLjLKVo7JgqiTg3hV3XfRvN_eJtjCrg_4eYonEvwW7b76wXwosiDi3WCSTEvKP16FFY%3D
这个URL记录了该场比赛所有玩家表现。
另一个是
https://pubg.op.gg/api/matches/Svg7Thpx__N3LAxphvieh7RnsU2LLRxYsNcygPRHqLjLKVo7JgqiTg3hV3XfRvN_eJtjCrg_4eYonEvwW7b76wXwosiDi3WCSTEvKP16FFY%3D/deaths这个就更厉害了,这个是该场比赛的全部击杀信息,包括武器,击杀坐标等等。
而那一大串"Svg...%3D"看似杂乱其实非常眼熟,这恰恰就是刚才我们爬到的各场次数据里的match_id。
通过对数据的简单处理,提取有用信息,我们就可以获得该场比赛的所有击杀数据。
> head(match_info)
match_id map time_event is_range_valid
1 Svg7Thpx__N3LAxphvieh7RnsU2LLRxYsNcygPRHqLjLKVo7JgqiTg3hV3XfRvN_eJtjCrg_4eYonEvwW7b76wXwosiDi3WCSTEvKP16FFY= ERANGEL 1543 true
2 Svg7Thpx__N3LAxphvieh7RnsU2LLRxYsNcygPRHqLjLKVo7JgqiTg3hV3XfRvN_eJtjCrg_4eYonEvwW7b76wXwosiDi3WCSTEvKP16FFY= ERANGEL 77 true
3 Svg7Thpx__N3LAxphvieh7RnsU2LLRxYsNcygPRHqLjLKVo7JgqiTg3hV3XfRvN_eJtjCrg_4eYonEvwW7b76wXwosiDi3WCSTEvKP16FFY= ERANGEL 109 true
4 Svg7Thpx__N3LAxphvieh7RnsU2LLRxYsNcygPRHqLjLKVo7JgqiTg3hV3XfRvN_eJtjCrg_4eYonEvwW7b76wXwosiDi3WCSTEvKP16FFY= ERANGEL 316 true
5 Svg7Thpx__N3LAxphvieh7RnsU2LLRxYsNcygPRHqLjLKVo7JgqiTg3hV3XfRvN_eJtjCrg_4eYonEvwW7b76wXwosiDi3WCSTEvKP16FFY= ERANGEL 965 true
6 Svg7Thpx__N3LAxphvieh7RnsU2LLRxYsNcygPRHqLjLKVo7JgqiTg3hV3XfRvN_eJtjCrg_4eYonEvwW7b76wXwosiDi3WCSTEvKP16FFY= ERANGEL 360 true
description victim_name victim_x victim_y killer_name killer_x killer_y distance
1 SCAR-L MasterKin6 468172.1 353564.9 niwangbaba520 469735.9 358853.6 55.1505377398985
2 S686 No-gun_So-Punch 456419.9 629486.0 douyu-3821776 456574.9 629685.8 2.52873565245596
3 S686 Forest-Jiang 450092.9 624182.3 xia199003 450048.3 622553.4 16.2951046943555
4 AKM hexuan 388991.9 341491.9 DrA_KImR 391399.1 341809.8 24.2810054363483
5 SCAR-L Thesungod1 162092.1 293967.1 AluckyBoY_ 162248.1 294106.3 2.09075680077821
6 AKM guiguijun 445004.8 627553.1 dzcao1m2 445146.6 627954.3 4.25521656323216
最后整合数据,进一步分析的工作,就可以慢慢在可视化工具以及统计软件里运行啦~ 这也就是我上一篇文章,以及NGA论坛的数据分析帖子的爬虫工具基础。
就介绍到这里,以后会继续写有意思的话题。欢迎大家讨论。
声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:704559159@qq.com