← Back to list

Raspagem de dados com loop (Tabela de melhores games dos últimos anos)

O objetivo final desse código é observar se há relação entre o jogos vencedores do Game Awards e os jogos com a maior nota do ano entre os…

Programador de Humanas · 2025-10-09 20:27 · 0 claps · 6.8 min read
#python #goty #jogos #metacritic #selenium
Open on Medium ↗

Raspagem de dados com loop (tabela de melhores jogos dos últimos anos)

O objetivo final desse código é observar se há relação entre o jogos vencedores do Game Awards e os jogos com a maior nota do ano entre os competidores. Para começar vou pegar o nome dos jogos que competiram em cada ano em uma tabela do wikipedia usando “beautifulsoup”. Depois vou pegar a nota de cada jogo no site Metacritic a partir da biblioteca “Selenium”.

Boa parte das bibliotecas não precisaram ser instaladas dado que usei o google colab.

import requests
from bs4 import BeautifulSoup
import pandas as pd
from io import StringIO
import re

Aqui configuro o agente que vai entrar no site.

headers = {"User-Agent": "Mozilla/5.0"}

Com o método “get( )” do módulo “requests”, faço a solicitação ao servidor para buscar o HTML da página.

response_wiki = requests.get(url, headers=headers)

Transformo o objeto html em formato beutifulsoup, uma forma mais organizada para o python ler.

soup = BeautifulSoup(response_wiki.content, "html.parser")

Com “find_all” procuro o elemento de classe “wikitable”, que é uma tabela da Wikipedia, dentro do html.

tabela = soup.find_all("table", class_= "wikitable")

Lê e salva a primeira tabela encontrada.

jogos_wiki = pd.read_html(StringIO(str(tabela[0])))[0]

jogos_wiki

Limpeza de dados

Agora vamos limpar os dados. Primeiro crio duas colunas novas. A coluna “win” é feita a partir da coluna “Game”. Todos os jogos que aparecem com “‡” vão aparecer como True, mas botando astype no final transformo True e False em 1 e 0.

O código para criar a coluna Status retorna a string “winner” para os jogos com o elemento “‡”, do contrário ele retorna 0.

A última linha utilizo “str.replace” para substituir “‡” por um elemento vazio.

jogos_tab = jogos_wiki.assign(
    win=jogos_wiki['Game'].str.contains("‡").astype(int),
    Status=["winner" if "‡" in Game else "0" for Game in jogos_wiki['Game']],
    Game=jogos_wiki['Game'].str.replace('‡', '')
)

Deixando os nomes apropriados para serem usados em links

Como meu objetivo é criar um loop em que o código acessa a página de cada jogo no metacritic, preciso de uma coluna com os nomes formatados no estilo que eles aparecem no link do site.

Para isso deixo todas as letras como minúsculas. Depois substituo todas as formas de espaço por hifen “-”. Uso o “normalize”, “encode” e “decode” ára retirar os caracteres especiais como acento. Retiro também caracteres como dois pontos, barra invertida, apostrofo e ponto ( r’[:\’.]’). Por final troco & por and e retiro o hífen que aparece no final de alguns nomes.

jogos_tab['urlname'] = (jogos_tab['Game']
                       .str.lower()
                       .str.replace(r'\s+', '-', regex=True)
                       .str.normalize('NFKD')
                       .str.encode('ascii', 'ignore')
                       .str.decode('utf-8')
                       .str.replace(r'[:\'.]', '', regex=True)
                       .str.replace('&', 'and', regex=True)
                       .str.strip('-')
                       )

Linhas duplicadas

É sempre importante verificar em uma base de dados se há linhas duplicadas. No caso dessa tabela havia uma. Para isso utilizo a função “drop_duplicates” onde informo qual a coluna que ele deve se basear e para manter a primeira linha encontrada.

jogos_tab.drop_duplicates(subset=['urlname'], keep='first', inplace=True)

jogos_tab

Usando Selenium para raspagem

Instalando pacotes

!pip install webdriver-manager
!apt-get update
!apt install chromium-chromedriver
!pip install selenium

Importando as bibliotecas

import pandas as pd
import time
import random
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from webdriver_manager.chrome import ChromeDriverManager

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

Criando uma lista vazia que vai receber os resultados das notas

resultados = []

Configurando a forma como o selenium vai acessar os sites

# 2️⃣ Configurar Selenium com Chrome
options = webdriver.ChromeOptions()
options.add_argument("--headless")  # roda sem abrir o navegador
options.add_argument("--no-sandbox") # Adiciona esta linha
options.add_argument("--disable-dev-shm-usage") # Adiciona esta linha
options.add_argument("--disable-blink-features=AutomationControlled")  # reduz detecção anti-bot
driver = webdriver.Chrome(options=options)

Para cada elemento (que chamei de “jogo”) da coluna “urlname” o python vai criar um link com esse nome adicionado no meio {jogo}. Ainda nessa iteração, o loop vai acessar esse link e baixar o html do site com “driver.get(url)”. Ele faz uma pausa aleatória para que o site não identifique que é um bot. Logo depois o código tenta encontrar o título do jogo e a nota dele no html. O resultado é adicionado na lista “resultados” com a função “.append”.

Cada iteração desse loop vai executar o que acabei de descrever. O python vai repetir esse mesmo código para cada jogo da coluna “urlname”.

for jogo in jogos_tab["urlname"]:
    url = f"https://www.metacritic.com/game/{jogo}/critic-reviews/"
    print(f"Coletando jogo: {jogo} -> {url}")

    try:
        driver.get(url) # requisita o site
        time.sleep(random.uniform(2, 4))  # pausa aleatória

        # Título
        try:
            titulo = driver.find_element(By.CSS_SELECTOR, "a.c-productSubpageHeader_back").text
        except:
            titulo = "Título não encontrado"

        # Nota
        try:
          nota = driver.find_element(By.CSS_SELECTOR, "div.c-siteReviewScore span").text
        except:
            nota = "Nota não encontrada"

        resultados.append({"jogo": jogo, "titulo": titulo, "nota": nota})

    except Exception as e:
        print(f"❌ Erro ao acessar {jogo}: {e}")
        resultados.append({"jogo": jogo, "titulo": None, "nota": None})
# 4️⃣ Fechar navegador
driver.quit()

Transformo essa lista em um dataframe do pandas.

df_result = pd.DataFrame(resultados)

df_result

Relação entre nota e vitória

O objetivo final de todo esse código é saber se há algum tipo de relação entre as notas compiladas pelo Metacritic e o jogo vencedor do Game Awards. Nessa fase irei inicialmente unir as tabelas do wikipedia e a tabela criada com as notas de cada jogo.

Para unir as tabelas utilizei a função “pd.merge” (merge = mesclar). Nela informo primeiro as tabelas que serão mescladas, depois as colunas de referência de cada tabela. No final uso o argumento “outer” para que se mantenham todas as linhas, isso porque caso um jogo esteja em uma tabela e em outra não é possível observar que houve esse erro. Sem isso a linha pode sumir e não haver a percepção de que houve um problema.

tab_unida = pd.merge(jogos_tab,
                        df_result,
                        left_on='urlname',
                        right_on='jogo',
                        how='outer')

tab_unida

Para organizar a tabela, estabeleço que ela vai ser organizada por ordem crescente em relação ao ano do evento e simultaneamente em ordem decrescente em relação as notas de cada jogo. Assim, para cada ano o primeiro jogo que aparece é o que tem a maior nota.

tab_unida = tab_unida.sort_values(
    by=['Event', 'nota'],
    ascending=[True, False]

)

É necessário que haja uma coluna que indique se aquele jogo teve a maior nota do ano dele. Para isso uso uma função que compara a maior nota do ano com a nota de cada célula da coluna nota e retorna True se aquela for a maior nota do ano e False se não.

tab_unida['Maiornota']= tab_unida['nota'] == tab_unida.groupby('Event')['nota'].transform('max')

tab_unida

Depois uso “astype(int)” para transformar True em 1 e False em 0, números inteiros.

tab_unida['Maiornota'] = tab_unida['Maiornota'].astype(int)

tab_unida

Agora sei se que jogos tiveram a maior nota do ano. Porém, quero saber quais os anos que o jogo de maior nota venceu o goty. Para isso eu crio uma função que verifica se há, para cada ano, alguma linha onde o jogo de maior nota também foi o campeão.

Depois agrupo a tabela por ano e aplico essa função para cada ano. Isso cria uma tabela que informa os anos em que isso aconteceu.

Por fim utilizo esse resultado para criar uma coluna.

# Cria uma função que verifica a condição dentro de cada grupo (ano)
def verifica_campeao_maior_nota(grupo):
    # Procura se há uma linha onde 'nota' e 'win' são ambos 1
    if ((grupo['Maiornota'] == 1) & (grupo['win'] == 1)).any():
        return 'Sim'
    else:
        return 'Não'

# Agrupa por ano e aplica a função, criando uma nova Series.
anos_vencedores = tab_unida.groupby('Event').apply(verifica_campeao_maior_nota)

# Adiciona a nova Series de volta ao DataFrame original como uma nova coluna
tab_unida['campeao_maior_nota_no_ano'] = tab_unida['Event'].map(anos_vencedores)

Para criar uma visualização mais adequada, crio uma tabela apenas com a coluna “Event”, que indica o ano da competição, e a coluna “campeao_maior_nota_no_ano”. Retiro as linhas duplicadas para que apresente apenas uma linha e um resultado por ano.

# Crie uma nova tabela apenas com as duas colunas que você precisa
tabela_resumo = tab_unida[['Event', 'campeao_maior_nota_no_ano']]

# Remova as linhas duplicadas para obter uma única resposta por ano
# O subset garante que a duplicação seja verificada apenas com base na coluna 'event'
tabela_resumo = tabela_resumo.drop_duplicates(subset=['Event'], keep='first')

# Opcional: Para melhor visualização, você pode renomear a coluna 'event' para 'Ano'
tabela_resumo.rename(columns={'Event': 'Ano'}, inplace=True)

tabela_resumo.reset_index(drop=True, inplace=True)

Nos últimos 11 anos em 6 o jogo com maior nota no metacritic foi campeão do goty. Nos últimos 5 anos os jogos com maior nota no metacritic ganharam o goty.

No entanto, olhando os dados como um todo percebi que é comum haver jogos com notas iguais. Como na tabela principal há uma coluna em que cada célula com o número 1 representa que aquele jogo teve a maior nota. Para verificar se houve mais de um jogo com essa mesma nota basta somar esses números por ano, os anos com números maiores que 1 são os que o jogo de maior nota esteve empatado com outros.

maiornota = tab_unida.groupby('Event')['Maiornota'].sum()

tabela2 = pd.merge(tabela_resumo,
                        maiornota,
                        left_on='Ano',
                        right_on='Event',
                        how='outer')

tabela2

No final fiz um resumo da tabela e depois abri no google planilhas.

tab = tab_unida[['Event', 'Game', 'Status', 'nota']]

tab


메타데이터
post_id
df674cf89cc9
slug
raspagem-de-dados-com-loop-tabela-de-melhores-games-dos-últimos-anos-df674cf89cc9
url
https://medium.com/@pedroruas95/raspagem-de-dados-com-loop-tabela-de-melhores-games-dos-%C3%BAltimos-anos-df674cf89cc9
canonical_url
https://medium.com/@pedroruas95/raspagem-de-dados-com-loop-tabela-de-melhores-games-dos-%C3%BAltimos-anos-df674cf89cc9
author_url
https://medium.com/@pedroruas95
status
ok
fetched_at
2026-06-20 20:29:01