Скрапінг даних з оголошень 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 Коментаріїв