CoderCastrov logo
CoderCastrov
Парсер

Как найти идеальную квартиру с помощью написанного на Python веб-парсера

Как найти идеальную квартиру с помощью написанного на Python веб-парсера
просмотров
8 мин чтение
#Парсер
Examples of apartments in Amsterdam where I will never be able to live.

Я живу в Амстердаме уже почти 10 лет. Я считаю, что Амстердам - замечательное место, и я рад, что могу жить здесь. Однако, то, что может быть менее замечательным в Амстердаме, - это текущее состояние рынка жилья для новичков (как для меня и моей подруги).

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

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


Разработанное мной решение, осуществляемое с помощью так называемого "веб-парсера", использует приложение на Python, развернутое в качестве веб-сервиса. Оно простое и элегантное, выполняя следующие задачи: ежечасное сканирование нескольких веб-сайтов брокеров; поиск новых квартир; и отправка уведомлений по электронной почте с найденными квартирами.

Моя гипотеза: Квартиры, предлагаемые брокерами, активными на платформе funda, сначала размещаются на их собственном веб-сайте, а затем некоторое время позже добавляются на платформу funda.

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

Я использовал три важных пакета Python для создания, отправки сообщений и развертывания парсера.

  • Scrapy (известный пакет для парсинга на Python)
  • Yagmail (ленивое, но мощное решение для использования учетной записи Gmail в качестве "почтового сервера")
  • Scrapyd (для развертывания парсера на внешнем сервере, к сожалению, не является частью этой статьи)

В этой статье будет несколько "начинающих" шагов по парсингу Всемирной паутины:

В этой статье не будет развертывания парсеров с использованием Scrapyd (если будет запрос, я могу подумать о создании статьи для развертывания и обслуживания).

Создание проекта Scrapy

Для начала давайте создадим новый проект с помощью встроенного интерфейса командной строки Scrapy CLI в вашем терминале. Вы можете использовать команду 'startproject', и вам не придется делать многое, чтобы начать работу. Я назвал свой проект 'housing', что лучше, чем 'пожалуйстаисправьтеситуациюсарендой', и 'housing' совпадает с английским переводом моей фамилии. Эта команда создает новый проект Scrapy в вашем текущем рабочем каталоге, включая все предварительно созданные файлы и структуру каталогов, вы не могли быть ленивее.

scrapy startproject housing

Определение объекта "дом" (Item)

Далее идет определение объектов для проекта. Создание объекта (Item) сравнимо с определением частей объекта, которые я хочу спарсить. Поскольку я хочу спарсить дома с веб-сайтов брокеров, мне понадобится объект "дом". К счастью, Scrapy уже создал файл под названием items.py с минимальным черновым вариантом объекта Scrapy под названием "HousingItem". Меня интересует несколько характеристик новой квартиры. Я хочу спарсить адрес, название брокера, цену квартиры, площадь, URL-адрес (чтобы посмотреть самому, когда получу уведомление по электронной почте) и телефонный номер брокера (чтобы быть первым звонящим, как только получу уведомление). Создайте соответствующие поля для объекта, чтобы мы могли наконец перейти к увлекательной части парсинга.

house

Поиск и анализ нужной веб-страницы

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

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

<html>
  <body>
    <div class="apartment">
      <h2>Overpriced Apartment 1</h2>
      <p>Price: $1000000</p>
    </div>
    <div class="apartment">
      <h2>Overpriced Apartment 2</h2>
      <p>Price: $1500000</p>
    </div>
    <div class="apartment">
      <h2>Reasonably Priced Apartment</h2>
      <p>Price: $500000</p>
    </div>
  </body>
</html>

При парсинге веба с использованием экземпляра парсера, парсер сохранит HTML-код целевой веб-страницы в объекте "response" (вместе с другой метаинформацией о разобранной веб-странице). Этот объект используется для разбора необходимой информации.

Кодирование логики парсера

В этом примере есть два дома, которые сдаются в аренду. При более детальном рассмотрении оба дома имеют одинаковые элементы DOM (объектная модель документа), за исключением содержимого внутри элементов. Эта структура поможет нам парсить страницу и извлекать нужные части двух домов с помощью так называемых "селекторов". В этом примере я использовал синтаксис CSS для запроса ответа (я советую вам ознакомиться с XPath). Пришло время закодировать наш парсер для этого конкретного сайта брокера. Scrapy использует имя "spider" для своих объектов парсера, и я буду использовать это обозначение сейчас. Конечно, Scrapy имеет встроенную функцию для создания новых парсеров с помощью командной строки.

scrapy genspider thehouseflippers thehouseflippers.nl

Я назову парсеры именем брокера: "thehouseflippers". Второй аргумент, домен, установлен на "thehouseflippers.nl". В конечном итоге он должен выглядеть как код ниже, но ради инструкции я дам окончательный код для парсера. Я объясню содержимое в следующих нескольких абзацах.

Чтобы избежать ошибок, необходимо импортировать класс Item из файла items.py с именем HousingItem (мы только что создали этот класс Item). Мы инициируем парсер как подкласс класса scrapy.Spider (что сильно упрощает жизнь). Внутри подкласса я определил имя парсера и установил желаемый URL в функции "start_request". В этом примере мы будем парсить одну страницу, но не стесняйтесь добавлять больше URL в будущем. Настоящая магия происходит внутри функции "parse".

Внутри функции "parse" парсер будет искать каждый элемент "div", назначенный классом "house" в объекте ответа (это запрошенный HTML-код URL, который мы поместили в функцию "start_requests"). Внутри каждого элемента "div", назначенного классом "house", функция "parse" ищет дополнительную информацию для каждого экземпляра, используя селекторы CSS. Поскольку я хочу парсить интересующую меня информацию, такую как адрес, цена и т. д., мне нужно указать местоположение этой конкретной информации внутри элемента "div" выбранного дома.

Поскольку я не хочу получать спам-сообщения каждый раз, когда парсер запускается с сообщениями о ранее спарсенных квартирах, я создал очень простое (и, вероятно, неловкое) решение для сохранения адреса первого найденного дома в последней сессии парсинга. Скрипт открывает файл с именем "thehouseflippers.txt" в директории "last" и устанавливает логическую переменную в значение True. В первой итерации всех найденных домов на странице он проверяет содержимое файла и сравнивает его с новым найденным адресом дома. Если адрес совпадает с содержимым файла, на сайте не размещена новая квартира. Если содержимое файла не совпадает с адресом первого найденного дома во время парсинга, значит, найден новый дом, и он заменит содержимое файла. Логическая переменная будет установлена в False, чтобы предотвратить перезапись файла следующим адресом домов, которые будут парситься.

Завершается функция возвратом данных в форме объекта HousingItem для каждого спарсенного дома с использованием функции yield. В последней части мы хотим уведомлять себя о том, когда была спарсена новая квартира или дом с URL. В этом месте вступают в игру "Item Pipelines".

Отправка электронной почты с использованием Item Pipeline и Yagmail

Item Pipelines полезны в сочетании с использованием класса Item. Для каждого спарсенного дома скрапер генерирует Item с помощью класса HousingItem. Этот Item можно автоматически обработать с помощью Item Pipeline. Чтобы уведомить себя о каждом новом найденном доме, я могу использовать этап предварительной обработки для очистки полей спарсенного Item и отправки себе (и своей подруге и кому я выберу) электронного письма, содержащего HTML-код, с использованием удивительного пакета под названием Yagmail.

Этот конкретный Item Pipeline с именем "HousingPipeline" обрабатывает только Item (есть и другие методы, но для этого проекта они не имеют практического применения). Первый шаг обработки Item внутри Pipeline выполняется для поля цены Item "house". Удаляются все символы, кроме цифр, и каждая цифра после четвертой обрабатывается как десятичное место. Те же шаги обработки применяются для площади: удаляются все символы, не являющиеся цифрами (например, м²). Можно добавить дополнительные шаги обработки, например, отправку электронной почты, когда цена ниже желаемой.

Забавная часть начинается с создания содержимого уведомительного письма, заполненного обработанными данными из Item. Содержимое заполняется с использованием Python, я использовал свои навыки HTML, чтобы создать красивый макет без особой причины. Он использует все поля экземпляра HousingItem. Инициализируйте SMTP с использованием вашей учетной записи Gmail (пожалуйста, создайте ключ, иначе письмо не будет отправлено) и используйте метод send для отправки письма. Не забудьте добавить HousingPipeline в ваш settings.py.

ITEM_PIPELINES = {
   'housing.pipelines.HousingPipeline': 300,
}

Парсинг страницы

Протестируйте только что созданный паук, используя утилиту командной строки Scrapy, и проверьте, все ли работает, возможно, потребуется некоторая отладка (конечно, моя лошадка). При выполнении команды 'scrapy crawl', за которой следует имя паука (вы видите методологию), паук будет обходить веб-сайт и, надеюсь, выводить информацию о найденных домах. Когда письма приходят с содержимым, точно таким, каким вы хотите, вы готовы к следующему этапу, называемому развертыванием этого сексуального парня (если, конечно, вы не хотите запускать команду вручную время от времени, не могу представить, что вы это делаете).

scrapy crawl thehouseflippers

Развертывание

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