CoderCastrov logo
CoderCastrov
Парсер

Condo.ca Веб-парсинг

Condo.ca Веб-парсинг
просмотров
4 мин чтение
#Парсер

Это мой первый проект по веб-парсингу на Python. Я также провел некоторый очень простой анализ данных с использованием Pandas.

Веб-сайтом, который я использую, является Condos.ca, и меня интересуют только арендные предложения для всех квартир в городе Торонто (На их веб-сайте размещено около 350+ предложений в городе Торонто, поэтому я подумал, что 350+ строк данных должны дать мне хороший старт с первым проектом по веб-парсингу).

Некоторые из основных пакетов, которые я использовал:

from bs4 import BeautifulSoup as bs 
import requests as rq 
from time import sleep 
import pandas as pd
from progressbar import ProgressBar
import numpy as np
import matplotlib.pylab as plt
from gmplot import gmplot
import googlemaps
from datetime import datetime
from matplotlib.backends.backend_pdf import PdfPages

BeautifulSoup и Requests - это пакеты, которые я использовал для общего веб-парсинга, а Progressbar - просто для отслеживания прогресса, чтобы у меня были некоторые визуализации прогресса. Я также импортировал пакеты gmplot и googlemaps, так как я хотел увидеть местоположение перечисленных квартир в Торонто, так как я очень люблю Google Maps... и, наконец, пакет pdfpages используется для сохранения всех графиков в файл PDF.

Вот веб-сайт, с которого я собираю все арендные предложения.

https://condos.ca/search?for=rent&page=

Обратите внимание, что номер страницы нужно вводить вручную. И на сегодняшний день (21.02.2019) есть 9 страниц или 386 единиц предложений.

Затем я буду собирать все интересующие меня характеристики для аренды квартир.

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

Вы можете увидеть всю запрошенную информацию (включая ссылку для открытия страницы квартиры) с помощью find-all и тега a и атрибутов {‘class':'no-decro','target':'_blank'} Я могу получить ссылку, название объявления, цену, спальни и ванные комнаты, кв. футы и доступность в [condo_data]list

for s1 in ls.find_all('a',{'class':'no-decro','target':'_blank'}):
    row=[]
    link ='https://condos.ca/'+s1.get('href')
    title=s1.get('title')
    price=s1.find('span',{'class':'tag-price'}).get_text()
    bed_bath=list(filter(None,s1.find('div',{'class':'listing-bed-bath-div'}).get_text().strip(' ').splitlines()))
    sq_ft=s1.find('div',{'class':'listing-size-div'}).get_text().replace('\n','').replace(' ','').replace('\t','')
    available_date=s1.find('li',{'class':'pull-right'}).get_text().replace('\n','').replace(' ','').replace('\t','').replace('DateAvailable', '')

После сбора всей информации я преобразую список в condosдатафрейм

condos=pd.DataFrame(condo_data, columns=['title', 'price','sq_ft','bed','shower','parking_available','available_date','link'], index=range(1,len(condo_data)+1))

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

Так что для парсинга всех местоположений квартир в списке, используя собранные мной ссылки из первого парсинга, теперь мы получаем адрес, включая под-область, область, город и почтовый индекс. Затем я могу добавить всю эту информацию о местоположении в датафрейм condos, используя функцию pd.assign(series)

for i in pbar_1(range(0,condos.shape[0])):
    sleep (1)
    u = condos.iloc[i,7]
    s = get_soup(u)
    for s2 in s.find_all('h2',{'class':'slide-address'}):
        addr=s2.get_text().replace('\t','').replace('\n','')
        a=s2.find_all('a')
        sub_addr=a[0].get_text().replace('\t','').replace('\n','')
        area_addr=a[1].get_text().replace('\t','').replace('\n','')
        city.append(a[2].get_text().replace('\t','')\
.replace('\n',''))condos = condos.assign\
(address=pd.Series(data=address,index=range(1,len(condo_data)+1)))

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

condos['area'].value_counts().plot(kind='pie',title='Количество предложений квартир по районам',fontsize=5)condos.groupby('area').agg({'price':['max','min','mean']}).\
plot(kind='barh',title='Максимальная/минимальная/средняя цена аренды по районам',grid=True,fontsize=5,mark_right=False) \
plt.legend(('Макс.','Мин.','Сред.'),loc='best')

Следующая часть этой статьи посвящена техническим деталям. В этом проекте парсинга я создал только одну функцию, которая получает объект soup из переданного URL и является повторно используемой.

def get_soup(url):
    r = rq.get(url)
    r.encoding='latin1'
    soup = bs(r.text,'lxml')
    return soup

Во время процесса веб-парсинга очистка данных может быть довольно раздражающей, когда вам нужно удалить '\n\t' из данных, и встроенная функция Python strip() работает только с первым вхождением, поэтому я использовал replaced({stripped},{replaced}), чтобы удалить все ненужные веб-скрипты. Например, вот так -

available_date=s1.find('li',{'class':'pull-right'}).get_text().replace('\n','').replace(' ','').replace('\t','').replace('DateAvailable', '')

Если вы хотите добавить значения в свой список Python, вы можете использовать list.append({value}), однако эта функция может принимать только одно значение, если значение еще не является списком. Поэтому я использовал list.extend(({value1},{value2}...)), см. пример ниже, когда я хочу объединить детали квартиры в каждую строку квартиры -

row.extend((title,price,sq_ft,bed,shower,parking_available,available_date,link))

Так как я хотел сохранить все графики matplot в файл PDF, я импортировал библиотеку PDF в Python from matplotlib.backend.backend_pdf import PdfPages, и это позволит сохранить несколько объектов plot в один файл PDF с помощью pdf.savefig() и plt.close(), чтобы Python знал, что эта часть построения графиков завершена.

condos['bed'].value_counts().plot(title='Типы спален',kind='bar')
pdf.savefig()
plt.close()

condos['shower'].value_counts().plot(title='Типы ванных комнат',kind='bar') 
pdf.savefig()
plt.close()

condos['sq_ft'].value_counts().plot(title='Размер квартиры',kind='bar',fontsize=5)
pdf.savefig()
plt.close()

Последний шаг - нарисовать тепловую карту, разбросанные точки на Google Maps с использованием API Google Maps. Обратите внимание, что map_plot Google может пометить только местоположение, указав широту и долготу в качестве параметров, но используя обратный gmap.geocode с адресом в качестве параметра, мы все равно можем пометить на Google Maps -

lat_long=[gmaps.geocode(geo_addr)[0]['geometry']['location'] for geo_addr in geo_address]
lats, lons = zip(*([(i['lat'],i['lng']) for i in lat_long]))

# Размещение карты с центром в центре Торонто
map_plot = gmplot.GoogleMapPlotter(43.6543, -79.3860,10)
# Разброс точек
map_plot.scatter(lats, lons, '#3B0B39', size=20, marker=False)
# Тепловая карта
map_plot.heatmap(lats, lons)
# Нарисовать карту
map_plot.draw(f'{file_name}.html')

Итак... с pdf.savefig(), map_plot(draw) и df.to_csv(), которые я не упомянул после того, как я очистил и создал датафрейм condos, я могу сохранить мои исходные данные, файлы анализа квартир, а также изображение карты для предложений квартир в моем каталоге. Так что мой следующий шаг в этой работе - автоматизировать работу сценария и сохранить его в облаке...

Список дел: 1) протестировать подключение airflow, docker и mysql на моем локальном сервере 2) загрузить весь практический материал на сервер AWS и в S3-хранилище, чтобы сценарий мог запускаться и предоставлять отчеты об анализе ежедневно.