因为审核起因,本文中的网站以 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 = []
1.url = node.css('a::attr(href)').extract_first()
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:
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 requests
2.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()
对了,本次数据是获取的美服数据哦。最近国内拜访不稳固,若是想要获取数据不买游戏的话倡议应用代理进行拜访。我这里应用的是 ipidea 的代理,新用户能够白嫖流量哦。
地址:http://www.ipidea.net/
最初规劝大家:适当游戏,理智生产,认真生存,反对正版。(大批量的数据还是存数据库吧,人家也反对导出 Excel)