Recolha de dados de anúncios do Airbnb com Python

Comentários: 0

Obter acesso aos dados da Airbnb é crucial para analisar o mercado imobiliário, pesquisar a dinâmica dos preços de aluguer, realizar análises competitivas e avaliar críticas e classificações. Isto pode ser conseguido através da recolha de dados da Web. No entanto, aceder a estes dados pode ser um desafio, uma vez que a recolha de dados pode violar os termos de utilização do site.

Em seguida, vamos explorar um guia passo a passo sobre como desenvolver um raspador da Web para extrair dados de anúncios do Airbnb usando Python e Selenium. Este guia também abordará a forma de evitar potenciais bloqueios e restrições impostos pela plataforma.

Compreender a arquitetura do sítio Web da Airbnb

O primeiro passo para criar um Web scraper é compreender como aceder às páginas Web em que está interessado, uma vez que a estrutura dos sítios Web pode mudar frequentemente. Para se familiarizar com a estrutura de um sítio, pode utilizar as ferramentas de desenvolvimento do browser para inspecionar o HTML da página Web.

Para aceder às Ferramentas de Programador, clique com o botão direito do rato na página Web e selecione "Inspecionar" ou utilize o atalho:

  • CTRL+SHIFT+I para Windows;
  • Opção + ⌘ + I no Mac.

Cada contentor de listagem é envolvido por um elemento div com o seguinte atributo: class="g1qv1ctd".

1.png

Ao clicar em "localização" e escrever "Londres, Reino Unido", podemos aceder à localização oferecida em Londres. O sítio Web sugere que se acrescentem as datas de entrada e de saída. Isto permite-lhes calcular o preço dos quartos.

2.png

O URL para esta página seria mais ou menos assim:

url = "https://www.airbnb.com/s/London--United-Kingdom/homes?tab_id=home_tab&refinement_paths%5B%5D=%2Fhomes&flexible_trip_lengths%5B%5D=one_week&monthly_start_date=2024-01-01&monthly_length=3&price_filter_input_type=0&channel=EXPLORE&query=London%2C%20United%20Kingdom&place_id=ChIJdd4hrwug2EcRmSrV3Vo6llI&date_picker_type=calendar&source=structured_search_input_header&search_type=autocomplete_click"

A partir da página de pesquisa, iremos extrair os seguintes atributos dos dados da listagem de produtos:

  • Listing URL;
  • Título;
  • Descrição;
  • Classificação;
  • Preço;
  • Informações Adicionais do Anúncio (Nº de camas e datas disponíveis).

3.png

Guia passo-a-passo para criar um programa de raspagem do Airbnb

To start web scraping for Airbnb data, you need to set up your development environment first. Here are the steps to do that:

Passo 1: Criando um ambiente virtual

Os ambientes virtuais permitem-lhe isolar os pacotes Python e as suas dependências para diferentes projectos. Isso ajuda a evitar conflitos e garante que cada projeto tenha as dependências corretas instaladas.

Criação de um ambiente virtual no Windows

Abra uma linha de comandos com privilégios de administrador e execute o seguinte comando para criar um novo ambiente virtual com o nome "venv":

python -m venv venv

Ativar o ambiente virtual:

venv\Scripts\activate

Criando um ambiente virtual no macOS/Linux

Abra um terminal e execute o seguinte comando para criar um novo ambiente virtual chamado "venv":

sudo python3 -m venv venv

Ativar o ambiente virtual:

source venv/bin/activate

Para desativar o ambiente virtual, basta executar o seguinte comando:

deactivate

Passo 2: Instalando as bibliotecas necessárias

Agora que tem um ambiente virtual configurado, pode instalar as bibliotecas necessárias.

Compreender as bibliotecas:

  • Selenium: Esta poderosa ferramenta de raspagem da Web permite-lhe controlar programaticamente um navegador da Web. Isto permite-lhe interagir com as páginas Web, incluindo clicar em botões, preencher formulários e navegar pelas páginas como se fosse um utilizador real.
  • Seleniumwire: Esta biblioteca estende o Selenium, permitindo intercetar e inspecionar solicitações HTTP e integrar proxies com suas operações de raspagem. Isso é muito importante, pois o Selenium não tem suporte nativo a proxy.
  • BeautifulSoup4: Esta é uma biblioteca projetada para analisar arquivos HTML e XML. Ela ajuda a extrair informações específicas de páginas da web de forma estruturada e eficiente.
  • lxml: Um analisador rápido e robusto de HTML e XML que complementa o BeautifulSoup.

No seu ambiente virtual ativado, execute o seguinte comando para instalar as bibliotecas necessárias:

pip install selenium beautifulsoup4 lxml seleniumwire

Drivers do Selenium

O Selenium requer um driver para fazer a interface com o navegador escolhido. Neste guia, usaremos o Chrome. No entanto, certifique-se de ter instalado o WebDriver apropriado para o navegador de sua escolha.

Uma vez descarregado, certifique-se de que o controlador é colocado num diretório acessível pela variável de ambiente PATH do seu sistema. Isto permitirá ao Selenium encontrar o controlador e controlar o browser.

Passo 3: Importar bibliotecas

No início do seu ficheiro Python, importe as bibliotecas Seleniumwire e BeautifulSoup. É assim que se faz:

from seleniumwire import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from bs4 import BeautifulSoup
import time
import csv
import random

Nós também importaremos as bibliotecas `random`, `time` e `csv` para vários utilitários.

Passo 4: Integração do proxy

Em seguida, definimos uma lista de proxies para evitar que sejam bloqueados pelo Airbnb. Ao tentar enviar uma solicitação sem um proxy premium, você pode encontrar uma resposta "Acesso negado".

4.png

Pode configurar um proxy da seguinte forma:

# Lista de procuradores
proxies = [
     "username:password@Your_proxy_IP_Address:Your_proxy_port1",
     "username:password@Your_proxy_IP_Address:Your_proxy_port2",
     "username:password@Your_proxy_IP_Address:Your_proxy_port3",
     "username:password@Your_proxy_IP_Address:Your_proxy_port4",
     "username:password@Your_proxy_IP_Address:Your_proxy_port5",

]

Certifique-se de que substitui "Your_proxy_IP_Address" e "Your_proxy_port" pelo endereço proxy real que obteve do Proxy-seller e substitua também os valores de "username" e "password" pelas suas credenciais reais.

Passo 5: Rotação de proxies

A rotação de proxies é um aspeto crucial da recolha de dados da Web. Os sítios Web bloqueiam ou restringem frequentemente o acesso a bots e scrapers quando recebem vários pedidos do mesmo endereço IP. Ao alternar entre diferentes endereços IP proxy, pode evitar a deteção, aparecer como vários utilizadores orgânicos e contornar a maioria das medidas anti-raspagem implementadas no sítio Web.

Para configurar a rotação de proxy, importe a biblioteca "random". Também definimos uma função `get_proxy()` para selecionar uma proxy da nossa lista. Esta função seleciona aleatoriamente um proxy da lista de proxies usando o método random.choice() e retorna o proxy selecionado.

def get_proxy():
    return random.choice(proxies)

Passo 6: Configurar o WebDriver

Em seguida, definimos a função principal chamada `listings()`. É aqui que configuraremos nosso "ChromeDriver". Essa função usa o Selenium para navegar na página de listagem de propriedades, aguarda o carregamento da página e analisa o HTML usando o Beautiful Soup.

def listings(url):

    proxy = get_proxy()
    proxy_options = {
        "proxy": {
            "http": f"http://{proxy}",
            "https": f"http://{proxy}",
            "no_proxy": "localhost,127.0.0.1",
        }
    }

    chrome_options = Options()
    chrome_options.add_argument("--headless")
  

    s = Service(
        "C:/Path_To_Your_WebDriver"
    )  # Substituir pelo caminho para o ChromeDriver
    driver = webdriver.Chrome(
        service=s, seleniumwire_options=proxy_options, chrome_options=chrome_options
    )

    driver.get(url)

    time.sleep(8)  # Ajustar com base no tempo de carregamento do sítio Web

    soup = BeautifulSoup(driver.page_source, "lxml")

    driver.quit()

Aqui, começamos selecionando um proxy aleatório e configurando as opções de proxy. Essas opções serão usadas para configurar o webdriver para usar o servidor proxy. Em seguida, configuramos as opções do Chrome. Adicione o argumento --headless para executar o navegador no modo headless, o que significa que o navegador será executado em segundo plano sem uma interface gráfica do usuário.

Em seguida, inicialize o webdriver com o serviço, as opções do seleniumwire e as opções do Chrome. O webdriver é então usado para navegar até o URL fornecido. Adicionamos um tempo de espera de 8 segundos para permitir que a página seja carregada completamente e, em seguida, analisamos o HTML retornado usando Beautiful Soup. Depois que a análise é concluída, ele fecha o webdriver.

Passo 7: Encontrar e extrair os dados da listagem

Depois de obter com êxito o conteúdo HTML, o próximo passo é extrair os dados relevantes para cada anúncio. Com a BeautifulSoup, podemos navegar facilmente pela estrutura HTML e localizar os elementos que contêm as informações do anúncio.

Extração de elementos de listagem

Primeiro, identificamos todos os elementos do anúncio na página. Estes elementos contêm os dados que nos interessam, como o URL do anúncio, o título, a descrição, a classificação, o preço e as informações adicionais.

listing_elements = soup.find_all("div", class_="g1qv1ctd")
for listing_element in listing_elements:

Este código usa o método find_all() do BeautifulSoup para localizar todos os elementos div com a classe "g1qv1ctd". Esses elementos representam anúncios individuais na página do Airbnb. Em seguida, ele percorre cada um desses elementos de anúncio para extrair os dados relevantes.

Extração de URL de listagem

Para cada elemento de listagem encontrado, extraímos o URL da listagem.

URL_element = soup.find("a", class_="rfexzly")
listing_data["Listing URL"] = (
    "https://www.airbnb.com" + URL_element["href"] if URL_element else ""
)

Aqui, procuramos no nosso objeto "soup" por uma etiqueta âncora com a classe "rfexzly". Se encontrar este elemento, extrai o atributo 'href' (que contém o URL relativo) e anexa-o ao URL de base para criar o URL de listagem completo. Se o elemento não for encontrado, atribui uma cadeia vazia para evitar erros.

Extração do título da listagem

Primeiro, vamos extrair o URL de cada anúncio. Isto permitir-nos-á visitar as páginas de cada anúncio mais tarde, se necessário.

title_element = listing_element.find("div", class_="t1jojoys")
listing_data["Title"] = (
    title_element.get_text(strip=True) if title_element else ""
)

O título está contido num elemento "div" com a classe "t1jojoys". Recuperamos o conteúdo de texto deste elemento, removendo qualquer espaço em branco à frente ou atrás. É guardada uma cadeia vazia se o elemento não for encontrado.

Extração da descrição do anúncio

Description_element = listing_element.find("span", class_="t6mzqp7")
listing_data["Description"] = (
    Description_element.get_text(strip=True) if Description_element else ""
)

À semelhança da extração do título, este código encontra um elemento span com a classe "t6mzqp7". Em seguida, extraímos e limpamos o conteúdo de texto deste elemento, que contém uma breve descrição do anúncio.

Extração da classificação da listagem

rating_element = listing_element.find("span", class_="ru0q88m")
listing_data["Rating"] = (
    rating_element.get_text(strip=True) if rating_element else ""
)

Como se vê no código acima, um elemento span com a classe "ru0q88m" contém o valor da classificação. Extraímos este valor, certificando-nos de que retiramos qualquer espaço em branco desnecessário.

Extração do preço de listagem

Por fim, extraímos o preço do anúncio.

price_element = listing_element.select_one("._1y74zjx")
listing_data["Price"] = (
    f"{price_element.get_text(strip=True)} per night" if price_element else ""
)

Este código localiza o elemento com a classe "_1y74zjx" dentro do elemento_da_listagem_actual. Se este elemento, que normalmente contém a informação de preço, for encontrado, o seu conteúdo de texto é extraído, limpo e acrescentado com "por noite" para formar uma cadeia de preços mais informativa.

Extração de informações adicionais da listagem

Algumas listagens podem conter informações adicionais que podemos extrair.

listing_info_element = listing_element.find("span", {"aria-hidden": "true"})
listing_data["Additional Listing information"] = (
    listing_info_element.get_text(strip=True) if listing_info_element else ""
)

Procuramos um elemento span com o atributo aria-hidden="true" para encontrar quaisquer informações adicionais sobre o anúncio. Depois de extrair todos os dados relevantes de cada elemento de listagem, anexamos os dados recolhidos a uma lista de listagens.

listings.append(listing_data)

Depois de todas as listagens terem sido processadas, devolvemos a lista de listagens, cada uma representada como um dicionário que contém os dados extraídos.

return listings

Passo 8: Escrever dados num ficheiro CSV

Depois de ter conseguido extrair dados das páginas de anúncios do Airbnb, o próximo passo importante é armazenar essas informações valiosas para análise e referência futuras. Usamos a biblioteca csv para essa tarefa. Abrimos um arquivo CSV no modo de gravação e criamos um objeto csv.DictWriter. Em seguida, escrevemos o cabeçalho e os dados no ficheiro.

airbnb_listings = listings(url)

csv_file_path = "proxy_web_listings_output.csv"

with open(csv_file_path, "w", encoding="utf-8", newline="") as csv_file:
    fieldnames = [
        "Listing URL",
        "Title",
        "Description",
        "Rating",
        "Price",
        "Additional Listing information",
    ]
    writer = csv.DictWriter(csv_file, fieldnames=fieldnames)
    writer.writeheader()
    for listing in airbnb_listings:
        writer.writerow(listing)

print(f"Data has been exported to {csv_file_path}")

Aqui está o código completo que utilizámos para este tutorial:

from seleniumwire import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from bs4 import BeautifulSoup
import time
import csv
import random

# Lista de procuradores
proxies = [ 
 "username:password@Your_proxy_IP_Address:Your_proxy_port1",
 "username:password@Your_proxy_IP_Address:Your_proxy_port2",
 "username:password@Your_proxy_IP_Address:Your_proxy_port3",
 "username:password@Your_proxy_IP_Address:Your_proxy_port4",
 "username:password@Your_proxy_IP_Address:Your_proxy_port5",
]

def get_proxy():
    return random.choice(proxies)


def listings(url):

    proxy = get_proxy()
    proxy_options = {
        "proxy": {
            "http": f"http://{proxy}",
            "https": f"http://{proxy}",
            "no_proxy": "localhost,127.0.0.1",
        }
    }

    chrome_options = Options()
    chrome_options.add_argument("--headless")
  

    s = Service(
        "C:/Path_To_Your_WebDriver"
    )  # Substituir pelo caminho para o ChromeDriver
    driver = webdriver.Chrome(
        service=s, seleniumwire_options=proxy_options, chrome_options=chrome_options
    )

    driver.get(url)

    time.sleep(8)  # Ajustar com base no tempo de carregamento do sítio Web

    soup = BeautifulSoup(driver.page_source, "lxml")

    driver.quit()

    listings = []

    # Encontrar todos os elementos de listagem na página
    listing_elements = soup.find_all("div", class_="g1qv1ctd")

    for listing_element in listing_elements:
        # Extrair dados de cada elemento da listagem
        listing_data = {}

        # URL da listagem
        URL_element = soup.find("a", class_="rfexzly")
        listing_data["Listing URL"] = (
            "https://www.airbnb.com" + URL_element["href"] if URL_element else ""
        )

        # Título
        title_element = listing_element.find("div", class_="t1jojoys")
        listing_data["Title"] = (
            title_element.get_text(strip=True) if title_element else ""
        )

        # Descrição
        Description_element = listing_element.find("span", class_="t6mzqp7")
        listing_data["Description"] = (
            Description_element.get_text(strip=True) if Description_element else ""
        )

        # Classificação
        rating_element = listing_element.find("span", class_="ru0q88m")
        listing_data["Rating"] = (
            rating_element.get_text(strip=True) if rating_element else ""
        )

        # Preço
        price_element = listing_element.select_one("._1y74zjx")
        listing_data["Price"] = (
            f"{price_element.get_text(strip=True)} per night" if price_element else ""
        )

        # Informações adicionais sobre o anúncio
        listing_info_element = listing_element.find("span", {"aria-hidden": "true"})
        listing_data["Additional Listing information"] = (
            listing_info_element.get_text(strip=True) if listing_info_element else ""
        )

        # Anexar os dados da listagem à lista
        listings.append(listing_data)

    return listings


url = "https://www.airbnb.com/s/London--United-Kingdom/homes?tab_id=home_tab&refinement_paths%5B%5D=%2Fhomes&flexible_trip_lengths%5B%5D=one_week&monthly_start_date=2024-01-01&monthly_length=3&price_filter_input_type=0&channel=EXPLORE&query=London%2C%20United%20Kingdom&place_id=ChIJdd4hrwug2EcRmSrV3Vo6llI&date_picker_type=calendar&source=structured_search_input_header&search_type=autocomplete_click"


airbnb_listings = listings(url)

csv_file_path = "proxy_web_listings_output.csv"

with open(csv_file_path, "w", encoding="utf-8", newline="") as csv_file:
    fieldnames = [
        "Listing URL",
        "Title",
        "Description",
        "Rating",
        "Price",
        "Additional Listing information",
    ]
    writer = csv.DictWriter(csv_file, fieldnames=fieldnames)
    writer.writeheader()
    for listing in airbnb_listings:
        writer.writerow(listing)

print(f"Data has been exported to {csv_file_path}")

Esta parte do código garante que os dados extraídos são armazenados num ficheiro CSV com o nome "proxy_web_listings_output.csv".

Resultados

Os resultados do nosso "scraper" são guardados num ficheiro CSV chamado "proxy_web_listings_output.csv", como se pode ver abaixo.

5.jpg

Este guia explica de forma eficaz como extrair dados de anúncios da Airbnb usando Python, permitindo a extração de detalhes importantes, como preços, disponibilidade e avaliações. Ele enfatiza a importância de usar proxies e rotacioná-los para evitar que sejam bloqueados pelas medidas anti-bot do Airbnb.

Comentários:

0 Comentários