由于审核原因,本文中的网站以S代替。
有刚刚使用S的用户,不知道玩什么游戏怎么办?往往热销商品会使他们最合适的选择。
当然,某个第三方的网站上面的数据会更详细,什么游戏用户活跃度高,哪个区服游戏价格更便宜上面都会有。但是加上了一层Cloudflare的浏览器验证。
有人说用cloudscraper,但是cloudscraper对商用版的Cloudflare好像不管用(应该是吧,如果有大佬有更好的方法请及时指出,谢谢),之后会用其他的方法再试试。所以这边先按下不表,开始获取S的热销信息。
一、热销获取分析
点击进入热销商品页:
https://那个网站/search/?sort_by=_ASC&force_infinite=1&snr=1_7_7_globaltopsellers_7&filter=globaltopsellers&page=2&os=win
上面的链接,仅仅能获取第一页的数据。
通过开发者模式找到真正的内容获取链接是:
https://那个网站/search/results/?query&start=0&count=50&sort_by=_ASC&os=win&snr=1_7_7_globaltopsellers_7&filter=globaltopsellers&infinite=1
其中start对应了开始位置,对应了翻页。count对应了一次获取了多少数据。
get请求即可,上代码:
1. def getInfo(self):2. url = 'https://那个网站/search/results/?query&start=0&count=50&sort_by=_ASC&os=win&snr=1_7_7_globaltopsellers_7&filter=globaltopsellers&infinite=1'
3. res = self.getRes(url,self.headers,'','','GET')#自己封装的请求方法
4. res = res.json()['results_html']
5. sel = Selector(text=res)
6. nodes = sel.css('.search_result_row')
7. for node in nodes:
8. gamedata = {}
9. gamedata['url'] = node.css('a::attr(href)').extract_first()#链接
10. gamedata['name'] = node.css('a .search_name .title::text').extract_first()#游戏名
11. gamedata['sales_date'] = node.css('a .search_released::text').extract_first()#发售日
12. discount = node.css('.search_discount span::text').extract_first()#是否打折
13. gamedata['discount'] = discount if discount else 'no discount'
14. price = node.css('a .search_price::text').extract_first().strip()#价格
15. discountPrice = node.css('.discounted::text').extract()#打折后的价格
16. discountPrice = discountPrice[-1] if discountPrice else ''
17. gamedata['price'] = discountPrice if discountPrice else price#最终价格
18. print(gamedata)
二、pandas保存数据
2.1 构建pandas DataFrame对象
pandas存储Excel数据利用的是pandas对象的to_excel方法,将pandas的Dataframe对象直接插入Excel表中。
而DataFrame表示的是矩阵的数据表,包含已排序的列集合。
首先,先将获取到的数据,构建成Dataframe对象,先将我们获取的数据分别存入对应的list中,获取的url存到url的list,游戏名存到name的list:
1. url = []2. name = []
3. sales_date = []
4. discount = []
5. price = []
2. if url not in self.url:
3. self.url.append(url)
4. name = node.css('a .search_name .title::text').extract_first()
5. sales_date = node.css('a .search_released::text').extract_first()
6. discount = node.css('.search_discount span::text').extract_first()
7. discount = discount if discount else 'no discount'
8. price = node.css('a .search_price::text').extract_first().strip()
9. discountPrice = node.css('.discounted::text').extract()
10. discountPrice = discountPrice[-1] if discountPrice else ''
11. price = discountPrice if discountPrice else price
12. self.name.append(name)
13. self.sales_date.append(sales_date)
14. self.discount.append(discount)
15. self.price.append(price)
16. else:
17. print('已存在')
将list组成相应的字典
1. data = {2. 'URL':self.url,'游戏名':self.name,'发售日':self.sales_date,'是否打折':self.discount,'价格':self.price
3. }
其中dict中的key值对应的是Excel的列名。之后用pandas的DataFrame()方法构建对象,之后插入Excel文件。
1. data = {2. 'URL':self.url,'游戏名':self.name,'发售日':self.sales_date,'是否打折':self.discount,'价格':self.price
3. }
4. frame = pd.DataFrame(data)
5. xlsxFrame = pd.read_excel('./steam.xlsx')
其中pd是引入pandas包的对象,约定俗成的见到pd就是引入了pandas。
import pandas as pd
2.2 pandas追加插入Excel
如果要是翻页的话,重复调用插入Excel方法时你会发现Excel表内的数据并不会增多,因为每一次to_excel()方法都会把你上一次写入的数据覆盖掉。
所以若想保留之前写入的数据,那就先把之前写入的数据读出来,然后和新产生的数据进行DaraFrame对象的合并,将总的数据再次写入Excel
frame = frame.append(xlsxFrame)
写入方法如下:
1. def insert_info(self):2. data = {
3. 'URL':self.url,'游戏名':self.name,'发售日':self.sales_date,'是否打折':self.discount,'价格':self.price
4. }
5. frame = pd.DataFrame(data)
6. xlsxFrame = pd.read_excel('./steam.xlsx')
7. print(xlsxFrame)
8. if xlsxFrame is not None:
9. print('追加')
10. frame = frame.append(xlsxFrame)
11. frame.to_excel('./steam.xlsx', index=False)
12. else:
13. frame.to_excel('./steam.xlsx', index=False)
逻辑:
1.将已有的数据生成DataFrame
2.读取之前写入的Excel文件,判断是否写入过数据
3.如果写入,将数据读出来合并后再次写入Excel
4.如果源文件为空,直接写入即可
三、代码整合
1. import requests2. from scrapy import Selector
3. import pandas as pd
4.
5. class getSteamInfo():
6.
7. headers = {
8. "Host": "那个网站",
9. "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
10. "accept-encoding": "gzip, deflate, br",
11. "accept-language": "zh-CN,zh;q=0.9",
12. "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.82 Safari/537.36",
13. }
14.
15. url = []
16. name = []
17. sales_date = []
18. discount = []
19. price = []
20.
21. # api获取ip
22. def getApiIp(self):
23. # 获取且仅获取一个ip
24. api_url = 'api地址'
25. res = requests.get(api_url, timeout=5)
26. try:
27. if res.status_code == 200:
28. api_data = res.json()['data'][0]
29. proxies = {
30. 'http': 'http://{}:{}'.format(api_data['ip'], api_data['port']),
31. 'https': 'http://{}:{}'.format(api_data['ip'], api_data['port']),
32. }
33. print(proxies)
34. return proxies
35. else:
36. print('获取失败')
37. except:
38. print('获取失败')
39.
40. def getInfo(self):
41. url = 'https://那个网站/search/results/?query&start=0&count=50&sort_by=_ASC&os=win&snr=1_7_7_globaltopsellers_7&filter=globaltopsellers&infinite=1'
42. res = self.getRes(url,self.headers,'','','GET')#自己封装的请求方法
43. res = res.json()['results_html']
44. sel = Selector(text=res)
45. nodes = sel.css('.search_result_row')
46. for node in nodes:
47. url = node.css('a::attr(href)').extract_first()
48. if url not in self.url:
49. self.url.append(url)
50. name = node.css('a .search_name .title::text').extract_first()
51. sales_date = node.css('a .search_released::text').extract_first()
52. discount = node.css('.search_discount span::text').extract_first()
53. discount = discount if discount else 'no discount'
54. price = node.css('a .search_price::text').extract_first().strip()
55. discountPrice = node.css('.discounted::text').extract()
56. discountPrice = discountPrice[-1] if discountPrice else ''
57. price = discountPrice if discountPrice else price
58. self.name.append(name)
59. self.sales_date.append(sales_date)
60. self.discount.append(discount)
61. self.price.append(price)
62. else:
63. print('已存在')
64. # self.insert_info()
65.
66. def insert_info(self):
67. data = {
68. 'URL':self.url,'游戏名':self.name,'发售日':self.sales_date,'是否打折':self.discount,'价格':self.price
69. }
70. frame = pd.DataFrame(data)
71. xlsxFrame = pd.read_excel('./steam.xlsx')
72. print(xlsxFrame)
73. if xlsxFrame is not None:
74. print('追加')
75. frame = frame.append(xlsxFrame)
76. frame.to_excel('./steam.xlsx', index=False)
77. else:
78. frame.to_excel('./steam.xlsx', index=False)
79.
80. # 专门发送请求的方法,代理请求三次,三次失败返回错误
81. def getRes(self,url, headers, proxies, post_data, method):
82. if proxies:
83. for i in range(3):
84. try:
85. # 传代理的post请求
86. if method == 'POST':
87. res = requests.post(url, headers=headers, data=post_data, proxies=proxies)
88. # 传代理的get请求
89. else:
90. res = requests.get(url, headers=headers, proxies=proxies)
91. if res:
92. return res
93. except:
94. print(f'第{i+1}次请求出错')
95. else:
96. return None
97. else:
98. for i in range(3):
99. proxies = self.getApiIp()
100. try:
101. # 请求代理的post请求
102. if method == 'POST':
103. res = requests.post(url, headers=headers, data=post_data, proxies=proxies)
104. # 请求代理的get请求
105. else:
106. res = requests.get(url, headers=headers, proxies=proxies)
107. if res:
108. return res
109. except:
110. print(f"第{i+1}次请求出错")
111. else:
112. return None
113.
114. if __name__ == '__main__':
115. getSteamInfo().getInfo()
对了,本次数据是获取的美服数据哦。最近国内访问不稳定,若是想要获取数据不买游戏的话建议使用代理进行访问。
最后奉劝大家:适当游戏,理智消费 ,认真生活,支持正版。(大批量的数据还是存数据库吧,人家也支持导出Excel)