Solucionado (ver solução)
Solucionado
(ver solução)
2
respostas

Erro no uso do 'for loop' para o objeto 'anuncios':

# Importando bibliotecas:
import pandas as pd
from urllib.request import Request, urlopen, urlretrieve
from urllib.error import URLError, HTTPError
from bs4 import BeautifulSoup

# Declarando variável cards:
cards = []

## Obtendo o HTML e o total de páginas:
url = 'https://rn.olx.com.br/rio-grande-do-norte/natal/imoveis/aluguel/apartamentos?o=1'
headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36'}
try:
    req = Request(url, headers=headers)
    response = urlopen(req)
    html = response.read().decode('utf-8')

except HTTPError as e:
    print(e.status, e.reason)

except URLError as e:
    print(e.reason)

# Criando o objeto soup:
soup = BeautifulSoup(html, 'html.parser')

# Número de páginas: *dependendo do site pode ser atomatizado ou coletado manualmente como nesse caso
pages = 29

## Iterando por todas as páginas do site:
for i in range(pages):
    ## Obtendo o HTML
    headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36'}
    req = Request('https://rn.olx.com.br/rio-grande-do-norte/natal/imoveis/aluguel/apartamentos?o=' + str(i + 1), headers=headers)
    response = urlopen(req)
    html = response.read().decode('utf-8')
    soup = BeautifulSoup(html, 'html.parser')

    # Obtendo as TAGs de interesse
    anuncios = soup.find('div', {"id": "column-main-content"}).findAll('div', class_="fnmrjs-2 jiSLYe")
    # Coletando as informações dos CARDS
    for anuncio in anuncios:
        card = {}

        # Nome do anúncio
        nome = anuncio.find("h2").getText()
        card['NOME'] = nome

        # Valor
        valor = anuncio.find("span", class_="sc-ifAKCX eoKYee").getText()
        card["VALOR"] = valor

        # Detalhes
        detalhe = anuncio.find("span", class_="sc-1j5op1p-0 lnqdIU sc-ifAKCX eLPYJb").get_text().split('|')
        card['DETALHES'] = detalhe

        # Endereço
        endereco = anuncio.find('span', class_="sc-7l84qu-1 ciykCV sc-ifAKCX hGjdHN").getText().split(', ')[1]
        card['ENDEREÇO'] = endereco

        # Adicionando resultado a lista cards
        cards.append(card)

# Criando um DataFrame com os resultados
dataset = pd.DataFrame(cards)
dataset

Tenho recebido o seguinte erro usando o método do curso e não sei como contornar.

" 49 # Valor

---> 50 valor = anuncio.find("span", class_="sc-ifAKCX eoKYee").getText() 51 card["VALOR"] = valor

AttributeError: 'NoneType' object has no attribute 'getText' "

Nesse caso, por usar 'anuncio' como o iterador, o objeto soup não é mais identificado? além disso é estranho como o erro não se deu na primeira variável "NOME".

2 respostas
solução!

Olá Lucas,

O problema é que nem sempre essa informação que você está selecionando está disponível, testando aqui eu vi que na página 7 do site tem esse anúncio:

Tudo que ele tem é o nome, valor e endereço, os detalhes estão faltando. Assim o seu código vai executado e lendo os dados corretamente por 7 páginas até que encontra esse caso onde o find de detalhe não vai encontrar o span.

Esse é um problema bem comum em scraping pois dificilmente a gente pode confiar que o site segue um único padrão, mas para contornar esse problema é bem simples, só precisamos verificar se o find encontrou algo antes de executar um get_text:

# Valor
span_valor = anuncio.find("span", class_="sc-ifAKCX eoKYee")
valor = span_valor.get_text() if span_valor else ''
card["VALOR"] = valor

# Detalhes
span_detalhe = anuncio.find("span", class_="sc-1j5op1p-0 lnqdIU sc-ifAKCX eLPYJb")
detalhe = span_detalhe.get_text().split('|') if span_detalhe else ''
card['DETALHES'] = detalhe

Colocando essa verificação em valor e detalhes o código executou até o fim sem erros, talvez depois seja necessário fazer a verificação para endereço também já que o site está sempre mudando.

Espero ter ajudado, qualquer coisa é só falar!

Obrigado!