由于审核原因,本文中的网站以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请求即可,上代码:
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: 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 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的代理,新用户可以白嫖流量哦。
最后奉劝大家:适当游戏,理智消费 ,认真生活,支持正版。(大批量的数据还是存数据库吧,人家也支持导出Excel)