CoderCastrov logo
CoderCastrov
Парсер

Парсинг данных о недвижимости с использованием API ChatGPT

Парсинг данных о недвижимости с использованием API ChatGPT
просмотров
8 мин чтение
#Парсер

Я работал в фонде недвижимости довольно долго и всегда интересовался рынком, поэтому я всегда искал способ понять его, увидеть общую картину и правильно оценить стоимость недвижимости. Для этого я обычно парсил данные о недвижимости в своем городе и следовал следующим шагам.

  1. Парсинг нескольких сайтов и получение широты и долготы, а также цены, количества комнат, площади и некоторых других деталей.

  2. Обратное геокодирование широты и долготы для получения адреса, города, района и страны.

  3. Расчет доходности недвижимости для района путем взятия недвижимости в аренду и получения средней цены аренды за квадратный метр для района из объявлений об аренде, а также получения средней цены продажи за квадратный метр для района из объявлений о продаже. Затем применяется следующая формула: ((средняя_аренда_за_квм_в_районе * 12) / средняя_цена_за_квм_в_районе) * 100.

Это фактически расчет капитализации, который выглядит так: (Валовый доход - расходы = чистый доход) / цена покупки * 100, но без расходов. Таким образом, это не идеальный способ, но очень сложно правильно учесть расходы на недвижимость, так как есть много переменных. Поскольку каждое здание в основном очень разное, затраты могут сильно варьироваться. Так что то, что я буду строить здесь, будет всего лишь быстрым показателем рынка, усредняющим все. Конечно, при покупке недвижимости проводите свою собственную предварительную проверку и рассчитывайте капитализацию.

Но теперь к самой теме... парсинг сайтов с использованием Beautifulsoup или Scrapy существует уже довольно долго, а также использование Selenium для очень сложных сайтов. Но для каждого сайта нам нужно настраивать код и по существу поддерживать его каждый раз, когда сайт вносит даже самые малые изменения в свой дизайн и HTML, поэтому каждый парсинг-код становится бесконечной борьбой между нами, пытающимися получить данные, и оригинальным сайтом, изменяющим дизайн. Здесь я не вдаваюсь в вопрос о законности парсинга в этой статье, так как по этому вопросу есть судебное решение. Web scraping is legal, US appeals court reaffirms | TechCrunch

Итак, теперь наш друг ChatGPT вступает в игру. Замечательный инструмент для подачи информации, ее извлечения и краткого изложения. Когда я открыл для себя этот замечательный инструмент, первая мысль, которая пришла мне в голову, была... как я могу использовать его программно? К счастью, OpenAI выпустила API (chat.openai.com), и также есть пакет для Python. openai · PyPI, поэтому теперь вопрос только в том, как подать данные в ChatGPT, чтобы получить результаты.

Теперь давайте попробуем это сделать с помощью Idealista, так как я ищу квартиру в солнечном Барселоне. Это действительно хороший сайт, и у них есть более простой способ доступа к данным, с помощью API. Request API access (idealista.com), поэтому мне на самом деле не нужно делать это. Всегда проверяйте.

Но я не собираюсь спамить их сайт и просто спаршу 1 страницу для понимания возможностей ChatGPT по извлечению текста.

Итак, начнем!

Сначала определим шаги нашей разработки.

    1. Настройка, получение ключа OpenAI, установка компонентов.
    1. Использование запроса для получения HTML с сайта.
    1. Использование Beautifulsoup для извлечения всего текста из HTML.
    1. Использование API OpenAI для извлечения данных из текста и преобразования их в JSON.
    1. Убедитесь, что вывод является корректным JSON.

1. Установка и настройка, получение ключа OpenAI и установка компонентов

Сначала нам нужно установить необходимые пакеты. Нам понадобятся 4 компонента, поэтому установим их с помощью pip: requests для получения HTML, beautifulsoup для удаления тегов HTML, openai для запроса к OpenAI и rich для красивого вывода информации для устранения ошибок.

python -m pip install requests, openai, beautifulsoup4, rich

Затем нам нужно получить ключ API от OpenAI, который вы должны сможете получить здесь: API keys — OpenAI API

2. Использование requests для получения HTML с сайта

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

Мне очень понравилась эта квартира: Piso en venta en calle de Bailèn, La Dreta de l’Eixample, Barcelona — idealista

Давайте использовать ее. Всегда проверяйте код ответа, чтобы убедиться, что он равен 200, и выводите HTML-код для проверки.

import requests

url = "https://www.idealista.com/inmueble/99172111/"
response = requests.get(
    url,
    headers={
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3",
        "Referer": "https://www.google.com",
        "Accept-Language": "en-US,en;q=0.9",
    },
)
if response.status_code == 200:
    html = response.text

3. Используйте beautiful soup для извлечения всего текста из HTML

После получения HTML-кода следующим шагом будет удаление всего, что нам не нужно. Это будут теги HTML, которые в основном являются просто шумом. Давайте удалим их и будем работать только с самим текстом. Также мы должны уменьшить количество пробелов и удалить все символы новой строки \n, так как они увеличивают объем текста, который должен обработать ChatGPT.

from bs4 import BeautifulSoup

def extract_text_from_html(html):
    soup = BeautifulSoup(html, "html.parser")
    text = soup.get_text(separator=" ")
    text = text.replace('\n', '')
    text = text.replace('  ', ' ')
    return text.strip()

text = extract_text_from_html(response.text)

4. использование API OpenAI для извлечения данных из текста и преобразования их в JSON

Теперь, когда у нас есть хороший текст... давайте посмотрим на его длину. 8 719 символов... это немного слишком много... и проблема заключается в том, что максимальное ограничение на количество токенов для модели GPT-3.5 составляет 4096 токенов. Мы можем фактически проверить, сколько токенов мы передаем, используя tiktoken · PyPI, который является токенизатором, используемым моделями OpenAI.

import tiktoken
enc = tiktoken.encoding_for_model("gpt-4")
num_tokens= len(enc.encode(text))
print(num_tokens) #tokens 2547

Пока количество токенов у нас в порядке. Но если бы у нас было гораздо больше токенов, нам пришлось бы разбить текст на части, чтобы сделать его меньше, так как мы будем передавать текст внутри запроса. Я бы предложил передавать только около 4000 слов + текст запроса, чтобы быть на стороне безопасности. Плюс, если мы реализуем разделение на части, нам не нужно будет беспокоиться о проблемах, когда размер текста будет меняться. Что может случиться. Итак, будем в безопасности. Плюс, разделение на части - это весело, это всего лишь еще одна простая функция, которую мы можем написать.

def chunk_text(text, chunk_size):
    chunks = []
    current_chunk = ""
    for word in text.split():
        if len(current_chunk) + len(word) + 1 <= chunk_size:
            current_chunk += " " + word
        else:
            chunks.append(current_chunk.strip())
            current_chunk = word
    if current_chunk:
        chunks.append(current_chunk.strip())
    return chunks

chunk_size = 4000
chunks = chunk_text(text, chunk_size)

Теперь мы переходим к интересной части и тому, что, я думаю, вы ждали, мы наконец-то используем API ChatGPT. Важным моментом здесь является установка температуры, чем ниже температура, тем более буквальным будет текстовый вывод. Чем выше температура, тем больше все правила выходят за рамки, и тем больше модель будет креативной или галлюцинировать... Мы не хотим, чтобы ChatGPT был слишком креативным.

Теперь... есть одна проблема с моим подходом, я выполняю цикл по частям... поэтому мне нужно извлекать и вставлять json с каждой частью. Но ChatGPT делает что-то странное и иногда добавляет какой-то другой текст к результату JSON (словарь). Что... раздражает. Но, увы... регулярные выражения помогут нам извлечь JSON (словарь). Так что нам нужна еще одна функция.

import openai
import re
import json
from rich import print

def extract_json_from_string(text):
    text = text.replace("\n", "")
    matches = re.findall(r"\{.*?\}", text)
    if matches:
        result = matches[0]
        result = eval(result)
        result = json.dumps(result, indent=4)
        return result

openai.api_key = api_key # <-- замените это на свой API-ключ

result = {
    "title": "",
    "offer_type": "",
    "property_type": "",
    "price": "",
    "currency": "",
    "area": "",
    "measurement": "",
    "address": "",
    "district": "",
    "city": "",
    "country_code": "",
    "latitude": "",
    "longitude": "",
}

for chunk in chunks:
  prompt = f"""  complete this json:  {str(result)}    from following text:  {str(chunk)}    follow these rules:  - measurement can only be SQM or SQFT  - offer_type can only be sale or rent  - property_type can only be apartment, house, commercial or land  - if you have the address, try to get latitude and longitude, district, city and country_code  - price must be float  - area must be float  - latitude must be float  - longitude must float  - country_code must be ISO max 2 characters  - currency must be ISO, max 3 characters  - if nothing can be extracted, return the provided JSON as it is  - District can not have ' inside   """

  response = openai.Completion.create(
      engine="text-davinci-003",
      prompt=prompt,
      max_tokens=600,
      n=1,
      stop=None,
      temperature=0.3,
  )
  generated_text = response.choices[0].text.strip()
  result = extract_json_from_string(generated_text)

print(result)

Резюме

Традиционный парсинг по сравнению с извлечением данных с помощью искусственного интеллекта.

Теперь, когда мы это сделали, давайте подведем итоги. В сущности, это довольно круто, мы можем развивать то, что мы построили дальше и просто передавать ссылку, чтобы получить данные для любого объявления. Нам не нужно беспокоиться о том, что изменения дизайна на веб-сайте уничтожат наш парсер. Нам не нужно создавать парсер для каждого веб-сайта, мы просто получаем ссылки с веб-сайта и готово. Но не все так просто. Точность того, как ChatGPT принимает данные, может не всегда быть 100%, и скорость получения данных для каждого объявления также намного выше, чем если бы мы парсили, скажем, тысячи объявлений. Я вижу это как ленивый медленный способ получить информацию уже в правильном формате. Но нужно понимать, что это еще не идеально. Но тем не менее, что удивительно, ChatGPT смог получить координаты.

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