想知道最新的steam免费领取游戏?python爬虫来帮忙

文章目录

  • 前言
  • 代码特性
  • 源码
  • 还有更多

前言

疫情在家期间,玩玩游戏无疑是很好地放松休闲手段。而许多游戏在steam等平台上则通过限时免费领取的吸引更多玩家的参与,再加上上次差点就错过古墓丽影9的免费领取时间,看来我又需要python来做一个自动化爬虫小帮手了!

爬取免费游戏界面当然可以直接爬取steam,但是epic等发行平台也有许多相当不错的免费游戏。想要全面地了解世界范围内的限时免费领取游戏?epicbundle可以为我们提供想要的资源

进入网站,epicbundle呈现给了我们大量的游戏发售和免费游戏的信息,可惜的是,内容太多了,包括了免费游戏,bundle等大量内容,而且点击页面也需要多次跳转,这个时候,召唤python冲啊!

代码特性

代码不难,很多篇幅都是注释和异常检测,实实在在地简单易懂!这段代码实现了以下特性:

  • 交互基于控制台
  • 爬取epicbundle前三页的所有免费游戏,修改一个数字即可任意选择爬取的页面范围
  • 可浏览器自动打开免费游戏领取界面
  • user自定义游戏平台范围:多平台或者仅仅steam
  • 可以详细打印爬取信息,返回所有的爬取数据
  • 低强度反反爬虫: 实践证明epicbundle可以识别过快的页面请求,因此添加了请求头并且适当降低了request部分代码频率

源码

# 看库包就觉得很简单~
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)
    

还有更多

感谢你阅读这篇博客代码的宝贵时间!成功地浏览了代码你肯定也发现了这段代码存在很多可以提升的空间,比如说

  • 实现多线程处理
  • 代码统一封装成类
  • 深化面向对象,外部输入BeautifulSoup搜索关键词
  • 数据本地化
  • 打包代码exe封装(windows),不然不如直接去网站找呢:)哈哈
    。。。。。。

对免费游戏的渴望催促着我使用小半天完成了这段小代码,功能没有很多,也是自己周末图一乐,希望各位看得开心,玩得更开心:)

你可能感兴趣的:(电脑与生活)