python爬虫实战-网易BUFF CSGO饰品
寒假迷上了csgo,一方面对这个纯粹的枪战游戏着迷,另一方面对精美的饰品着迷。众所周知,csgo是个理财游戏饰品游戏,能够掌握到喜欢饰品的价格就可以得到炼金收益,掌握其动态变化可以当倒爷(不提倡)。
本文是本小白入坑爬虫项目的实战,适合大家练手。疫情期间受到博主puppylpg的启发,自己也边学边做摸石头过河。话不多说先上效果图
目录
Request库介绍
你浏览到的网页都有对应的源代码,具体查看方式是利用有Chrome核的浏览器右键然后查看源代码,而request库的作用就是获取其页面的源代码。
request库的调用import requests
一个请求指令需要包含:response = requests.get(url, headers, cookies)
其中url是请求路径,headers是请求头,cookies是请求身份文件。
通常在登录后你的cookies跟headers就确定了。
获取header,cookies
首先需要登陆buff,登陆过后右键页面点检查,刷新可以查看你本机的header核cookies
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36',
}
# cookie
cookie_str = r'Device-Id=xLoPYA08mzx1RcfxWgJ7; Locale-Supported=zh-Hans; game=csgo; _ga=GA1.2.308981242.1590934310; _gid=GA1.2.1199922105.1591931691; NTES_YD_SESS=ibf9I12bOgxvKCyxN2P3JoQtaAcvZGsJXKGNOEdpOTkD5CnFOwbg6tpHCs4mpmrOfn3nyBCzmupp1Xja1RhK1BkZRbFbI.5zzW.kjFHpMfDXjiFRh0664TPZynx.teVt43efjkfBDzsGdK9WE4cCONux_NiUXwAJYKH67Ni5EPG2ypuWiHwHwY1dCFUEWQ4lR2U42gbXpQscfik7gAAdLCxxA8gg1V8aOxu71AI_usoRq; S_INFO=1591931716|0|3&80##|18588891371; P_INFO=18588891371|1591931716|1|netease_buff|00&99|null&null&null#CN&null#10#0|&0|null|18588891371; session=1-XJCjTQFMSIgRQUkgJTN9xoP1nvWaLC0KpoJ8E9M-A5N62043038656; _gat_gtag_UA_109989484_1=1; csrf_token=IjQxZTQ3MTFhZmE5M2QwMzU1MWFkYmViN2IzYTQwMjExODA4NzY3ZjUi.EcSFQg.StET4McSLh1iM2IH1Gkjpq2Pwe0'
cookies = {}
for line in cookie_str.split(';'):
key, value = line.split('=', 1)
cookies[key] = value
具体的更多request库的应用请
分析API
进入buff的csgo饰品专栏(https://buff.163.com/market/?game=csgo#tab=selling&page_num=1)
后可以看见
这就说明,我们只需找到这全部目录下的该武器种类的全部饰品皮肤对应的id,逐个请求就可以找到相应饰品的信息。
随便点开一个款武器种类(以ak47为例)检查其源代码,检查请求的内容。发现
这个.json文件中大有乾坤
"items": [
{
"appid": 730,
"bookmarked": false,
"buy_max_price": "193",
"buy_num": 22,
"description": null,
"game": "csgo",
"goods_info": {
"icon_url": "https://g.fp.ps.netease.com/market/file/5aa0c2f769b21ae0f25da300W8ER6ycS",
"info": {
"tags": {
"exterior": {
"category": "exterior",
"internal_name": "wearcategory2",
"localized_name": "\u4e45\u7ecf\u6c99\u573a"
},
"quality": {
"category": "quality",
"internal_name": "strange",
"localized_name": "StatTrak\u2122"
},
"rarity": {
"category": "rarity",
"internal_name": "legendary_weapon",
"localized_name": "\u4fdd\u5bc6"
},
"type": {
"category": "type",
"internal_name": "csgo_type_rifle",
"localized_name": "\u6b65\u67aa"
},
"weapon": {
"category": "weapon",
"internal_name": "weapon_ak47",
"localized_name": "AK-47"
}
}
},
"item_id": null,
"original_icon_url": "https://g.fp.ps.netease.com/market/file/5a7abfa516b6d4ab48222b6f9v9qaRgs",
"steam_price": "43.1",
"steam_price_cny": "304.51"
},
"has_buff_price_history": true,
"id": 38220,
"market_hash_name": "StatTrak\u2122 AK-47 | Redline (Field-Tested)",
"market_min_price": "0",
"name": "AK-47\uff08StatTrak\u2122\uff09 | \u7ea2\u7ebf (\u4e45\u7ecf\u6c99\u573a)",
"quick_price": "197.4",
"sell_min_price": "197.9",
"sell_num": 1539,
"sell_reference_price": "197.9",
"steam_market_url": "https://steamcommunity.com/market/listings/730/StatTrak%E2%84%A2%20AK-47%20%7C%20Redline%20%28Field-Tested%29",
"transacted_num": 0
},
它包含了武器id,英文名,最低售价,最高售价等关键信息。所以这个请求url就是我们需要的APIhttps://buff.163.com/api/market/goods?game=csgo&page_num=1&category=weapon_ak47&_=1591941311097
最后面的数字是相对时间,可以去除。所以到了这一步,我们需要先找到所有类别的标签Category整理成list,逐一请求即可。https://buff.163.com/api/market/goods?game=csgo&page_num=1&category=
+categorylist[i]
获取Category_list
进入Buff中CSGO饰品市场首页https://buff.163.com/market/?game=csgo#tab=selling&page_num=1
,查看源代码
观察到目录的形式是以<li value="weapon_fiveseven">FN57
形式呈现。
故直接请求该页面,利用正则匹配表达式(re库)提取引号内的内容。
source_page_url = "https://buff.163.com/market/?game=csgo#tab=selling&page_num=1"
cat_response = requests.get(url=source_page_url, headers=headers, cookies=cookies)
html_text0 = cat_response.text
# 找出各个武器种类
category_list = re.findall( r'li value="weapon_(.+?)">', html_text0, re.M)
for i in range(len(category_list)):
category_list[i] = "weapon_" + category_list[i]
分析页面
利用正则匹配,将物品的id,名字,价格一一归类。
需要注意的是一个api中page_num=1
,需要获取总页码数量,并切换继续爬取信息。
for i in range(len(category_list)):
# 获取不同物件名称
# 标准url:https://buff.163.com/api/market/goods?game=csgo&page_num=1&category=weapon_knife_butterfly
category_url = "&category=" + category_list[i]
first_url = 'https://buff.163.com/api/market/goods?game=csgo&page_num=1' + category_url
# 获取单一物件的总页码
page_response = requests.get(url=first_url, headers=headers, cookies=cookies)
html_text1 = page_response.text
page_num_list = re.findall(r'"total_page": (.*)', html_text1, re.M)
page_num = page_num_list[0]
# 获取名字和价格
names_list_temp = re.findall(r'"market_hash_name": "(.*)",', html_text2, re.M)
price_list_temp = re.findall(r'"sell_min_price": "(.*)",', html_text2, re.M)
id_list_temp = re.findall(r'"id": (.*),', html_text2, re.M)
注意用try语句记录爬取出错的数据节点,否则一出异常的话前面爬下来的信息可能都会丢失。
将数据保存成csv文件,方便后续访问。
# 汇合信息写成表格并保存
csv_name = ["id","name","price"]
csv_data = zip(id_list,names_list,price_list)
items_information = pd.DataFrame(columns=csv_name, data=csv_data)
items_information.to_csv("items_information.csv")
得到如此数据
饰品武器箱
了解到饰品来源武器箱可以更直观地为后面炼金的成本以及收益铺垫。
下面只爬取崭新出厂以及无计数器的武器饰品。
先从上面的csv文件中,将Factory New的武器筛选出来,有了他们的id就能够前往具体的页面。
以崭新黑色魅影AWP为例https://buff.163.com/market/goods?goods_id=763243&from=market#tab=selling
,其源代码中第一行就包含了该武器的全部信息。
<html> <head><title>AWP | 黑色魅影 (崭新出厂)_CS:GO饰品交易_网易BUFF</title><meta content="text/html; charset=utf-8" http-equiv="Content-Type"><meta name="csrf_token" content="IjQxZTQ3MTFhZmE5M2QwMzU1MWFkYmViN2IzYTQwMjExODA4NzY3ZjUi.EcS1EA.Mv46cvhCLjco-Kj0f5ITOI3g3Pk"><meta name="keywords" content="AWP | 黑色魅影 (崭新出厂),崭新出厂,普通,AWP,狙击步枪,隐秘,步枪,AWP,头号特训收藏品,黑,大姐姐,黑色魅影,“头号特训”武器箱,csgo饰品交易,csgo皮肤交易,csgo国服饰品交易,csgo低价饰品,csgo饰品商城,饰品磨损排名查询,csgo饰品检视"><meta name="description" content="网易BUFF游戏饰品皮肤交易平台,专注更安全,更便捷,更高效的CS:GO饰品皮肤交易服务- AWP | 黑色魅影 (崭新出厂),崭新出厂,普通,AWP,狙击步枪,隐秘,步枪,AWP,头号特训收藏品,黑,大姐姐,黑色魅影,“头号特训”武器箱。">
同样的利用正则匹配,将他们分类,是保密还是隐秘,出自哪个武器箱都分类好。
items_type = ["消费", "工业", "军规", "受限", "保密", "隐秘"]
# 找出各个武器的中文名字
chinese_list = re.findall(r'<head><title>(.*?)_CS:GO饰品交易', html_text4, re.M)
# 找出所属箱子
box_list = re.findall(r',(.*?)收藏品,', html_text4, re.M)
if box_list == []:
box_list = re.findall(r',(.*?)collection,', html_text4, re.M)
# 判断稀有度
for str in items_type:
if str in html_text4:
type_str = str
break
else:
if items_type.index(str) == len(items_type):
type_str = "Na"
print("type error occurd in id:" + id)
else:
continue
爬取了一段时间后报错,发现有的武器没有箱子来源,故需要加上异常处理,避免辛辛苦苦爬半天的数据丢失。
再次将信息绘制成csv表格
name = ["id", "Chinese_name", 'belonging', "type", "price"]
data = zip(list(box_sort_dic.keys()), [x[0] for x in list(box_sort_dic.values())],
[x[1] for x in list(box_sort_dic.values())]
, [x[2] for x in list(box_sort_dic.values())], [x[3] for x in list(box_sort_dic.values())])
items_sorting = pd.DataFrame(columns=name, data=data)
items_sorting.to_csv("items_sorting.csv")
这就有了开头那样的数据图,是不是炼金党福音。
饰品历史价格
在爬取饰品的历史价格中,需要注意buff最多提供3个月的历史数据,而且要高闪券才能看近三个月的价格,感兴趣的小伙伴可以买一天的高闪券然后全部爬完慢慢欣赏。
使用高闪券后来到https://buff.163.com/market/goods?goods_id=763243&from=market#tab=price-chart
价格趋势页面,同样的检查浏览器中含有price_history的json文件,请求api如下:https://buff.163.com/api/market/goods/price_history/buff?game=csgo&goods_id=776481¤cy=CNY&days=90
同样的,只需改变id便可以找到对应饰品的历史价格。
"price_history": [
[
1589356800000,
9255.0
],
[
1589360400000,
19400.0
],
[
1589371200000,
20400.0
],
[
1589374800000,
19688.0
],
[
1589378400000,
19642.0
],
[
1589385600000,
24400.0
],
[
1589428800000,
19500.0
],
[
1589432400000,
19399.0
],
[
1589436000000,
19000.0
],
[
1589443200000,
19900.0
],
[
1589450400000,
19498.0
这里只提供一个思路,具体实现代码就不呈现了。
可以将爬到的历史价格数据可视化,也可以将数据喂入长短神经网络进行数值分析,把饰品当股票来玩。
总结
1.在爬虫的实际使用中,一定要是用time.sleep函数,否则一方面会对目标网站服务器造成巨大压力,另一方面各大网络的反爬机制中会对短时间大量访问的ip进行封禁,一般设立在0.5~1.5s之间,随机数更好。
2.要做好异常处理,记录出错的数据节点,避免时间浪费。
3.关注的人多的话会多出一期炼金分析,分享一下本人9%收益率的炼金模型。由于本人对炼金的机制也不是很清楚,欢迎小伙伴们留言给我提供更好的思路。