Curso
Em uma era em que a internet está repleta de dados e, aparentemente, os dados viraram o novo petróleo, o web scraping se tornou ainda mais importante e prático para diversas aplicações. Web scraping é o processo de extrair informações de sites. Também é chamado de web harvesting ou extração de dados da web. Copiar um texto de um site e colá-lo no seu computador também é web scraping — porém, manual. No geral, quando falamos em web scraping, estamos nos referindo à extração automática de dados com a ajuda de web crawlers. Web crawlers são scripts que se conectam à web via protocolo HTTP e permitem buscar dados de forma automatizada.
Se você é cientista de dados, engenheiro ou qualquer pessoa que analisa grandes volumes de dados, saber extrair dados da web é uma habilidade valiosa. Suponha que você encontre dados on-line e não haja uma forma direta de baixá-los: usar Python para web scraping é uma habilidade que permite extrair essas informações para um formato útil e, depois, importar e trabalhar com elas de várias maneiras.
Algumas aplicações práticas de web scraping:
- Coletar currículos de candidatos com uma habilidade específica,
- Extrair tweets do Twitter com determinadas hashtags,
- Geração de leads em marketing,
- Raspar detalhes de produtos e avaliações em e-commerces como a Amazon — foco deste tutorial
Além desses casos, o web scraping é amplamente usado em processamento de linguagem natural para extrair textos de sites e treinar modelos de deep learning.
Antes de prosseguir, lembre-se de que sites como a Amazon podem atualizar seus termos de uso específicos ou criar novas restrições técnicas que afetam como o conteúdo pode ser acessado ou reutilizado. É sua responsabilidade revisar os Termos de Serviço e o arquivo robots.txt do site para garantir que seu caso de uso esteja em conformidade. As políticas podem mudar e as permissões variam.
Possíveis desafios do web scraping
-
Um dos desafios ao coletar informações de sites é a variedade de estruturas. Os templates mudam de um site para outro e costumam ser únicos; por isso, generalizar pode ser complicado.
-
Outro desafio é a durabilidade. Como desenvolvedores atualizam seus sites com frequência, você não pode contar com o mesmo scraper por muito tempo. Mesmo mudanças pequenas podem atrapalhar a coleta.
Para contornar esses desafios, há algumas alternativas. Uma é adotar integração e entrega contínuas (CI/CD) e manutenção constante, já que as modificações do site são dinâmicas.
Outra abordagem, mais realista em muitos casos, é usar APIs (Application Programming Interfaces) oferecidas por sites e plataformas. Por exemplo, Facebook e Twitter fornecem APIs pensadas para desenvolvedores que querem experimentar com seus dados ou extrair informações — digamos, sobre amigos e amigos em comum — e montar um grafo de conexões. O formato dos dados via API costuma ser JSON ou XML, diferente do scraping tradicional, em que você lida principalmente com HTML.
O que é Beautiful Soup?
Beautiful Soup é uma biblioteca puramente em Python para extrair dados estruturados de sites. Ela permite fazer parsing de dados em arquivos HTML e XML. Funciona como um módulo auxiliar e interage com o HTML de forma semelhante (e muitas vezes melhor) à interação que você teria com a página usando ferramentas de desenvolvedor.
-
Gera economia de horas (ou dias) de trabalho, pois funciona com parsers como
lxmlehtml5libpara oferecer formas "Pythonicas" de navegar, buscar e modificar a árvore de parsing. -
Outro recurso poderoso do Beautiful Soup é converter automaticamente documentos de entrada para Unicode e documentos de saída para UTF-8. Como desenvolvedor, você não precisa se preocupar com isso — a menos que o documento não especifique a codificação ou o Beautiful Soup não consiga detectá-la.
-
Também costuma ser mais rápido em comparação com outras técnicas gerais de parsing ou scraping.
Tipos de parsers
Fique à vontade para saber mais neste link.
Chega de teoria, né? Vamos instalar o Beautiful Soup e explorar seus recursos e capacidades com Python.
No primeiro passo, você precisa instalar a biblioteca Beautiful Soup pelo terminal ou no Jupyter Lab. A melhor forma é via pip, então certifique-se de que o módulo pip já está instalado.
!pip3 install beautifulsoup4
Requirement already satisfied: beautifulsoup4 in /usr/local/lib/python3.7/site-packages (4.7.1)
Requirement already satisfied: soupsieve>=1.2 in /usr/local/lib/python3.7/site-packages (from beautifulsoup4) (1.9.5)
Importando as bibliotecas necessárias
Vamos importar os pacotes necessários para extrair os dados do site e visualizá-los com seaborn, matplotlib e bokeh.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
import re
import time
from datetime import datetime
import matplotlib.dates as mdates
import matplotlib.ticker as ticker
from urllib.request import urlopen
from bs4 import BeautifulSoup
import requests
Fazendo scraping dos livros mais vendidos da Amazon
O URL que vamos raspar é este: https://www.amazon.in/gp/bestsellers/books/. O parâmetro de página pode ser modificado para acessar os dados de cada página. Para obter todas as páginas, você precisará fazer um loop por todas elas e construir o dataset. Antes, porém, é preciso descobrir o número de páginas no site.
Para se conectar ao URL e obter o conteúdo HTML, você vai precisar de:
- Definir uma função
get_dataque receba o número da página como argumento, - Definir um
user-agentpara ajudar a evitar a detecção como scraper, - Passar o URL para
requests.gete incluir o cabeçalho de user-agent, - Extrair o conteúdo retornado por requests.get,
- Fazer o parsing da página especificada e atribuí-la à variável
soup,
O próximo passo, e um dos mais importantes, é identificar a tag pai sob a qual ficam todos os dados de que você precisa. Os dados que vamos extrair são:
- Nome do livro
- Autor
- Avaliação
- Número de clientes que avaliaram
- Preço
A imagem abaixo mostra onde está a tag pai; ao passar o mouse, todos os elementos necessários são destacados.

Assim como a tag pai, você precisa encontrar os atributos para nome do livro, autor, avaliação, número de clientes e preço. Vá até a página que deseja raspar, selecione o atributo, clique com o botão direito e escolha "inspecionar elemento". Isso ajuda a localizar os campos específicos que você precisa extrair do HTML bruto, como mostrado na figura a seguir:

Observe que alguns nomes de autores não estão cadastrados na Amazon; então, você precisará usar um find adicional para esses casos. No código abaixo, há condicionais if-else aninhadas para extrair nomes de autores/publicações.
no_pages = 2
def get_data(pageNo):
headers = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0", "Accept-Encoding":"gzip, deflate", "Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "DNT":"1","Connection":"close", "Upgrade-Insecure-Requests":"1"}
r = requests.get('https://www.amazon.in/gp/bestsellers/books/ref=zg_bs_pg_'+str(pageNo)+'?ie=UTF8&pg='+str(pageNo), headers=headers)#, proxies=proxies)
content = r.content
soup = BeautifulSoup(content)
#print(soup)
alls = []
for d in soup.findAll('div', attrs={'class':'a-section a-spacing-none aok-relative'}):
#print(d)
name = d.find('span', attrs={'class':'zg-text-center-align'})
n = name.find_all('img', alt=True)
#print(n[0]['alt'])
author = d.find('a', attrs={'class':'a-size-small a-link-child'})
rating = d.find('span', attrs={'class':'a-icon-alt'})
users_rated = d.find('a', attrs={'class':'a-size-small a-link-normal'})
price = d.find('span', attrs={'class':'p13n-sc-price'})
all1=[]
if name is not None:
#print(n[0]['alt'])
all1.append(n[0]['alt'])
else:
all1.append("unknown-product")
if author is not None:
#print(author.text)
all1.append(author.text)
elif author is None:
author = d.find('span', attrs={'class':'a-size-small a-color-base'})
if author is not None:
all1.append(author.text)
else:
all1.append('0')
if rating is not None:
#print(rating.text)
all1.append(rating.text)
else:
all1.append('-1')
if users_rated is not None:
#print(price.text)
all1.append(users_rated.text)
else:
all1.append('0')
if price is not None:
#print(price.text)
all1.append(price.text)
else:
all1.append('0')
alls.append(all1)
return alls
O código abaixo realiza as seguintes funções:
- Chama a função
get_datadentro de um laçofor, - O
foritera a partir de 1 até o número de páginas + 1, - Como a saída é uma lista aninhada, primeiro achatamos a lista e então a passamos para um DataFrame,
- Por fim, salvamos o DataFrame em um arquivo CSV.
results = []
for i in range(1, no_pages+1):
results.append(get_data(i))
flatten = lambda l: [item for sublist in l for item in sublist]
df = pd.DataFrame(flatten(results),columns=['Book Name','Author','Rating','Customers_Rated', 'Price'])
df.to_csv('amazon_products.csv', index=False, encoding='utf-8')
Lendo o arquivo CSV
Agora vamos carregar o arquivo CSV que você criou e salvou acima. Esta etapa é opcional; você pode usar o DataFrame df diretamente e pular o passo abaixo.
df = pd.read_csv("amazon_products.csv")
df.shape
(100, 5)
O shape do DataFrame mostra que há 100 linhas e 5 colunas no seu arquivo CSV.
Vamos imprimir as primeiras 5 linhas do conjunto de dados.
df.head(61)
| Book Name | Author | Rating | Customers_Rated | Price | |
|---|---|---|---|---|---|
| 0 | The Power of your Subconscious Mind | Joseph Murphy | 4.5 out of 5 stars | 13,948 | ₹ 99.00 |
| 1 | Think and Grow Rich | Napoleon Hill | 4.5 out of 5 stars | 16,670 | ₹ 99.00 |
| 2 | Word Power Made Easy | Norman Lewis | 4.4 out of 5 stars | 10,708 | ₹ 130.00 |
| 3 | Mathematics for Class 12 (Set of 2 Vol.) Exami... | R.D. Sharma | 4.5 out of 5 stars | 18 | ₹ 930.00 |
| 4 | The Girl in Room 105 | Chetan Bhagat | 4.3 out of 5 stars | 5,162 | ₹ 149.00 |
| ... | ... | ... | ... | ... | ... |
| 56 | COMBO PACK OF Guide To JAIIB Legal Aspects Pri... | MEC MILLAN | 4.5 out of 5 stars | 114 | ₹ 1,400.00 |
| 57 | Wren & Martin High School English Grammar and ... | Rao N | 4.4 out of 5 stars | 1,613 | ₹ 400.00 |
| 58 | Objective General Knowledge | Sanjiv Kumar | 4.2 out of 5 stars | 742 | ₹ 254.00 |
| 59 | The Rudest Book Ever | Shwetabh Gangwar | 4.6 out of 5 stars | 1,177 | ₹ 194.00 |
| 60 | Sita: Warrior of Mithila (Ram Chandra Series -... | Amish Tripathi | 4.4 out of 5 stars | 3,110 | ₹ 248.00 |
61 rows × 5 columns
Vamos fazer um pré-processamento nas colunas Rating, Customers_Rated e Price.
- Como as avaliações vão até 5, mantenha apenas o valor da nota e remova o restante do texto.
- Na coluna customers_rated, remova as vírgulas.
- Na coluna price, remova o símbolo de rúpia, as vírgulas e faça o split pelo ponto.
- Por fim, converta as três colunas para inteiro ou float.
df['Rating'] = df['Rating'].apply(lambda x: x.split()[0])
df['Rating'] = pd.to_numeric(df['Rating'])
df["Price"] = df["Price"].str.replace('₹', '')
df["Price"] = df["Price"].str.replace(',', '')
df['Price'] = df['Price'].apply(lambda x: x.split('.')[0])
df['Price'] = df['Price'].astype(int)
df["Customers_Rated"] = df["Customers_Rated"].str.replace(',', '')
df['Customers_Rated'] = pd.to_numeric(df['Customers_Rated'], errors='ignore')
df.head()
| Book Name | Author | Rating | Customers_Rated | Price | |
|---|---|---|---|---|---|
| 0 | The Power of your Subconscious Mind | Joseph Murphy | 4.5 | 13948 | 99 |
| 1 | Think and Grow Rich | Napoleon Hill | 4.5 | 16670 | 99 |
| 2 | Word Power Made Easy | Norman Lewis | 4.4 | 10708 | 130 |
| 3 | Mathematics for Class 12 (Set of 2 Vol.) Exami... | R.D. Sharma | 4.5 | 18 | 930 |
| 4 | The Girl in Room 105 | Chetan Bhagat | 4.3 | 5162 | 149 |
Vamos verificar os tipos de dados do DataFrame.
df.dtypes
Book Name object
Author object
Rating float64
Customers_Rated int64
Price int64
dtype: object
Substitua os valores zero no DataFrame por NaN.
df.replace(str(0), np.nan, inplace=True)
df.replace(0, np.nan, inplace=True)
Contando a quantidade de NaNs no DataFrame
count_nan = len(df) - df.count()
count_nan
Book Name 0
Author 6
Rating 0
Customers_Rated 0
Price 1
dtype: int64
Pelo resultado acima, dá para observar que há seis livros sem nome de autor e um livro sem preço. Essas informações são cruciais para quem quer vender seus livros e não deveriam ser omitidas.
Vamos remover esses NaNs.
df = df.dropna()
Livro de maior preço por autor na Amazon
Vamos descobrir quais autores têm os livros com maior preço. Vamos visualizar os 20 principais autores.
data = df.sort_values(["Price"], axis=0, ascending=False)[:15]
data
| Book Name | Author | Rating | Customers_Rated | Price | |
|---|---|---|---|---|---|
| 56 | COMBO PACK OF Guide To JAIIB Legal Aspects Pri... | MEC MILLAN | 4.5 | 114 | 1400.0 |
| 98 | Diseases of Ear, Nose and Throat | P L Dhingra | 4.7 | 118 | 1285.0 |
| 3 | Mathematics for Class 12 (Set of 2 Vol.) Exami... | R.D. Sharma | 4.5 | 18 | 930.0 |
| 96 | Madhymik Bhautik Vigyan -12 (Part 1-2) (NCERT ... | Kumar-Mittal | 5.0 | 1 | 765.0 |
| 6 | My First Library: Boxset of 10 Board Books for... | Wonder House Books | 4.5 | 3116 | 750.0 |
| 38 | Indian Polity - For Civil Services and Other S... | M. Laxmikanth | 4.6 | 1210 | 700.0 |
| 42 | A Modern Approach to Verbal & Non-Verbal Reaso... | R.S. Aggarwal | 4.4 | 1822 | 675.0 |
| 27 | The Intelligent Investor (English) Paperback –... | Benjamin Graham | 4.4 | 6201 | 650.0 |
| 99 | Law of CONTRACT & Specific Relief | Dr. Avtar Singh | 4.4 | 23 | 643.0 |
| 49 | All In One ENGLISH CORE CBSE Class 12 2019-20 | Arihant Experts | 4.4 | 493 | 599.0 |
| 72 | The Secret | Rhonda Byrne | 4.5 | 11220 | 556.0 |
| 86 | How to Prepare for Quantitative Aptitude for t... | Arun Sharma | 4.4 | 847 | 537.0 |
| 8 | Quantitative Aptitude for Competitive Examinat... | R S Aggarwal | 4.4 | 4553 | 435.0 |
| 16 | Sapiens: A Brief History of Humankind | Yuval Noah Harari | 4.6 | 14985 | 434.0 |
| 84 | Concept of Physics Part-2 (2019-2020 Session) ... | H.C. Verma | 4.6 | 1807 | 433.0 |
from bokeh.models import ColumnDataSource
from bokeh.transform import dodge
import math
from bokeh.io import curdoc
curdoc().clear()
from bokeh.io import push_notebook, show, output_notebook
from bokeh.layouts import row
from bokeh.plotting import figure
from bokeh.transform import factor_cmap
from bokeh.models import Legend
output_notebook()
p = figure(x_range=data.iloc[:,1], plot_width=800, plot_height=550, title="Authors Highest Priced Book", toolbar_location=None, tools="")
p.vbar(x=data.iloc[:,1], top=data.iloc[:,4], width=0.9)
p.xgrid.grid_line_color = None
p.y_range.start = 0
p.xaxis.major_label_orientation = math.pi/2
show(p)

Pelo gráfico acima, dá para ver que os dois livros com maior preço são dos autores Mecmillan e P L Dhingra.
Livros mais bem avaliados por autor
Vamos descobrir quais autores têm os livros mais bem avaliados e quais são esses títulos. Para isso, vamos filtrar apenas autores com pelo menos 1000 avaliações de clientes.
data = df[df['Customers_Rated'] > 1000]
data = data.sort_values(['Rating'],axis=0, ascending=False)[:15]
data
| Book Name | Author | Rating | Customers_Rated | Price | |
|---|---|---|---|---|---|
| 26 | Inner Engineering: A Yogi’s Guide to Joy | Sadhguru | 4.7 | 4091 | 254.0 |
| 70 | Bhagavad-Gita (Hindi) | A. C. Bhaktivedanta | 4.7 | 1023 | 150.0 |
| 11 | The Alchemist | Paulo Coelho | 4.7 | 22182 | 264.0 |
| 47 | Harry Potter and the Philosopher's Stone | J.K. Rowling | 4.7 | 7737 | 234.0 |
| 84 | Concept of Physics Part-2 (2019-2020 Session) ... | H.C. Verma | 4.6 | 1807 | 433.0 |
| 16 | Sapiens: A Brief History of Humankind | Yuval Noah Harari | 4.6 | 14985 | 434.0 |
| 38 | Indian Polity - For Civil Services and Other S... | M. Laxmikanth | 4.6 | 1210 | 700.0 |
| 29 | Wings of Fire: An Autobiography of Abdul Kalam | Arun Tiwari | 4.6 | 3513 | 301.0 |
| 39 | The Theory of Everything | Stephen Hawking | 4.6 | 2004 | 199.0 |
| 25 | The Immortals of Meluha (Shiva Trilogy) | Amish | 4.6 | 4538 | 248.0 |
| 23 | Life's Amazing Secrets: How to Find Balance an... | Gaur Gopal Das | 4.6 | 3422 | 213.0 |
| 34 | Dear Stranger, I Know How You Feel | Ashish Bagrecha | 4.6 | 1130 | 167.0 |
| 17 | The Monk Who Sold His Ferrari | Robin Sharma | 4.6 | 5877 | 137.0 |
| 13 | How to Win Friends and Influence People | Dale Carnegie | 4.6 | 15377 | 99.0 |
| 59 | The Rudest Book Ever | Shwetabh Gangwar | 4.6 | 1177 | 194.0 |
p = figure(x_range=data.iloc[:,0], plot_width=800, plot_height=600, title="Top Rated Books with more than 1000 Customers Rating", toolbar_location=None, tools="")
p.vbar(x=data.iloc[:,0], top=data.iloc[:,2], width=0.9)
p.xgrid.grid_line_color = None
p.y_range.start = 0
p.xaxis.major_label_orientation = math.pi/2
show(p)

Pelo gráfico acima, os três livros mais bem avaliados com mais de 1000 avaliações são Inner Engineering: A Yogi’s Guide to Joy, Bhagavad-Gita (Hindi) e The Alchemist.
p = figure(x_range=data.iloc[:,1], plot_width=800, plot_height=600, title="Top Rated Books with more than 1000 Customers Rating", toolbar_location=None, tools="")
p.vbar(x=data.iloc[:,1], top=data.iloc[:,2], width=0.9)
p.xgrid.grid_line_color = None
p.y_range.start = 0
p.xaxis.major_label_orientation = math.pi/2
show(p)

O gráfico acima mostra, em ordem decrescente, os 10 autores com livros mais bem avaliados e mais de 1000 avaliações de clientes: Sadhguru, A. C. Bhaktivedanta e Paulo Coelho estão no topo.
Autores e livros com mais avaliações de clientes
Você já viu os livros e autores com melhores notas, mas também é importante avaliar credibilidade pelo volume de avaliações. Vamos concluir quais são o melhor autor e o melhor livro com base no número de clientes que avaliaram.
Bora descobrir.
data = df.sort_values(["Customers_Rated"], axis=0, ascending=False)[:20]
data
| Book Name | Author | Rating | Customers_Rated | Price | |
|---|---|---|---|---|---|
| 11 | The Alchemist | Paulo Coelho | 4.7 | 22182 | 264.0 |
| 1 | Think and Grow Rich | Napoleon Hill | 4.5 | 16670 | 99.0 |
| 13 | How to Win Friends and Influence People | Dale Carnegie | 4.6 | 15377 | 99.0 |
| 16 | Sapiens: A Brief History of Humankind | Yuval Noah Harari | 4.6 | 14985 | 434.0 |
| 18 | Rich Dad Poor Dad : What The Rich Teach Their ... | Robert T. Kiyosaki | 4.5 | 14591 | 296.0 |
| 10 | The Subtle Art of Not Giving a F*ck | Mark Manson | 4.4 | 14418 | 365.0 |
| 0 | The Power of your Subconscious Mind | Joseph Murphy | 4.5 | 13948 | 99.0 |
| 48 | The Power of Your Subconscious Mind | Joseph Murphy | 4.5 | 13948 | 99.0 |
| 72 | The Secret | Rhonda Byrne | 4.5 | 11220 | 556.0 |
| 41 | 1984 | George Orwell | 4.5 | 10829 | 95.0 |
| 2 | Word Power Made Easy | Norman Lewis | 4.4 | 10708 | 130.0 |
| 46 | Man's Search For Meaning: The classic tribute ... | Viktor E Frankl | 4.4 | 8544 | 245.0 |
| 67 | The 7 Habits of Highly Effective People | R. Stephen Covey | 4.3 | 8229 | 397.0 |
| 47 | Harry Potter and the Philosopher's Stone | J.K. Rowling | 4.7 | 7737 | 234.0 |
| 40 | One Indian Girl | Chetan Bhagat | 3.8 | 7128 | 113.0 |
| 65 | Thinking, Fast and Slow (Penguin Press Non-Fic... | Daniel Kahneman | 4.4 | 7087 | 410.0 |
| 27 | The Intelligent Investor (English) Paperback –... | Benjamin Graham | 4.4 | 6201 | 650.0 |
| 17 | The Monk Who Sold His Ferrari | Robin Sharma | 4.6 | 5877 | 137.0 |
| 53 | Ram - Scion of Ikshvaku (Ram Chandra) | Amish Tripathi | 4.2 | 5766 | 262.0 |
| 93 | The Richest Man in Babylon | George S. Clason | 4.5 | 5694 | 129.0 |
from bokeh.transform import factor_cmap
from bokeh.models import Legend
from bokeh.palettes import Dark2_5 as palette
import itertools
from bokeh.palettes import d3
#colors has a list of colors which can be used in plots
colors = itertools.cycle(palette)
palette = d3['Category20'][20]
index_cmap = factor_cmap('Author', palette=palette,
factors=data["Author"])
p = figure(plot_width=700, plot_height=700, title = "Top Authors: Rating vs. Customers Rated")
p.scatter('Rating','Customers_Rated',source=data,fill_alpha=0.6, fill_color=index_cmap,size=20,legend='Author')
p.xaxis.axis_label = 'RATING'
p.yaxis.axis_label = 'CUSTOMERS RATED'
p.legend.location = 'top_left'
BokehDeprecationWarning: 'legend' keyword is deprecated, use explicit 'legend_label', 'legend_field', or 'legend_group' keywords instead
show(p)

O gráfico acima é um diagrama de dispersão que cruza a avaliação média com o número de clientes que avaliaram para cada autor. Algumas conclusões:
- Sem dúvida, The Alchemist, de Paulo Coelho, é o best-seller: a nota e o volume de avaliações caminham juntos.
- O livro Ram - Scion of Ikshvaku (Ram Chandra), de Amish Tripathi, tem nota 4,2 com 5.766 avaliações. Já The Richest Man in Babylon, de George S. Clason, tem volume de avaliações semelhante, mas nota 4,5. Ou seja, mais clientes deram notas altas para The Richest Man in Babylon.
Conclusão
Parabéns por concluir o tutorial!
Este foi um guia introdutório para fazer scraping na Amazon com Beautiful Soup e visualizar os dados extraídos usando a biblioteca de gráficos Bokeh. Um bom próximo passo em web scraping com Beautiful Soup é raspar dados de outros sites e explorar os insights. Também temos um tutorial sobre scraping no Reddit se você quiser mais orientação sobre sites populares.
Se você está começando em Python e quer aprender mais, faça o curso Introduction to Data Science in Python da DataCamp.
