Data Scraping das lojas do Buscapé com Python e Beautiful Soup

Nessa altura do campeonato todo mundo já sabe o que é Web Scraping, Scraping ou Data Scraping, mas vamos lá: É a varredura de um site ou de outro programa para extração de dados. Fiz isso a vida toda, aliás, meu primeiro estágio em 2002 envolvia muito disso, Eu pegava os dados de sites como Guia Mais, Listas OESP, etc, fazia o tratamento das informações e colocava em um mapa no qual os Gênios do Marketing utilizavam as informações pra fazer análises inteligentes de ações de marketing em áreas específicas. Eu achava o máximo!

Há a discussão se isso é legal ou não é legal, mas os dados estão abertos na internet e se não há nada especificado nos termos de uso do site então você pode sim fazer o data scraping. Inclusive o próprio Buscapé começou assim.

Um desses dias procurei na internet por alguma lista de e-commerces brasileiros e não achei nada, então pensei em ver se tinha alguma coisa no buscapé, já que ele agrega dezenas de e-commerces. Bom, achei essa página aqui que possui as informações das lojas cadastradas no buscapé: http://www.buscape.com.br/pesquise-uma-loja.html?pg=1.  Esse pg na query string é o número da página que estamos, obviamente.

Essa é a carinha da página:
buscape-pesquisa-uma-loja

 

Você pode ver que essa página é uma lista paginada das lojas cadastradas no buscapé. E isso se segue até a página 21270 mostrando 12 empresas por página.

buscape-rodape

E pra cada e-commerce que você clicar você vai ver várias informações sobre a empresa:

buscape-ricardo-eletro

 

Até aí, tudo fácil. Só achei a página com a lista de empresas, vi que ela tem uma paginação da página 1 até a página 21270, contém 12 lojas por página e que pra pegar as informações completas é necessário entrar no link de cada uma das lojas. Esse é o algoritmo, agora pra fazer isso acontecer tem que criar o script python.

Eu decidi criar 2 scripts, um para pegar o link de todas as lojas de cada uma das páginas da lista e o segundo para entrar em cada link de empresa e retirar essas informações colocando num Excel gigantesco.

Então, organizando, o primeiro script faz isso aqui:

  1. Encontrar qual elemento da página de listagem contém o link para as lojas
  2. Varrer todas as páginas de listagem para pegar os links individuais de cada página de loja
  3. Salvar esses links em um arquivo Excel (pode fazer de qquer outro jeito, eu quis assim)

Primeiro de tudo, você precisa encontrar na estrutura da página os elementos HTML e CSS que contêm os links que precismos retirar. Eu usei o Dev Tools do Chrome pra inspecionar o elemento e vi que todas as lojas estão em uma DIV que contém uma classe chamada size1of3 e é essa classe que vou utilizar para pegar todas as lojas. Dê uma olhada na figura:

buscape-div-loja

 

O trecho HTML das divs é normalmente assim:

<div class="unit size1of3">
 <div class="bp_shop_info line">
 <div class="shop_info_inner">
 <div class="main">
 <div class="leftCol name">
 <a data-preco="" title="Extra.com.br" href="http://www.buscape.com.br/empresa/avaliacao-sobre-extra-com-br--77.html">
 <img alt="Extra.com.br" src="http://imagem.buscape.com.br/vitrine/logo77.gif">
 </a>
 </div>
 <div class="features_wrapper main">
 <div class="line">
 <div class="speech_bubble_pointer">
 &nbsp;
 </div>
 <div class="inner">
 <div class="features_list main rounded_corner radius10">
 <ul class="features_inner">
 <li class="info_ebit_rating line">
 <a class="ico_ebit sprite_ico ebit_40 leftCol" title="Loja e-bit Excelente" target="_blank" href="http://www.ebit.com.br/lojas_virtuais/html/rateloja.asp?PnumNumEmpresa=2043">
 Loja E-bit e-bit Excelente
 </a>
 <div class="main">
 <a class="info_ebit ebit_ajuda" title="Loja e-bit Excelente" target="_blank" href="http://www.ebit.com.br/lojas_virtuais/html/rateloja.asp?PnumNumEmpresa=2043">
 e-bit Excelente
 </a>
 <span class="ratings">
 Avaliada por 
 <a href="http://www.buscape.com.br/empresa/avaliacao-sobre-extra-com-br--77.html">
 237.812 pessoas
 </a>
 </span>
 </div>
 </li>
 <li>
 <a title="Clique para ver mais informações" target="_blank" href="http://www.buscape.com.br/empresa/avaliacao-sobre-extra-com-br--77.html" class="sprite_ico info_shop">
 Mais detalhes da loja
 </a>
 </li>
 <li class="sprite_ico operation_area">
 Vende pela Internet
 </li>
 </ul>
 </div>
 </div>
 </div>
 </div>
 </div>
 </div>
 </div>
</div>

Dentro dessa div nós podemos pegar o primeiro link que aparece e extrair dele o title, que é o nome da loja e o href com o link para a página específica daquela loja. Eu escrevi isso em javascript mesmo, testei no Console e vi que funcionava


$('.size1of3').each(function() {var x =  $(this).find('a:first');console.log(x.attr('title') + ' ' + x.attr('href'))});

Agora vamos escrever o script em Python!


#URL http://www.buscape.com.br/pesquise-uma-loja.html?pg=1
#from 1 to 21265
# $('.size1of3').each(function() {var x = $(this).find('a:first');console.log(x.attr('title') + ' ' + x.attr('href'))});
import requests
import bs4
import openpyxl
import logging
from openpyxl import Workbook

#iniciar o arquivo de log
logging.basicConfig(filename='arq_links.log',level=logging.WARNING)

#iniciar a planilha do excel otimizada para escrita
wb = Workbook(write_only = True)
ws = wb.create_sheet()

for i in range(1,21266): 
    try:
       payload = {'pg':str(i)}
       response = requests.get('http://www.buscape.com.br/pesquise-uma-loja.html', params = payload)

       soup = bs4.BeautifulSoup(response.text)

       for div in soup.find_all(class_='size1of3'):
           ws.append([
           div.find('a')['title'], 
           div.find('a')['href'],
           'http://www.buscape.com.br/pesquise-uma-loja.html?pg=%s' % i,
           i,
       ])
 
       print "#%s" % i,

 except Exception as err:
     print "Erro na pagina %s" % i
     logging.exception(u"Erro na pagina %s" % i) 


wb.save('lojas.xlsx')

Estou usando o requests pra dar o GET na página e sempre passo como a query string (a variável payload) a página que quero dar GET.


payload = {'pg':str(i)}
response = requests.get('http://www.buscape.com.br/pesquise-uma-loja.html', params = payload)

Eu faço agora o parse desse resultado que vem no response.text usando o Beautiful Soup pra pegar apenas as informações que eu quero, no caso o nome da loja e o link para a página individual dela. Também resolvi salvar o link da página em que estou.

soup = bs4.BeautifulSoup(response.text)

for div in soup.find_all(class_='size1of3'):
    ws.append([
      div.find('a')['title'], 
      div.find('a')['href'],
      'http://www.buscape.com.br/pesquise-uma-loja.html?pg=%s' % i,
      i,
    ])

Estou usando o openpyxl que é excelente pra criar arquivos XLSX e também resolvi criar um log pra ver quais páginas podem ter dado errado por algum motivo. Assim é possível ver quais páginas ficaram de fora da sua lista e rodá-las novamente.

Enfim, rodando esse arquivo temos como saída um arquivo chamado lojas.xlsx com a lista de todas as lojas e com os links para a página individual delas. Então a parte um foi concluída, agora só falta entrar em cada uma dessas lojas e pegar os dados delas.

O segundo script deve fazer isso aqui:

  1. Vamos verificar como é o HTML + CSS de cada página de loja para saber como vamos fazer o scraping.
  2. Ler o arquivo excel gerado pelo primeiro script que contém o link de cada loja.
  3. Entrar em cada página e pegar os dados relevantes disponíveis
  4. Salvar tudo em um XLSX gigante

Pra verificar o formato HTML a gente pode inspecionar o elemento de novo dentro da página da loja. O que dá pra ver é que a div principal que contém os dados tem a classe company-header. Nessa div você pode pegar a classificação Ebit da loja, a descrição da loja e uma lista de informação de contatos que não é a mesma para todos os contatos, alguns tem informação como e-mail, telefone e outros não, então vamos ter que driblar (“Dibrar”) isso.

O bom é que todas essas informações de contato estão em uma lista e podemos pegar todos os elementos <li> desta lista e salvar em uma lista python. Depois podemos parsear essas informações e colocá-las em colunas certinhas num banco de dados, por enquanto só vou focar em pegar os dados.

O script fica assim:

import requests
import bs4
import openpyxl
import logging
from openpyxl import load_workbook
from openpyxl import Workbook

#iniciar o arquivo de log
logging.basicConfig(filename='arq_lojas.log',level=logging.WARNING)

#Abrindo o excel de leitura
wb = load_workbook(filename = 'lojas.xlsx', use_iterators = True)
ws = wb.get_sheet_by_name(name = 'Sheet1')

#iniciar a planilha do excel de excrita
wb_escrita = Workbook(write_only = True)
ws_escrita = wb_escrita.create_sheet()

for row in ws.iter_rows():
    try:
        nome = row[0].value
        url = row[1].value
        response = requests.get(url)
        soup = bs4.BeautifulSoup(response.text)

        div = soup.find(class_='company-header')
        ebit = ''
        if div.find('img'):
            if div.find('img').has_attr('title'):
                ebit = div.find('img')['title']

 
        desc = div.find(class_='about').string

        div = soup.find(class_='company-contacts')
        lista = []
        for li in div.find_all('li'):
            lista.append (li.text)

        ws_escrita.append(
            [nome,
            url,
            ebit,
            desc] + lista #Adicionando a lista de contatos daquela loja
        )
    except Exception as err:
        print "Erro na pagina %s" % url
        logging.exception(u"Erro na pagina %s" % url) 

wb_escrita.save('lojas_final.xlsx')

Ficou bem parecido com o primeiro arquivo. Agora é só executar os scripts. Execute o primeiro, ele vai demorar algumas horas até terminar, depois execute o segundo script. Aqui demorou bastante, quase 20 horas pra executar tudo.

O resultado final com os arquivos de excel e o código fonte você pode ver aqui no meu github: https://github.com/ffreitasalves/buscape-scraper