Скрапинг данных из объявлений Airbnb с помощью Python

Комментарии: 0

Получение доступа к данным Airbnb является важным этапом при анализе рынка недвижимости. Это необходимо для исследования цен на аренду жилья и их динамики в рамках маркетинговых кампаний, проведения конкурентного анализа, оценки отзывов и рейтингов, и может быть достигнуто путем скрапинга веб-данных. Однако доступ к этим данным может быть ограничен, поскольку скрапинг может нарушать правила использования сайта.

Далее пошагово рассмотрим, как разработать веб-скрапер для извлечения данных из объявлений на Airbnb с помощью Python и Selenium и при этом избежать возможных блокировок и ограничений со стороны платформы.

Особенности архитектуры веб-сайта Airbnb

Первый шаг в создании веб-скрапера — понимание того, как получить доступ к интересующим нас веб-страницам, поскольку структура веб-сайтов может меняться со временем.

Чтобы понять структуру сайта, мы можем использовать инструменты разработчика браузера для изучения HTML веб-страницы. Для доступа к инструментам разработчика вы можете кликнуть правой кнопкой мыши и выбрать пункт “Просмотреть код элемента” или использовать сочетание клавиш:

  • “CTRL+SHIFT+I” для пользователей Windows;
  • “Option + ⌘ + I” для пользователей Mac.

Обратите внимание, что каждый контейнер с объявлением на Airbnb обернут в элемент “div” с определенным атрибутом класса: class=”g1qv1ctd”.

1.png

Для примера, выберем вкладку “location” и введем “London, UK”, таким образом получив доступ к предложениям по размещению в Лондоне. Веб-сайт предложит добавить даты заезда и выезда, что позволяет рассчитать стоимость проживания.

2.png

URL для этой страницы будет выглядеть примерно так:

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"

Исходя из страницы поиска, мы будем извлекать следующие атрибуты данных объявлений:

  • URL объявления;
  • Заголовок;
  • Описание;
  • Рейтинг;
  • Цена;
  • Дополнительная информация по объявлению (количество кроватей и доступные даты).

3.png

Создание скрипта для скрапинга данных с Airbnb

Прежде чем начать скрапинг, нужно настроить среду разработки. Вот шаги, которые нужно выполнить:

Шаг 1: Создание виртуальной среды

Виртуальные среды в Python — инструмент, который позволяет изолировать пакеты и их зависимости для разных проектов. Использование виртуальной среды помогает избежать конфликтов между библиотеками и обеспечивает наличие всех необходимых зависимостей в рамках конкретного проекта.

Создание виртуальной среды на Windows

Откройте командную строку с правами администратора и выполните следующую команду для создания новой виртуальной среды с именем “venv”:

python -m venv venv

Активируйте виртуальную среду:

venv\Scripts\activate

Создание виртуальной среды на macOS/Linux

Откройте терминал и выполните следующую команду для создания новой виртуальной среды с именем “venv”:

sudo python3 -m venv venv

Активируйте виртуальную среду:

source venv/bin/activate

Чтобы деактивировать виртуальную среду, выполните следующую команду:

deactivate

Шаг 2: Установка необходимых библиотек

После настройки виртуальной среды можно приступить к установке требуемых библиотек для скрапинга данных.

Обзор библиотек:

  • Selenium: этот инструмент позволяет программно управлять веб-браузером, взаимодействуя со страницами сайтов как реальный пользователь — нажимая на кнопки, заполняя формы и выполняя навигацию по сайту.
  • Seleniumwire: расширяет возможности Selenium, добавляя функции для перехвата и анализа HTTP-запросов, а также поддержку прокси, что особенно полезно для сложных задач по веб-скрапингу.
  • BeautifulSoup4: библиотека для разбора HTML и XML. Она облегчает извлечение данных из веб-страниц, позволяя выбирать интересующие элементы с помощью простого и понятного API.
  • lxml: высокопроизводительный парсер HTML и XML, который часто используется вместе с BeautifulSoup для ускорения и оптимизации процесса разбора данных.

В активированной виртуальной среде выполните следующую команду:

pip install selenium beautifulsoup4 lxml seleniumwire

Драйверы Selenium

Для работы с Selenium необходим специальный драйвер, который будет осуществлять взаимодействие с выбранным браузером. В данном руководстве мы будем использовать браузер Chrome, но важно установить соответствующий WebDriver для выбранного браузера. После загрузки убедитесь, что драйвер расположен в каталоге, который включен в переменную среды PATH вашей операционной системы. Это позволит Selenium автоматически находить драйвер и управлять браузером.

Шаг 3: Импорт библиотек

В начале Python-файла импортируйте Seleniumwire и BeautifulSoup, а также другие необходимые библиотеки с помощью следующих команд:

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

Мы также импортируем библиотеки “random”, “time” и “csv” для различных вспомогательных функций.

Шаг 4: Интеграция прокси

Далее мы загружаем список прокси, чтобы избежать блокировки со стороны Airbnb. При попытке отправить запрос без использования приватного прокси пользователь может столкнуться с ответом “Access Denied”.

4.png

Настройка прокси выполняется следующим образом:

# Список прокси-серверов
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",

]

Убедитесь, что заменили “Your_proxy_IP_Address”, “Your_proxy_port”, а также “username” и “password” на актуальные данные.

Шаг 5: Настройка прокси с ротацией

Ротация прокси — ключевой элемент успешного веб-скрапинга. Веб-сайты часто блокируют доступ, когда замечают множество запросов с одного IP-адреса. Ротация различных прокси позволяет замаскировать активность, имитируя работу множества обычных пользователей и обойти анти-скрапинговые системы безопасности.

Для настройки ротации прокси сначала импортируйте библиотеку “random”. Затем создайте функцию “get_proxy()”, которая будет выбирать прокси из предоставленного списка случайным образом, используя метод “random.choice()”, и возвращать выбранный прокси.

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

Шаг 6: Настройка WebDriver

Далее мы создаем основную функцию под названием “listings()”. В этой функции настраивается "ChromeDriver", также она использует Selenium для навигации по странице с объявлениями о недвижимости, ожидает загрузки страницы и анализирует HTML с помощью 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"
    )  # Замените на ваш путь к ChromeDriver
    driver = webdriver.Chrome(
        service=s, seleniumwire_options=proxy_options, chrome_options=chrome_options
    )

    driver.get(url)

    time.sleep(8)  # Настройте в зависимости от времени загрузки сайта

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

    driver.quit()

В этой функции сначала выбирается случайный прокси и настраиваются его опции, которые в дальнейшем используются для конфигурации WebDriver. Далее настраиваются опции Chrome, включая аргумент "--headless", что позволяет браузеру работать в фоновом режиме без графического интерфейса.

Затем WebDriver инициализируется с указанными сервисом, опциями seleniumwire и Chrome, что, в свою очередь, используется для перехода по заданному URL. Время ожидания в 8 секунд позволяет странице полностью загрузиться, после чего с помощью Beautiful Soup производится анализ возвращенного HTML. По завершении анализа WebDriver закрывается.

Шаг 7: Поиск и извлечение данных из объявления

Следующий этап после получения HTML-содержимого страницы включает в себя извлечение данных из каждого объявления. Используя библиотеку BeautifulSoup, мы можем эффективно производить навигацию по структуре HTML и определять элементы, содержащие нужную нам информацию.

Извлечение элементов объявлений

Для начала нужно определить все элементы объявления на странице, которые содержат необходимые нам данные: URL объявления, заголовок, описание, рейтинг, цену и другую релевантную информацию.

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

Этот код использует метод “find_all()” библиотеки BeautifulSoup для поиска всех элементов “div” с классом “g1qv1ctd”. Эти элементы представляют собой отдельные объявления на странице Airbnb. Затем скрипт перебирает каждый из этих элементов для извлечения соответствующих данных.

Извлечение URL объявления

Для каждого найденного элемента объявления производится извлечение URL.

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

В этом фрагменте кода мы исследуем объект “soup” на предмет наличия тега анкора с классом “rfexzly”. Если такой элемент найден, из него извлекается атрибут “href”, содержащий URL. Этот URL затем добавляется к базовому адресу Airbnb для формирования полного URL объявления. В случае отсутствия элемента присваивается пустая строка, чтобы предотвратить возможные ошибки в выполнении кода.

Извлечение заголовка объявления

Сначала мы извлечем URL каждого объявления. Это позволит нам в дальнейшем посетить страницы каждого из этих объявлений, если это будет необходимо.

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

Далее, для извлечения заголовка объявления, мы обращаемся к элементу “div” с классом “t1jojoys”. Из этого элемента извлекается текстовое содержимое, при этом удаляются все начальные и конечные пробелы для чистоты данных. В случае отсутствия такого элемента в объявлении сохраняется пустая строка, чтобы избежать ошибок при обработке данных.

Извлечение описания объявления

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

Так же, как и при извлечении заголовка, этот код находит элемент “” с классом “t6mzqp7”. Затем из этого элемента извлекается и очищается текстовое содержимое, которое представляет собой краткое описание объявления.

Извлечение рейтинга объявления

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

Как видно из кода выше, элемент “span” с классом “ru0q88m” содержит значение рейтинга. Мы извлекаем это значение, убедившись, что лишние пробелы удалены.

Извлечение цены объявления

Наконец, мы извлекаем цену объявления.

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

Этот код находит элемент с классом “._1y74zjx” в текущем элементе объявления. Если этот элемент, который обычно содержит информацию о цене, найден, его текстовое содержимое извлекается, очищается и дополняется фразой “per night”, формируя таким образом более информативную строку с ценой.

Извлечение дополнительной информации из объявления

Некоторые объявления могут содержать дополнительную информацию, которую мы можем извлечь.

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 ""
)

Мы ищем элемент “” с атрибутом aria-hidden=”true” для поиска дополнительной информации об объявлении. После того как все релевантные данные из каждого элемента объявления извлечены, мы добавляем собранные данные в список объявлений.

listings.append(listing_data)

Как только все объявления обработаны, мы возвращаем список объявлений, где каждое объявление представлено в виде словаря, содержащего извлеченные данные.

return listings

Шаг 8: Запись данных в файл CSV

После успешного сбора данных со страниц объявлений Airbnb следующим важным шагом является сохранение этой информации для будущего анализа и справки. Для этой задачи мы используем библиотеку csv. Сначала открываем файл CSV в режиме записи и создаём объект csv.DictWriter. Затем мы записываем заголовок и данные в файл.

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}")

Ниже представлена полная версия кода, используемого в ходе данного туториала:

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

# Список прокси-серверов
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"
    )  # Замените на ваш путь к ChromeDriver
    driver = webdriver.Chrome(
        service=s, seleniumwire_options=proxy_options, chrome_options=chrome_options
    )

    driver.get(url)

    time.sleep(8)  # Настройте в зависимости от времени загрузки сайта

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

    driver.quit()

    listings = []

    # Найдите все элементы объявлений на странице
    listing_elements = soup.find_all("div", class_="g1qv1ctd")

    for listing_element in listing_elements:
       # Извлеките данные из каждого элемента объявления
        listing_data = {}

        # URL объявления
        URL_element = soup.find("a", class_="rfexzly")
        listing_data["Listing URL"] = (
            "https://www.airbnb.com" + URL_element["href"] if URL_element else ""
        )

        # Заголовок
        title_element = listing_element.find("div", class_="t1jojoys")
        listing_data["Title"] = (
            title_element.get_text(strip=True) if title_element else ""
        )

       # Описание
        Description_element = listing_element.find("span", class_="t6mzqp7")
        listing_data["Description"] = (
            Description_element.get_text(strip=True) if Description_element else ""
        )

        # Рейтинг
        rating_element = listing_element.find("span", class_="ru0q88m")
        listing_data["Rating"] = (
            rating_element.get_text(strip=True) if rating_element else ""
        )

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

        # Дополнительная информация объявления
        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 ""
        )

        # Добавьте данные объявления в список
        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}")

Эта часть кода обеспечивает сохранение собранных данных в файл CSV под названием “proxy_web_listings_output.csv”.

Результаты

Результаты работы нашего скрапера сохраняются в файл CSV в формате показанном ниже на скриншоте.

5.jpg

Данная инструкция эффективна для извлечения данных из объявлений Airbnb с помощью Python и позволяет собирать важную информацию о недвижимости, включая цены, доступность и отзывы. Использование прокси и настройка их ротации — важный шаг, чтобы избежать блокировки со стороны механизмов защиты Airbnb от ботов.

Комментарии:

0 комментариев