steam夏日促销悄然开始,用Python爬取排行榜上的游戏打折信息!
前言
本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理。
不知不觉,一年一度如火如荼的steam夏日促销悄然开始了。每年通过大大小小的促销,我的游戏库里已经堆积满还未下载过的游戏。但所谓“买到就是赚到,G胖一定大亏”的想法日渐流行,指不定以后就靠它们发达了呢。
有时候滚动steam的排行榜看自己喜欢的游戏的时候,未免会被右边的价格影响到。久而久之我发现我所不想买的游戏并不是因为它不好玩,而是它还没打折。又或者有些心水未被别人挖掘,在排行榜隐秘的角落里自怨自艾,等待“把玩”它的人出现~
于是我简单的用python爬取了steam排行榜前10000个游戏的信息,其中有游戏名,评价,价格,出版日期等,在更加简洁的列表界面选取自己感兴趣的游戏之时,也可以进行进一步的数据分析。
废话不多说,赶紧开始,不然被我拖更到促销结束了就蹭不到热度了。(本来也没有热度)
开始爬取
先说说这次爬虫选用数据的优缺点:
第一,我发现了steam在显示排行榜列表的时候后台会进行一个查询的申请,点开一看是一串json代码,而且在python进行request的时候不需要模拟浏览器进行填“headers”表的操作。通过访问而得到的json代码大大简化了循环复杂度,一次循环可以得到100个游戏信息。
第二,因为只需要遍历所有json代码,时间上可以比进入每一个游戏链接更加短。
第三,但就因为没有进入每个游戏的链接,所以像评论,简介,开发商等信息就没有爬取。但爬取游戏链接的爬虫攻略网上也有很多,这里就不弄斧了。
首先,进入官网的排行榜页面,为了避免游戏DLC、bundle等影响后期操作的类型出现,记得在右边的过滤器里只勾选游戏类目。
通过后台的XHR发现,页面每次刷新都只显示前50个游戏,当我们滚动页面往下看时,网站会发送一个神秘代码:
经过观察,我发现代码会自动申请返回从start参数的数字开始,一共count参数的数字的游戏信息。比如,下面的图显示它申请了从第51个到100个总共50个游戏的信息。
双击上上图的红框链接,返回的页面长这样:
所谓json格式,其实就是在字典里夹字典或者列表,目前许多大数据都是这样保存滴。所以在查询的时候其实很方便,但是我在抽取信息的时候还是会用到正则表达式,因为会方便很多。
知道这些之后,剩下的就可以用python一个个有用信息抽取出来,组成一个新的Dataframe列表,以便之后保存为csv格式。
# 导入需要用到的库 import requests from bs4 import BeautifulSoup import re import json import numpy as np import pandas as pd import matplotlib.pyplot as plt
我们尝试用requests打开上面json页面的链接,并用json load解析。
这里我更改了start和count 的参数,比较方便对照原网页来看信息是否一致。
url = 'https://store.steampowered.com/search/results/?query&start=0&count=100&dynamic_data=&sort_by=_ASC&category1=998&snr=1_7_7_globaltopsellers_7&filter=globaltopsellers&infinite=1' content = requests.get(url).content jsontext = json.loads(content) soup = BeautifulSoup(jsontext['results_html'],'html.parser')
可以看看soup返回的结果,它显示了json里边'results_html'返回的东西,因为前边的内容我们已经不需要了,所有游戏信息都在这个键里边。
接着我们回到那个json页面看看我们想要的东西都藏在哪:
游戏名字藏在span的title class里:
name = soup.find_all('span',class_ ='title')
出版日期藏在div的另一个class里:
listdate = soup.find_all('div', class_ ='col search_released responsive_secondrow')
同样的,可以用上面的方法找到游戏的链接、ID,这里就不赘述了。
评分和打分人数藏在span标签里,如果用字典查找的话会比较麻烦,所以我们稍后使用正则表达式将它俩提取出来:
不幸运的是,有些游戏因为还没上架,所以没有人评论,我们用正则表达式得到的信息是乱码。所以我们用函数来防止出现乱码的可能性:
def get_reviewscore(review):gamereview=[]for i in range(len(review)): try:score = re.search('br>(\d\d)%',str(review[i]))[1]except:score = ''gamereview.append(score)return gamereview ########################################### def get_reviewers(review):reviewers=[]for i in range(len(review)):try:ppl = (re.search('the\s(.*?)(\s)user',str(review[i]))[1])except:ppl = ''reviewers.append(ppl)return reviewers
如果看到这里的读者觉得很轻松,那我便可以继续往下述说,因为爬取价格比评论更加麻烦。但仅限于麻烦,并没有很高大上的操作;而我相信我并不是用聪明的方法爬取到想要的结果,因为对于这个体量的数据再优化的代码对于运行时间来说相差不大。反正结果都一样,管它呢。
其实要找物品的最终价格(即免费游戏,打折后或未打折的游戏价格)非常简单,因为他就藏在这里:
默认后边两位为小数点后两位,所以我们直接把这串数字揪出来并除以100:
def get_finalprice(price):finalprice=[]for i in range(len(price)):pricelist = int(re.search('final(\W+?)(\d+)(\W)',str(price[i]))[2])/100finalprice.append(pricelist)return finalprice
但我们如果就想知道他的原价,以便之后做分析该怎么办呢?
先看一下steam排行榜上的价格有三种显示方法:
第一种,带有划线价格的打折商品,在源代码中长这样:
第二种,免费的:
头疼的是,免费的标识也有变体:
(连to的大小写也有不一样的……steam您用点心!)
不过Free还是老老实实在最前面,所以我们后边只要找到Free就好啦。
第三种,原价显示:
上面的图片都是我在抽查的时候发现的规律与变形,为了避免后续几千个游戏有“乌合之众”,我在代码里只查找这三种格式,如果有奇形怪状的数据出现,直接一棍子打成“空值”:
def get_price(price):oripricelist=[]for i in range(len(price)):try:oripricelist.append(price[i].find_all(class_="col search_price responsive_secondrow")[0].text)except:oripricelist.append(price[i].find_all(class_="col search_price discounted responsive_secondrow")[0].text)ori_price=[]for i in range(len(oripricelist)):try:search = re.search('Free',oripricelist[i])[0].replace('Free','0')except:if oripricelist[i]== '\n':search=''else:try:search = re.search('HK.*?(\d+\.\d+)\D',oripricelist[i])[1]except:search=''ori_price.append(search)return ori_price
定义完这些想要的数据之后,我们就开始跑循环了。
先把我们要的数据列命好名字:
def get_data(games=1000): num_games = gamesgamename=[]gamereview=[]gamereviewers=[]gamerelease=[]oriprice=[]final_price=[]appid=[]website=[]
接着我们以每个链接查询100个游戏的步伐开始跑循环并将里边的信息找出来,录入上面的列表里:
page = np.arange(0,num_games,100)for num in page:url = 'https://store.steampowered.com/search/results/?query&start='+str(num)+'&count=100&dynamic_data=&sort_by=_ASC&category1=998&snr=1_7_7_globaltopsellers_7&filter=globaltopsellers&infinite=1'print('the {} iteration: Trying to connect...'.format((num/100)+1))content = requests.get(url).contentjsontext = json.loads(content)soup = BeautifulSoup(jsontext['results_html'],'html.parser')name = soup.find_all('span',class_ ='title')review = soup.find_all('div', class_ ='col search_reviewscore responsive_secondrow')listdate = soup.find_all('div', class_ ='col search_released responsive_secondrow')price = soup.find_all('div', class_ = 'col search_price_discount_combined responsive_secondrow')href = soup.find_all(class_='search_result_row ds_collapse_flag')for i in name:gamename.append(i.text)getreview = get_reviewscore(review) for i in getreview:gamereview.append(i)getreviewers = get_reviewers(review)for i in getreviewers:gamereviewers.append(i)for i in listdate:gamerelease.append(i.text)getprice = get_price(price)for i in getprice:oriprice.append(i)getfinalprice = get_finalprice(price)for i in getfinalprice:final_price.append(i)for i in range(len(href)):appid.append(eval(soup.find_all(class_='search_result_row ds_collapse_flag')[i].attrs['data-ds-appid']))website.append(soup.find_all(class_='search_result_row ds_collapse_flag')[i].attrs['href'])print('done')
我们在遍历中每次访问页面、完成每次循环的时候都让电脑打印一段字,以便出错的时候能快速找出出错的页面。
接下来就将得到的数据塞进一个数据表里:
df = pd.DataFrame(data=[gamename,gamereview,gamereviewers,gamerelease,oriprice,final_price,appid,website]).Tdf.columns = ['name','review_score','reviewers','release_date','ori_price','final_price','id','link']return df#呼叫我们的函数: df = get_data(10000) #这里的数字代表爬取10000个游戏
等待漫长的过程与欣赏成功的过程:
最后的数据集长这样:
接下来只要保存为csv格式,就可以开始分析数据了。但这已经不是爬虫文章的内容,所以不会往下继续分析啦。
总结与反思
一
我发现final_price也就是一开始提取的最终价格中,会有高于原价的现象。
比如CS:GO的最终价格并不是0,是因为它有一个升级包:
前1000个游戏里总共有3个这样的错误:
实况足球2020 是demo版免费,而想体验完整游戏确实需要78港币;
奇异人生1 是第一篇章免费,后边的篇章需要23.8港币。
二
这些代码跑起来虽然快,但得到的信息依旧太少,如果要深入研究steam的数据还是需要有强大的耐心遍历所有游戏链接呐。
三
这次的爬虫经历其实也发现了steam一些录入大数据库的时候的小差错,比如前面所提到的免费标识竟然有3种变体,但他们可能觉得问题不大。
源码获取加群:850591259
steam夏日促销悄然开始,用Python爬取排行榜上的游戏打折信息!相关推荐
- steam夏日促销悄然开始,用Python爬取排行榜上的游戏打折信息
前言 很多人学习python,不知道从何学起. 很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手. 很多已经做案例的人,却不知道如何去学习更加高深的知识. 那么针对这三类人,我给大 ...
- steam夏日促销用Python爬取排行榜上的游戏打折信息
不知不觉,一年一度如火如荼的 steam 夏日促销悄然开始了.每年通过大大小小的促销,我的游戏库里已经堆积满还未下载过的游戏.但所谓"买到就是赚到,G胖一定大亏"的想法日渐流行,指 ...
- python爬取电影评分_用Python爬取猫眼上的top100评分电影
代码如下: # 注意encoding = 'utf-8'和ensure_ascii = False,不写的话不能输出汉字 import requests from requests.exception ...
- python爬房源信息_用python爬取链家网的二手房信息
题外话:这几天用python做题,算是有头有尾地完成了.这两天会抽空把我的思路和方法,还有代码贴出来,供python的初学者参考.我python的实战经历不多,所以代码也是简单易懂的那种.当然过程中还 ...
- Python爬取豆瓣电影top250的电影信息
Python爬取豆瓣电影top250的电影信息 前言 一.简介 二.实例源码展示 小结 前言 相信很多小伙伴在学习网络爬虫时,老师们会举一些实例案例讲解爬虫知识,本文介绍的就是经典爬虫实际案例–爬取豆 ...
- python爬取并分析淘宝商品信息
python爬取并分析淘宝商品信息 背景介绍 一.模拟登陆 二.爬取商品信息 1. 定义相关参数 2. 分析并定义正则 3. 数据爬取 三.简单数据分析 1.导入库 2.中文显示 3.读取数据 4.分 ...
- python爬取boss直聘招聘信息_年底啦,利用Python爬取Boss直聘的招聘信息,为明年跳槽做准备...
原标题:年底啦,利用Python爬取Boss直聘的招聘信息,为明年跳槽做准备 前言 为什么都说程序员的薪资高,但是刚开始入职的你,薪资并不是自己想象中的那样,首先是你的工作经验不足,其次就是需要不断的 ...
- python爬取文献代码_使用python爬取MedSci上的影响因子排名靠前的文献
使用python爬取medsci上的期刊信息,通过设定条件,然后获取相应的期刊的的影响因子排名,期刊名称,英文全称和影响因子.主要过程如下: 首先,通过分析网站http://www.medsci.cn ...
- 1-3 用Python爬取微博上电影主题的热度(主题的阅读数和讨论数)
1-3 用Python爬取微博上电影主题的热度(主题的阅读数和讨论数) 1 weiboHeat.py 2 #-*- coding:utf-8 -*- 3 ''' 4 该脚本可以从wap版的微博网站上爬 ...
最新文章
- Nature:2020年最佳科学影像,每一张都是壁纸,每一张都是历史
- 理解进化的五座“桥”
- quartz定时定时任务执行两次
- 关于C语言的问卷调查
- Wifi模块—源码分析Wifi热点扫描(Android P)
- java图片转ascii字符画(转载)
- !doctype html报错h5,【Web前端问题】javascript import 报错
- node 大写_大写Node.js模块
- 论文学习12-Conditional Random Fields: Probabilistic Models for Segmenting and Labeling Sequence Data(CRF
- python如何爬取sci论文中所需的数据_sci论文中的科研数据处理方法
- macbook air可以运行c语言吗,新 MacBook Air 现场上手:它让 MacBook 变得有点尴尬了...
- hdu 1713求分数的最小公倍数
- “无法找到Internet Explorer”的解决方法
- 小学多媒体计算机室管理计划,多媒体教室管理工作计划
- 计算机内存延迟,内存延迟有多重要?游戏性能测试说明真相:酷睿i9-9900K依然无敌...
- struts2联网问题
- 教你巧用万用表测量大值电阻
- 用本地播放器看直播,录制高清视频streamlink的使用
- 2017cad光标大小怎么调_AutoCAD 2010如何调整光标的大小?调整光标大小的方法
- vue+ElementUI页面模板