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

В этом уроке по парсингу мы собираемся парсить крупнейший портал недвижимости в Португалии Idealista. Мы собираемся использовать Python для этого урока.

Собираем все ингредиенты в одном месте

Я предполагаю, что вы уже установили Python на свой компьютер. Я буду использовать python 3.x. После установки нам потребуются еще две библиотеки для извлечения данных.

  • Selenium — будет использоваться для рендеринга сайта Idealista.
  • BeautifulSoup — будет использоваться для создания дерева HTML для разбора данных.
  • Chromium — это веб-драйвер, который Selenium использует для управления Chrome. Скачать его можно здесь.

Настраивать

Во-первых, нам нужно создать папку, в которой мы будем хранить наш скрипт.

mkdir coding

Внутри этой папки вы можете создать файл с любым именем. В этом случае я собираюсь использовать Idealista.py. Наконец, мы собираемся установить вышеупомянутые библиотеки, используя pip.

pip install selenium
pip install beautifulsoup4

Selenium — это инструмент автоматизации браузера, он будет использоваться для загрузки нашего целевого URL в настоящий браузер Chrome. BeautifulSoup, также известный как BS4, будет использоваться для чистого извлечения данных из необработанного HTML, возвращаемого селеном.

Мы также можем использовать здесь библиотеку requests, но идеалисты любят отправлять капчи, а обычный HTTP-запрос GET может заблокировать ваш запрос и привести к серьезной поломке вашего конвейера данных. Чтобы придать Idealista настоящую атмосферу браузера, мы продвигаемся вперед с селеном.

Что мы собираемся скрести?

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

Какие данные мы собираемся извлечь?

Лучше решить это заранее, чем решить это в середине блога.

Я решил очистить следующие точки данных:

  • Название собственности
  • Цена недвижимости
  • Размер области
  • Описание недвижимости
  • Выделенная веб-ссылка собственности.

Сначала мы очистим всю страницу с помощью селена и сохраним исходный код страницы в некоторой переменной. Затем мы создадим дерево HTML, используя BS4. Наконец, мы будем использовать методы find() и find_all() для извлечения соответствующих данных.

Давайте сначала очистим исходный код страницы

Мы будем использовать селен для этой части. Мы будем использовать метод драйвера page_source, который поможет нам получить источник текущей страницы или целевую страницу.

from bs4 import BeautifulSoup
from selenium import webdriver
import time
import schedule

PATH = 'C:\Program Files (x86)\chromedriver.exe'



l=list()
o={}

target_url = "https://www.idealista.com/venta-viviendas/torrelavega/inmobiliaria-barreda/"


driver=webdriver.Chrome(PATH)

driver.get(target_url)


time.sleep(5)
resp = driver.page_source
driver.close()

Сначала я импортировал все необходимые библиотеки, а затем определил расположение нашего браузера Chromium. Не забудьте сохранить версию хрома такой же, как у вашего браузера Chrome, иначе он не будет работать.

После этого я создал экземпляр Chrome с путем загрузки драйвера. С помощью этой команды мы можем выполнять несколько тестов в браузере, пока вы не закроете соединение с помощью метода .close().

Затем я использовал метод .get() для загрузки веб-сайта. Он не только загружает веб-сайт, но и ожидает завершения рендеринга веб-сайта.

Наконец, мы извлекли данные с помощью метода page_source и закрыли сеанс с помощью метода .close(). .close() отключит ссылку от браузера. Теперь у нас есть полные данные страницы. Теперь мы можем использовать BS4 для создания супа, через который мы можем извлекать нужные данные, используя методы .find() и .find_all() BS4.

Скрапинг заголовка

Давайте сначала осмотрим и найдем элемент DOM.

Название свойства хранится под тегом с классом item-link. Этот тег вложен в тег div с классом item-info-container.

soup = BeautifulSoup(resp, 'html.parser')

allProperties = soup.find_all("div",{"class":"item-info-container"})

После закрытия сеанса веб-драйвера мы создали дерево страниц, через которое будем извлекать текст. Для простоты мы сохранили все свойства в виде списка внутри переменной allProperties. Теперь нам станет намного проще извлекать заголовки и другие данные.

Поскольку внутри нашей переменной allProperties есть несколько свойств, нам нужно запустить цикл for, чтобы получить доступ к каждому свойству и извлечь из него всю необходимую информацию.

for i in range(0,len(allProperties)):
    o["title"]=allProperties[i].find("a",{"class":"item-link"}).text.strip("\n")

Объект o будет содержать все заголовки всех свойств после окончания цикла for. Давайте очистим оставшиеся точки данных.

Соскоб Цена недвижимости

Давайте проверим и найдем расположение этого элемента внутри DOM.

Цена хранится внутри тега span класса item-price. Мы будем использовать ту же технику, что и для очистки заголовка. Внутри цикла for мы будем использовать приведенный ниже код.

o["price"]=allProperties[i].find("span",{"class":"item-price"}).text.strip("\n")

Это извлечет все цены одну за другой.

Размер и описание области очистки

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

Размер области хранится внутри тега div с классом "item-detail-char".

o["area-size"]=allProperties[i].find("div",{"class":"item-detail-char"}).text.strip("\n")

Описание свойства можно найти внутри тега div с классом «item-description».

URL-адрес выделенного ресурса

С помощью той же техники вы также можете парсить выделенные ссылки. Найдем его местонахождение.

Ссылка хранится внутри тега с атрибутом href. Это не полный URL, поэтому мы добавим предлог. Здесь мы будем использовать метод .get() из BS4, чтобы получить значение атрибута.

o["property-link"]="https://www.idealista.com"+allProperties[i].find("a",{"class":"item-link"}).get('href')

Здесь мы добавили https://www.idealista.com в качестве предлога, потому что мы не найдем полный URL внутри тега href.

Нам удалось собрать все интересующие нас данные.

Полный код

Вы можете внести еще несколько изменений, чтобы извлечь немного больше информации, такой как количество свойств, карта и т. д. Но текущий код будет выглядеть так.

from bs4 import BeautifulSoup
from selenium import webdriver
import time


PATH = 'C:\Program Files (x86)\chromedriver.exe'



l=list()
o={}

target_url = "https://www.idealista.com/venta-viviendas/torrelavega/inmobiliaria-barreda/"


driver=webdriver.Chrome(PATH)

driver.get(target_url)


time.sleep(7)
resp = driver.page_source
driver.close()

soup = BeautifulSoup(resp, 'html.parser')

allProperties = soup.find_all("div",{"class":"item-info-container"})

for i in range(0,len(allProperties)):
    o["title"]=allProperties[i].find("a",{"class":"item-link"}).text.strip("\n")
    o["price"]=allProperties[i].find("span",{"class":"item-price"}).text.strip("\n")
    o["area-size"]=allProperties[i].find("div",{"class":"item-detail-char"}).text.strip("\n")
    o["description"]=allProperties[i].find("div",{"class":"item-description"}).text.strip("\n")
    o["property-link"]="https://www.idealista.com"+allProperties[i].find("a",{"class":"item-link"}).get('href')
    l.append(o)
    o={}

print(l)

После того, как вы напечатаете ответ, он будет выглядеть так.

Давайте перейдем ко второму разделу этого руководства, где мы также создадим поддержку нумерации страниц. Благодаря этому мы сможем просканировать все страницы, доступные для определенного места.

Очистка всех страниц

Вы, должно быть, заметили одну вещь: каждая страница имеет 30 свойств. С помощью этой информации вы можете получить общее количество страниц в каждом месте. Конечно, сначала вам нужно будет очистить общее количество свойств, которые есть в любом месте.

Текущая целевая страница имеет 146 свойств. Мы должны очистить это число, а затем разделить его на 30. Это число будет общим количеством страниц. Итак, давайте сначала очистим этот номер.

Как видите, это число находится внутри строки. Мы должны очистить эту строку, а затем использовать функцию python .split(), чтобы разбить строку на список. Тогда первый элемент списка будет нашим желаемым элементом, потому что 146 — это первый символ внутри предложения.

Эта строка хранится внутри тега div с классом «заголовок списка». Давайте извлечем его.

totalProperties = int(soup.find("div",{"class":"listing-title"}).text.split(" ")[0])
totalPages = round(totalProperties/30)

с помощью метода int() я преобразовал строку в целое число. Затем мы разделили его на 30, чтобы получить общее количество страниц. Теперь давайте проверим, как меняется шаблон URL при изменении номера страницы.

При нажатии на страницу номер два URL-адрес будет выглядеть так: https://www.idealista.com/venta-viviendas/torrelavega/inmobiliaria-barreda/pagina-2.htm.

Итак, он добавляет строку «pagina-2.htm», когда вы нажимаете на вторую страницу. Точно так же, когда вы нажимаете на третью страницу, вы получаете «pagina-3.htm». Нам просто нужно изменить целевой URL, просто добавив эту строку в соответствии с номером страницы, на которой мы находимся. Для этого мы будем использовать цикл for.

from bs4 import BeautifulSoup
from selenium import webdriver
import time


PATH = 'C:\Program Files (x86)\chromedriver.exe'



l=list()
o={}

target_url = "https://www.idealista.com/venta-viviendas/torrelavega/inmobiliaria-barreda/"


driver=webdriver.Chrome(PATH)

driver.get(target_url)


time.sleep(7)
resp = driver.page_source
driver.close()

soup = BeautifulSoup(resp, 'html.parser')
totalProperties = int(soup.find("div",{"class":"listing-title"}).text.split(" ")[0])
totalPages = round(totalProperties/30)
allProperties = soup.find_all("div",{"class":"item-info-container"})

for i in range(0,len(allProperties)):
    o["title"]=allProperties[i].find("a",{"class":"item-link"}).text.strip("\n")
    o["price"]=allProperties[i].find("span",{"class":"item-price"}).text.strip("\n")
    o["area-size"]=allProperties[i].find("div",{"class":"item-detail-char"}).text.strip("\n")
    o["description"]=allProperties[i].find("div",{"class":"item-description"}).text.strip("\n")
    o["property-link"]="https://www.idealista.com"+allProperties[i].find("a",{"class":"item-link"}).get('href')
    l.append(o)
    o={}

for x in range(2,totalPages+1):
    target_url = "https://www.idealista.com/venta-viviendas/torrelavega/inmobiliaria-barreda/pagina-{}.htm".format(x)
    driver=webdriver.Chrome(PATH)

    driver.get(target_url)


    time.sleep(7)
    resp = driver.page_source
    driver.close()

    soup = BeautifulSoup(resp, 'html.parser')
    allProperties = soup.find_all("div",{"class":"item-info-container"})
    for i in range(0,len(allProperties)):
        o["title"]=allProperties[i].find("a",{"class":"item-link"}).text.strip("\n")
        o["price"]=allProperties[i].find("span",{"class":"item-price"}).text.strip("\n")
        o["area-size"]=allProperties[i].find("div",{"class":"item-detail-char"}).text.strip("\n")
        o["description"]=allProperties[i].find("div",{"class":"item-description"}).text.strip("\n")
        o["property-link"]="https://www.idealista.com"+allProperties[i].find("a",{"class":"item-link"}).get('href')
        l.append(o)
        o={}

print(l)

После извлечения данных с первой страницы мы запускаем цикл for, чтобы получить новый целевой URL-адрес и извлечь из него данные таким же образом. Как только вы распечатаете список l, вы получите полные данные.

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

Позвольте мне быть с вами предельно честным: Idealista.com — это хорошо защищенный сайт, и его нельзя парсить в больших масштабах. Фактически, после 10 или 20 запросов он сможет обнаружить неправомерное использование и заблокирует доступ к сайту. После этого вы будете продолжать получать 403 ошибки при каждом веб-запросе, который вы делаете. Как этого избежать? Что ж, для этого я бы посоветовал вам использовать Scrapingdog, который представляет собой Web Scraping API. Scrapingdog использует свой большой пул прокси-серверов для преодоления любых проблем, с которыми вы можете столкнуться при извлечении данных в масштабе. Давайте посмотрим, как мы можем использовать Scrapingdog для масштабного парсинга Idealista.com.

Использование Scrapingdog для парсинга Idealista

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

Вы можете найти свой ключ API в верхней части панели инструментов. Вам просто нужно внести несколько изменений в приведенный выше код, и Scrapingdog сможет справиться с остальными задачами. Вам даже не нужен Selenium или любой другой веб-драйвер, чтобы очистить его. Вам просто нужно использовать библиотеку requests, чтобы сделать запрос GET к API Scrapingdog.

from bs4 import BeautifulSoup
import requests




l=list()
o={}

target_url = "https://www.idealista.com/venta-viviendas/torrelavega/inmobiliaria-barreda/"


resp = requests.get("https://api.scrapingdog.com/scrape?api_key=Your-API-KEY&url={}&dynamic=false".format(target_url))
soup = BeautifulSoup(resp.text, 'html.parser')
totalProperties = int(soup.find("div",{"class":"listing-title"}).text.split(" ")[0])
totalPages = round(totalProperties/30)
allProperties = soup.find_all("div",{"class":"item-info-container"})

for i in range(0,len(allProperties)):
    o["title"]=allProperties[i].find("a",{"class":"item-link"}).text.strip("\n")
    o["price"]=allProperties[i].find("span",{"class":"item-price"}).text.strip("\n")
    o["area-size"]=allProperties[i].find("div",{"class":"item-detail-char"}).text.strip("\n")
    o["description"]=allProperties[i].find("div",{"class":"item-description"}).text.strip("\n")
    o["property-link"]="https://www.idealista.com"+allProperties[i].find("a",{"class":"item-link"}).get('href')
    l.append(o)
    o={}
print(totalPages)
for x in range(2,totalPages+1):
    target_url = "https://www.idealista.com/venta-viviendas/torrelavega/inmobiliaria-barreda/pagina-{}.htm".format(x)

    resp = requests.get("https://api.scrapingdog.com/scrape?api_key=Your-API-KEY&url={}&dynamic=false".format(target_url))
    soup = BeautifulSoup(resp.text, 'html.parser')
    allProperties = soup.find_all("div",{"class":"item-info-container"})
    for i in range(0,len(allProperties)):
        o["title"]=allProperties[i].find("a",{"class":"item-link"}).text.strip("\n")
        o["price"]=allProperties[i].find("span",{"class":"item-price"}).text.strip("\n")
        o["area-size"]=allProperties[i].find("div",{"class":"item-detail-char"}).text.strip("\n")
        o["description"]=allProperties[i].find("div",{"class":"item-description"}).text.strip("\n")
        o["property-link"]="https://www.idealista.com"+allProperties[i].find("a",{"class":"item-link"}).get('href')
        l.append(o)
        o={}

print(l)

Мы удалили Selenium, потому что он нам больше не нужен. Не забудьте заменить Your-API-KEY собственным ключом API. Вы можете найти свой ключ на приборной панели. Этот код предоставит вам неразрывный поток данных. Помимо этого остальная часть кода останется прежней.

Точно так же, как этот Scrapingdog можно использовать для очистки любого веб-сайта, не будучи заблокированным.

Заключение

Idealista — это богатый данными сайт о недвижимости, который не нуждается в представлении. После Zillow Idealista является самым известным сайтом по продаже недвижимости. Как я уже сказал, парсинг может помочь вам или вашей компании принять некоторые действительно важные решения.

Это самый простой способ очистить Idealista. Мы не использовали надлежащие методы обработки ошибок, но в реальных примерах вы всегда должны использовать операторы try/except, чтобы избежать каких-либо последствий или сбоев.

Надеюсь, вам понравился этот небольшой урок, и если да, то не забудьте поделиться им с друзьями и в социальных сетях.

Дополнительные ресурсы