Como fazer Web Scraping em Python

Como fazer Web Scraping em Python

Um tutorial sobre Web Scraping para montar datasets de esportes para seus projetos pessoais

Luis Felipe Bueno
Mar 13, 2019 Âˇ 7 min read
Source: Sabri Tuzcu

Uma das melhores maneiras de se praticar suas habilidades de Data Science e construir o seu portfĂłlio, ĂŠ trabalhando em projetos pessoais. Um dos melhores jeitos de encontrar um projeto para fazer ĂŠ com algo relacionado a seus gostos pessoais, como por exemplo, algum esporte.

Para trabalhar em seu projeto, ĂŠ possĂ­vel utilizar a seção de datasets do Kaggle para verificar se jĂĄ existe uma base do jeito que vocĂŞ quer. Caso nĂŁo exista, ĂŠ possĂ­vel extraĂ­-los do jeito que quiser de sites da Internet com o uso de tĂŠcnicas de Web Scraping.

Uma boa opção para estatĂ­sticas esportivas sĂŁo os sites do grupo Sports Reference. Eles trazem vĂĄrios tipos de estatĂ­sticas, desde as mais simples atĂŠ as avançadas sobre os mais variados esportes, como Basquete, Baseball e Futebol Americano, do universitĂĄrio ao profissional das mais diferentes ligas.

Sites do grupo Sports Reference

Como exemplo, usarei o site de Basquete para extrair dados da NBA, porÊm com os conhecimentos deste tutorial você serå capaz de extrair informaçþes de qualquer um dos outros sites com pequenas modificaçþes, tendo em vista que por serem da mesma empresa eles possuem o mesmo padrão.

Todo o cĂłdigo desse tutorial pode ser acessado nesse gist.

Bibliotecas utilizadas:

  • requests: biblioteca para execução de requisiçþes HTTP;
  • BeautifulSoup: biblioteca para extração de dados em arquivos HTML e XML;
  • Pandas: biblioteca para armazenar, limpar e salvar os dados em forma de tabela.

Usaremos as bibliotecas acima da seguinte forma: Usaremos arequests para executar requisiçþes GET e obter o cĂłdigo HTML das pĂĄginas que queremos; depois, utilizaremos a BeautifulSoup para extrair os dados que queremos destas pĂĄginas; por fim, salvaremos esses dados em um Data Frame do Pandas.

Extraindo tabelas de estatĂ­sticas

Como primeiro exemplo, vamos utilizar a pĂĄgina de EstatĂ­sticas Individuais Totais da temporada de 2017/2018 da NBA. Esta pĂĄgina contĂŠm uma Ăşnica tabela, onde cada linha representa um jogador e as respectivas informaçþes deles na Ăşltima temporada da NBA, como por exemplo a quantidade de minutos jogados e arremessos convertidos.

Utilizando a ferramenta de inspeção do navegador na tabela, podemos verificar que os dados estĂŁo armazenados em uma tabela HTML, representado pela tag table.

Utilizando a função Inspecionar para analisar o HTML.

Sabendo qual elemento devemos extrair da pågina HTML para conseguir os dados, Ê possível começar a parte da programação!

Primeiro, devemos importar a bibliotecas que serĂŁo usadas:

import pandas as pd
import requests
from bs4 import BeautifulSoup

O primeiro passo serĂĄ fazer uma requisição GET para a pĂĄgina. Para isso, devemos chamar o mĂŠtodo requests.get com a URL da pĂĄgina como argumento.

Este mĂŠtodo retorna um objeto Response que contĂŠm vĂĄrios informaçþes, das quais utilizaremos o status_code para verificar se a requisição retornou um status 200, indicando que ela foi bem sucedida, e content para acessar o cĂłdigo da pĂĄgina HTML.

req = requests.get('https://www.basketball-reference.com/leagues/NBA_2018_totals.html')if req.status_code == 200:
print('Requisição bem sucedida!')
content = req.content

Depois de obter o HTML da pĂĄgina, podemos utilizar a biblioteca BeautifulSoup para extrair a tabela. Primeiro, devemos criar um objeto que irĂĄ salvar o documento de maneira estruturada de acordo com as tags, e depois podemos acessar o elemento que quisermos chamando o mĂŠtodo find passando como argumento o nome da tag, no caso table.

soup = BeautifulSoup(content, 'html.parser')
table = soup.find(name='table')

Agora que temos o cĂłdigo HTML da tabela, podemos utilizar o Pandas para carregar os dados em um Data Frame, utilizando o mĂŠtodo read_html. Para isto, existem dois pontos para ficar atento: o primeiro ĂŠ que antes de passar a variĂĄvel ‘table’ na função, devemos convertĂŞ-la para string primeiro, tendo em vista que no momento ela ĂŠ um objeto do BeautifulSoup; o segundo ĂŠ que o retorno deste mĂŠtodo ĂŠ sempre uma lista de Data Frames, e portanto devemos acessar a posição 0 dela para obter nossa tabela.

table_str = str(table)
df = pd.read_html(table_str))[0]

E se a pĂĄgina tiver mais de uma tabela?

No caso anterior, a pĂĄgina continha somente uma tabela, entĂŁo havia somente uma tag table para extrair. No entanto, em muitas pĂĄginas existem vĂĄrias tabelas, como ĂŠ o caso da pĂĄgina de Classificaçþes da temporada de 2017/2018 da NBA, por exemplo. Neste caso, para obter uma tabela especĂ­fica existem duas opçþes:

  • A primeira ĂŠ substituir o mĂŠtodo find pelo find_all, que retorna uma lista de todos os elementos encontrados ao invĂŠs de um sĂł. Nesse caso, ĂŠ possĂ­vel acessar a tabela desejada verificando em qual posição do vetor ela se encontra.
  • A segunda ĂŠ utilizar o argumento attrs do mĂŠtodo find, passando um dicionĂĄrio que indica quais atributos o elemento obrigatoriamente deve ter para ser extraĂ­do. Por exemplo, considerando a pĂĄgina de classificaçþes citada acima e que queremos extrair as colocaçþes dos times na conferĂŞncia Oeste (Western Conference), usamos o inspetor para verificar que o id dessa tabela ĂŠ “confs_standings_W”. Portanto, o cĂłdigo ficaria da seguinte forma:
table = soup.find(name='table', attrs={'id':'confs_standings_W'})
Acesse o post e saiba com contribuir para o Data Hackers

Obtendo estatĂ­sticas de vĂĄrias temporadas

Agora que conseguimos extrair dados de uma Ăşnica pĂĄgina, seria interessante obter dados de vĂĄrias temporadas de uma sĂł vez. Comparando a URL de EstatĂ­sticas de 2018 com a de 2017, podemos ver que elas sĂŁo iguais, com exceção do nĂşmero do ano da temporada.

Com isso, ĂŠ possĂ­vel criar um loop que itere sobre uma lista de anos incluindo eles na URL e repetindo o processo da seção anterior para cada uma delas, montando uma grande tabela. Para obter uma lista de todos os anos em um certo intervalo, podemos usar a função range nativa do Python.

O cĂłdigo a seguir cria uma função que faz isso automaticamente, e usa ela para extrair as estatĂ­sticas totais de 2013 a 2018. Perceba que uma coluna Year ĂŠ criada em cada extração para que seja possĂ­vel diferenciar de qual ano cada estatĂ­stica pertence no DataFrame principal.

def scrape_stats(base_url, year_start, year_end):
years = range(year_start,year_end+1,1)

final_df = pd.DataFrame()

for year in years:
print('Extraindo ano {}'.format(year))
req_url = base_url.format(year)
req = requests.get(req_url)
soup = BeautifulSoup(req.content, 'html.parser')
table = soup.find('table', {'id':'totals_stats'})
df = pd.read_html(str(table))[0]
df['Year'] = year
final_df = final_df.append(df) return final_dfurl = 'https://www.basketball-reference.com/leagues/NBA_{}_totals.html'df = scrape_stats(url, 2013, 2018)

Pequeno exemplo de uso dos dados

Primeiro, algo importante a se fazer ĂŠ fazer uma pequena limpeza dos dados. Olhando a tabela no site, podemos ver que os nomes das colunas se repetem vĂĄrias vezes no meio dela. Podemos eliminar essas linhas do Data Frame da seguinte maneira:

drop_indexes = df[df['Rk'] == 'Rk'].index # Pega indexes onde a coluna 'Rk' possui valor 'Rk'
df.drop(drop_indexes, inplace=True) # elimina os valores dos index passados da tabela

Outra coisa que tem que ser feita ĂŠ converter os valores que representam nĂşmeros na tabela, pois quando o Panda pega a tabela do HTML, todos os dados sĂŁo lidos como objetos.

numeric_cols = df.columns.drop(['Player','Pos','Tm'])
df[numeric_cols] = df[numeric_cols].apply(pd.to_numeric)

Depois, ĂŠ possĂ­vel utilizar o Pandas em conjunto com bibliotecas comoMatplotlib eSeaborn para gerar visualizaçþes de dados interessantes.

Por exemplo, o grĂĄfico a seguir mostra a mĂŠdia de bolas de 3 pontos arremessadas por ano na NBA.

import matplotlib.pyplot as plt
import seaborn as sns
sns.barplot(x=’Year’, y=’3PA’)
GrĂĄfico de mĂŠdia de tentativas de arremessos de 3 pontos por temporada

Perceba como o número de bolas de 3 arremessadas aumentou consideravelmente nos últimos anos, indo de aproximadamente 90 para 120 entre 2013 e 2017, aonde atingiu uma estabilidade. Podemos concluir que nos últimos anos esse tipo de arremesso passou a ter cada vez mais importância no jogo.

JĂĄ que o volume de bolas de 3 aumentou consideravelmente, quais sĂŁo os jogadores que mais acertaram nesse perĂ­odo? Vamos verificar o top 5 de arremessadores com manipulaçþes do Pandas.

Gerando tabela de maiores nĂşmeros de arremessos de 3 pontos convertidos

Uau! O jogador Stephen Curry, da equipe do Golden State Warriors, ocupa 4 das 5 primeiras posiçþes do top 5, seguido de seu companheiro de equipe Klay Thompson! NĂŁo ĂŠ a toa que ele jĂĄ ĂŠ considerado um dos melhores arremessadores da histĂłria, e que seu time ganhou 3 dos 6 campeonatos disputados nesse perĂ­odo, alĂŠm de uma campanha histĂłrica de 73 vitĂłrias e somente 9 derrotas na Temporada Regular!

E se somarmos todas as bolas de 3 convertidas por jogadores nesse perĂ­odo, como ficaria o top 5?

Gerando tabela de soma de arremessos dados e convertidos dos Ăşltimos 5 anos

Podemos ver que Curry lidera com uma boa folga do segundo colocado, James Harden, e com uma quantidade menor de arremessos, o que mostra que ele foi mais eficiente do que Harden. AlĂŠm disso, podemos ver que tanto Curry quanto Harden arremessam muito mais bolas de 3 comparado aos outros jogadores no top 5.

Concluindo

Espero que este tutorial tenha te ajudado a entender como funciona o processo de Web Scraping e te inspire a começar seus projetos pessoais de Data Science sobre seu esporte favorito!

AlÊm de gerar vårias visualizaçþes de Dados interessantes, outra possibilidade seria gerar modelos de Machine Learning, para prever:

  • qual time tem mais chances de ser campeĂŁo;
  • quais serĂŁo os Novatos com maior evolução com base nos dados histĂłricos;
  • comparar jogadores de diferentes perĂ­odos de acordo com seu estilo de jogo;
  • quem serĂĄ o melhor jogador da temporada (PrĂŞmio de MVP).

Caso tenha alguma sugestĂŁo ou dĂşvida, fique a vontade para comentar ou me adicionar no LinkedIn para conversar sobre o artigo.

AtĂŠ mais!

Data Hackers

Blog oficial da comunidade Data Hackers

Luis Felipe Bueno

WRITTEN BY

Data Scientist @ IBM

Data Hackers

Data Hackers

Blog oficial da comunidade Data Hackers

ComentĂĄrios

Ebook

Postagens mais visitadas