共计 9210 个字符,预计需要花费 24 分钟才能阅读完成。
因为审核起因,本文中的网站以 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)