疫情在家期间,玩玩游戏无疑是很好地放松休闲手段。而许多游戏在steam等平台上则通过限时免费领取的吸引更多玩家的参与,再加上上次差点就错过古墓丽影9的免费领取时间,看来我又需要python来做一个自动化爬虫小帮手了!
爬取免费游戏界面当然可以直接爬取steam,但是epic等发行平台也有许多相当不错的免费游戏。想要全面地了解世界范围内的限时免费领取游戏?epicbundle可以为我们提供想要的资源
进入网站,epicbundle呈现给了我们大量的游戏发售和免费游戏的信息,可惜的是,内容太多了,包括了免费游戏,bundle等大量内容,而且点击页面也需要多次跳转,这个时候,召唤python冲啊!
代码不难,很多篇幅都是注释和异常检测,实实在在地简单易懂!这段代码实现了以下特性:
# 看库包就觉得很简单~
from bs4 import BeautifulSoup
import requests
import re
import time
from selenium import webdriver
'''
获得epicbundle前三页的所有免费游戏信息
'''
dest_url = 'https://www.epicbundle.com/'
header = {
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
'accept-language': 'en-US,en;q=0.9,zh-TW;q=0.8,zh;q=0.7',
'cache-control': 'max-age=0',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36'
}
def handler(url):
'''总控
实现用户自定义
'''
html = request(url)
steam, all_ = parse(html)
# steam or all?
steamOnly = input('你只需要steam上的免费游戏吗(默认开启)?(y/n)')
steamOnly = False if steamOnly=='n' else True
# verbose or clean?
verbose = input('是否打印完整的日志(默认关闭)?(y/n)')
verbose = False if verbose=='n' else True
# 直接在浏览器中打开吗?
openBowser = input('直接在浏览器中打开免费游戏的领取界面吗(默认开启)?(y/n)')
openBowser = False if openBowser=='n' else True
pipeline(steam, all_, steamOnly, verbose, openBowser)
def request(url):
'''请求网站,获得html文件
Args:
url: 主网站域址
header: HTTP请求头,模拟浏览器
Returns:
html plain text
'''
try:
time.sleep(1)
r = requests.get(url, headers=header)
time.sleep(1)
r.raise_for_status()
time.sleep(1)
r.encoding=r.apparent_encoding
return r.text
except RuntimeError as e:
print(f'request error {e}')
return None
def parse(html):
'''获取网页中的免费游戏元素
Args:
html: html plain text
Returns:
steamFree: Array, 存储steam免费游戏信息Element
allFree: Array, 存储所有的免费游戏信息Element
'''
steamFreeGameElements = []
allFreeGameElements = []
bs = BeautifulSoup(html, 'html.parser')
# 获得页面所有的free game
try:
pageElements = bs.find_all('div', {'class': re.compile('article.*?free')})
except:
print('unable to find page elements-----')
return None
# 遍历存储目标元素,分为steam和所有两组储存,所有组包括了steam
for pageElement in pageElements:
try:
title = pageElement.find('h2').find('a').find('span').get_text()
if 'Steam' in title:
steamFreeGameElements.append(pageElement)
allFreeGameElements.append(pageElement)
except:
print('error iterate free elements-----')
return None
return steamFreeGameElements, allFreeGameElements
def pipeline(steamElements, allElements, steamOnly=True, verbose=False, openBrowser=True):
'''处理元素
提取元素中的有效信息, 其中以tuple array的形式存储
免费游戏的名称,描述和官网三个方面
Args:
steamElements: array, steam免费游戏元素
allElements: array, 所有的免费游戏元素
steamOnly: 是否只爬取steam内容
verbose: 是否更详细地打印日志
openBrowser: 爬取后是否直接打开游戏平台页面
Returns:
'''
game = tuple()
names = []
descriptions = []
urls = []
# 选择你需要的免费游戏的范围
targetElements = steamElements if steamOnly else allElements
# 开始操作
for element in targetElements:
detailPageUrl = element.find('h2').find('a')['href']
name, descr, url = getDetailPageInfo(dest_url + detailPageUrl)
# 打印日志
print(f'got a free game !\nname: {name}\ndescription: {descr}\nurl: {url}\n-----')
names.append(name)
descriptions.append(descr)
urls.append(url)
# 使用Chrome打开免费游戏网页
if openBrowser:
openInBrower(url)
logInfo = zip(names, descriptions, urls)
n = len(logInfo)
# 打印最终信息
if verbose:
print(f'页面爬取完成\nFound recently free game below, {n} games available:\n{logInfo}')
def getDetailPageInfo(url):
'''获得页面详细信息
Args:
url: 游戏信息详细页
Returns:
name: 游戏名称
description: 游戏描述和评价
officialUrl: 游戏发售界面
'''
r = request(url)
bs = BeautifulSoup(r, 'html.parser')
name = ''
description = ''
officialUrl = ''
# 获得名称信息
# 不推荐这种写法,一步一步找最合适
try:
nameTag = bs.find('div', {'class': 'bundleTitle'}).find('h1').get_text()
name = nameTag.split(':')[1].strip()
except:
print('unable to fetch name-----')
# 获得描述信息
try:
post = bs.find('div', {'class': 'article blogPostArticle'})
description = post.find('p', {'class': 'bold'}).get_text()
except:
print('unable to fetch description-----')
# 获得官网链接
try:
officialUrl = post.find('a', {'title': 'Get this great game for free!'})['href']
except:
print('unable to fetch official url-----')
return name, description, officialUrl
def openInBrower(url):
'''使用Chrome打开游戏页面
'''
driver = webdriver.Chrome()
driver.get(url)
if __name__ == "__main__":
# 多页遍历
pages = 3 # 改动这个数字,即可自定义爬取的页面范围
for page in range(pages):
url = dest_url + '?page={}'.format(page+1) if page!=0 else dest_url
handler(url)
感谢你阅读这篇博客代码的宝贵时间!成功地浏览了代码你肯定也发现了这段代码存在很多可以提升的空间,比如说
对免费游戏的渴望催促着我使用小半天完成了这段小代码,功能没有很多,也是自己周末图一乐,希望各位看得开心,玩得更开心:)