0.被血源狂虐的我决定出来报复社会了
1.思路
从主页的所有游戏中获取各游戏的详细测评页面
打开主页面后:
①找到这个游戏所属的平台(后来采用了一种很捷报蛋疼的方法,好在电脑任劳任怨什么都帮我干了
②游戏名称
③游戏的各种评价
④网站自动算出的游戏评分
#或许还应该搞个排名?
#有点内容的比如说新游戏排名,类别排名
⑤游戏发售的时间
把上述内容存入dict中以便查阅
整理数据后提取所有评论,存入一个txt中
21
首先我们要整理一下这些属性的关系:
从首页提取的信息大概遵循这样的规则
game,ps4,8.0,2017-1-1
game,steam,8.0,2017-1-1
game1,switch,9.0,2017-1-2
........
游戏的名字只有一个,发售时间和评分也只有一个,但是平台却不是只有一个。我们所要做的就是把游戏时间评分绑定在一起,用set()去掉重复的部分同时,还要把平台叠加起来。……然后就可以发现这操作起来很麻烦。那怎么办呢,自然是在获取信息的时候就进行筛选,筛选完了再放进去。
platform_list=['ps4','xbox one','Switch','Steam','ios','android','客户端游戏']
def get_platform(number):
return platform_list[int(number)-1]
由于在游戏页面中显示平台的那个标签没什么特点,只能用nga分类游戏时记录了,它本身的界面就是http://game.nga.cn/all?platform=1
这样格式的。(其中1代表ps4,2表示xbox以此类推)
搞定了这个游戏分类的难题后,就正式开始爬数据。7个平台的游戏下又有分页面,就简单用for循环遍历获取所有数据。
gamedict={}
for url_platform in ['http://game.nga.cn/all?platform={}'.format(i) for i in range(1,8)]:
for pages in [url_platform+'&page={}'.format(i) for i in range(1,20)]:
listsoup=BeautifulSoup(requests.get(pages,proxies=proxies,headers=headers).content,'lxml')
if listsoup.find('div', class_='noItem')==True:
break
for game in listsoup.find_all(target='_blank',class_=''):
name = game.get_text()
platform = get_platform(url_platform[-1])
score = game.parent.find_next_sibling('div',class_='num').get_text()
time = game.parent.find_next_sibling('div',class_='time').get_text().strip('发售')
url = game.get('href')
这里必须要赞美一下伟大的beautifulsoup模块,也太好用了吧。
nga的结构是这个样子的:
<div class="blockItem addBorder">
<a class="pic" href="http://bbs.nga.cn/read.php?tid=12852020" style="background-image: url(http://img.nga.cn/attachments/mon_201711/15/-6oh25Q5-58wK1dT3cSi3-9i.jpg);" target="_blank"></a>
<h5><a href="http://bbs.nga.cn/read.php?tid=12852020" target="_blank">一起剪纸吧 加强版</a></h5>
<div class="time">2017-11-10<font>发售</font></div>
<div class="tags"><span class="icon03"></span></div>
<div class="num">8.1</div>
</div>
如果我们用soup.find_all(target='_blank')
找这个tag的话,(我以为)并不能直接找到和它parent tag并列的class='time'或者'num'的那几个tag。
然而BeautifulSoup真是太棒了,它不但提供了找到父标签的方法,还提供了找到兄弟标签的方法,分别是:
tag.parent
tag.find_next_sibling()
这样一来不管目标网页的结构有多混乱都可以轻松找到想获取的内容。
if (name in gamedict)==True:
gamedict[name][1].append(platform)
if (name in gamedict)==False:
gamedict[name]=[name,list([platform]),score,url,time]
最后几行if判断干的事情就是烦恼了很久的多平台游戏分类,其实原理也是相当朴素啊……这故事是不是告诉我们整理东西要越早越好(强行大道理)。
2.2
之后我们要做的就是,将从主页爬到的各个游戏的数据进一步扩展,得到详细测评的内容。
comment_pattern=re.compile('postcontent[0-9]')
#标签的class都是'postcontent+数字'格式
for info in gamedict.values():
page=requests.get((info[3]),proxies=proxies,headers=headers).content
soup=BeautifulSoup(page,'lxml')
last_page=soup.find('a',class_=' uitxt1')
#看有没有多页评论进行条件分歧
if last_page==None:
cmts=[cmts.get_text() for cmts in soup.find_all(id=comment_pattern,class_="postcontent ubbcode" )][1:]
cmts_1=[]
for cmt in cmts:
cmts_1.append(re.sub('((\[.*\])|(\n)|(\s+))','',cmt))
info.append(cmts_1)
else:
for son_page in [info[3]+"&page={}".format(i) for i in range(1,int(last_page_number=last_page.get('href')[-1]))]:
son_page_soup=BeautifulSoup(son_page,'lxml')
cmts=[cmts.get_text() for cmts in son_page_soup.find_all(id=comment_pattern,class_="postcontent ubbcode" )][1:]
cmts_1=[]
for cmt in cmts:
cmts_1.append(re.sub('((\[.*\])|(\n)|(\s+))','',cmt))
#去掉一些空格、换行或者格式为[一些奇怪的字符]的论坛表情代码
info.append(cmts_1)
2.3
在1.2中我们得到一个格式为
{'游戏名称':'游戏名称',['平台1','平台2','平台3'],'评分','发售日期',['评论1','评论2','评论3','评论4']}
的dict。
(此处有一个疑问,如果取消dict用Class Game(object)存取数据的话会不会更好?但是游戏名称是中文,怎么定义名称又是一个问题。如果有人能解答就好了)
那么我们就可以把comment存到txt中方便存取操作。这一步还算简单。
for info in gamedict.values():
name=re.sub('((\s+)|(\/))','_',info[0])
这一步就是去除一些windows文件名中非法字符的部分。
for comment in info[5]:
comment_txt_file=open('C:\\piyan\\nga_game_comment\\%s.txt'% name,'a',encoding='utf-8')
print(comment,file=comment_txt_file)
comment_txt_file.close()
2.4
数据都准备好了,下面就是激动人心的可视化环节辣!!
因为研究到这里已经很累了(是你太菜),就迫不及待地用垃圾效率搞了起来。
分词用的是结巴分词,安利一下:
https://github.com/fxsjy/jieba
特别要提到的是中文会出现方框的情况下,只要设置一下font_path参数就好。
import jieba
from wordcloud import WordCloud,STOPWORDS
import re
import matplotlib.pyplot as plt
font=r'C:\Windows\Fonts\msyh.ttc'
text=open('C:\\piyan\\nga_game_comment\\星露谷物语.txt',encoding='utf-8').read()
text=' '.join(jieba.cut(text,cut_all=True))
wordcloud=WordCloud().generate(text)
STOPWORDS=set(STOPWORDS)
newstopwords=['以为','游戏','真的','不是','可以','非常','系列','还是','这个','虽然','这个','的确','似的','出现','我们','这款','过不去','不多','多个','作为','觉得','差不多']
#其实应该是有词典的吧??但是我懒得研究了就……
for words in newstopwords:
STOPWORDS.add(words)
wordcloud = WordCloud(max_font_size=200,font_path=font,width=1500,height=800,stopwords=STOPWORDS).generate(text)
plt.figure()
plt.imshow(wordcloud, interpolation="bilinear")
plt.axis("off")
plt.show()
wordcloud.to_file('C:\\piyan\\nga_comment_pic\\stardew.png')
我们看一下结果就是
![](https://img.haomeiwen.com/i8789997/d92fd139698832df.png)
当然如果略过分词阶段效果也挺搞笑的:
![](https://img.haomeiwen.com/i8789997/b430f9facb279242.png)
![](https://img.haomeiwen.com/i8789997/7cac9270fc7843fd.png)
3.总结
3.1关于数据本身
感觉nga的评分系统也是最近才出的,基数太小本来也就没什么普遍性。下次得试试steam商店的测评,感觉会比较有意思。(问题来了,steam商店没有评分只有好评差评,而且动态页面,至今还没找到那个json文件)
在自己玩的时候(筛选9分以上的ps4游戏),发现,嗯?为什么没有巫师3这不科学?……之后看了一下才知道原来ps4上的叫巫师3年度版之类的,评论的人很少。
那么问题来了,如何把游戏本体和dlc分类到一起,避免这种情况呢?感觉这似乎变成了nlp问题……瑟瑟发抖。
3.2最后说句废话
急需下一个project给我打发时间。这些本质上就是文字的就不够好玩也不够有技术,很愁(没有)。
网友评论