вівторок, 29 січня 2013 р.

Збір даних з допомогою Python.

При аналізі цін на нерухомість у Львові використовувались дані з сайту dom.ria.ua. Вони мають певні недоліки (детальніше про них тут ). Тому побудувати більш точну модель визначення ціни можна застосувавши інший підхід до збору даних. Додамо нові фактори для визначення, збільшимо сам набір даних, а також застосуємо кращі методи очищення.

В якості джерела використаємо http://www.real-estate.lviv.ua. Тут, на додачу від параметрів, які вже використовувались при попередньому аналізі можна отримати інформацію про додаткові чинники: матеріал стін (цегла, дерево і т. д.), тип будинку (новобудова, чешка, польський і т.д.), стан квартири, а також кількість балконів. Сторінка продажу виглядає так:


Таких сторінок наразі є 258. Інформація про кожну квартиру містить посилання на сторінку з детальнішою інформацією:

Алгоритм збору даних наступний:
  1. Знайти кількість сторінок з посиланнями;
  2. Для кожної сторінки завантажити список лінків на детальний опис квартири;
  3. Для кожного детального опису отримати значення полів: Адреса, Ціна, Кількість кімнат, Загальна площа, Житлова площа, Площа кухні, Кількість поверхів у будинку, Поверх, Кількість балконів, Тип стін, Тип будинку, Стан квартири, Кількість днів на сайті;
  4. Отримані дані про кожну квартиру записати в базу даних.
Отримувати необхідні нам параметри будемо з допомогою Python (2.7.3) та бібліотеки Beautiful Soup (HTML/XML парсер для Python, версія 4).  Легко визначити, в яких тегах сторінки міститься необхідна інформація  можна використовуючи розширення Firebug для Firefox (відповідний фрагмент коду підсвічується при виділенні елемента сторінки).
Встановлюємо Beautiful Soup з допомогою Ubuntu:
sudo apt-get install python-bs4 
Збір даних  будемо проводити в два етапи, для кожного з яких пишемо окремий скрипт.
  1. Отримати список посилань на детальний опис квартир та записати його у файл.
  2. Перейти по кожному з посилань, які містяться у файлі, отримати інформацію про кожен об'єкт та записати її в базу даних.
Етап1.
Імпортуємо потрібні модулі:
import urllib2
from bs4 import BeautifulSoup
urllib2 використовується для роботи з вебсторінками.
Передаємо Beautiful Soup сторінку http://www.real-estate.lviv.ua/sale-kvartira/Lviv:
url = 'http://www.real-estate.lviv.ua/sale-kvartira/Lviv'
page = urllib2.urlopen(url)
soup = BeautifulSoup(page)

Визначаємо найбільший номер сторінки. Він міститься в останньому посиланні, яке знаходиться в межах тега з атрибутом сlass = "search_result":


 
all_links = soup.find(class_ = "search_result")
# список всіх посилань, які містяться всредині тега з атрибутом class = "search_result"
links1 = all_links.find_all("a")
# останнє посилання цього списку
last_page = links1[-1].get("href")
# оримуємо сам номер, який міститься після символу "_"
n=last_page.split("_")
last_page_number = n[1]
Кожна сторінка з посиланнями на детальний вміст має формат:
"http://www.real-estate.lviv.ua/sale-kvartira/Lviv/p_" + номер_сторінки
Для кожної такої сторінки отримуємо список посилань, які містяться всередині тега
 з атрибутом class = "adr" та додаємо їх до списка s, об'єднавши їх з стрічкою "http://www.real-estate.lviv.ua/", оскільки посилання внутрішні:
s = [] 
for i in range(1, (int(last_page_number)+1)):
    cur_url = "http://www.real-estate.lviv.ua/sale-kvartira/Lviv/p_" + str(i)
    page = urllib2.urlopen(cur_url)
    soup = BeautifulSoup(page)
    
    linkslist = soup.find_all(class_ = "adr")
    for x in linkslist:
      urllist = x.find_all("a")

      for link in urllist:
        s.append("http://www.real-estate.lviv.ua" + link.get("href"))  
Зберігаємо результат у файлі:
f = open('realtylinks.txt', 'w')
for url in s:
  print >> f, url
f.close()


Переходимо до другого етапу:
Парсимо кожну сторінку, посилання на яку є в нашому файлі:
f = open('/home/nastya/Projects/Python/realtylinks.txt','r')
for line in f.readlines():
    url = line
    page = urllib2.urlopen(url)
    soup = BeautifulSoup(page)

Інформацію по квартиру будемо заносити в словник flats, створюємо для нього значення по замовчуванню:

flat = {'Адреса': 'NULL',
        'Матеріал стін': 'NULL',
        'Ціна': 'NULL',
        'Загальна площа': 'NULL',
        'Житлова площа': 'NULL',
        'Площа кухні': 'NULL',
        'Ціна $': 'NULL',
        'Тип будівлі': 'NULL',
        'Поверховість будівлі': 0,
        'Поверх': 0,
        'Днів на сайті': 200000,
        'Кількість балконів': 100,
        'Кімнат': 0,
        'Код квартири': 0,
        'Оновлено': 'NULL',
        'Стан': 'NULL'
         }

Заповнюємо словник значеннями, враховуючи, що адреса є елементом заголовку h2, а решта даних містяться в таблиці:

# отримуємо адресу
description = soup.find("h2").get_text()
desc = description.split(": ")
flat['Адреса'] =  desc[1]
# отримуємо решту параметрів:
features = soup.find_all("tr")
for i in features:
  f = i.get_text()
  f_list = f.split(":")
  x = f_list[0]
  if  x in flat.keys():
    flat[x] = f_list[1]

Вміст даного словника потрібно записати в базу даних. Записувати будемо в PostgreSQL.  Для запису скористаємося об'єктно-реляційне відображенням SQLObject, яке підтримує різні бази даних (PostgreSQL, MySQL, SQLite та інші), та дозволяє відображати об'єкти Python у SQL базу даних.
Встановлюємо  в Ubuntu:
apt-get install python-sqlobject 
Імпортуємо в Python необхідні модулі:
from sqlobject import *

# для коректної обробки unicode символів
from __future__ import unicode_literals 
Прописуємо параметри з'єднання з PostgreSQL:
connection_string = 'postgres://user:password@host/dbname' 
connection = connectionForURI(connection_string)
sqlhub.processConnection = connection 
Оголошуємо клас Flat:
class Flat(SQLObject):
    adress = StringCol()
    walls = StringCol()
    price = StringCol()
    area = StringCol()
    living_area = StringCol()
    kitchen_area = StringCol()
    dollar_price = StringCol()
    building_type = StringCol()
    floors_number = IntCol()
    floor = IntCol()
    days = IntCol()
    balcony = IntCol()
    rooms = IntCol()
    code = IntCol()
    updated = StringCol()
    condition = StringCol() 
Створюємо таблицю, куди будемо записувати:
Flat.createTable()    
При створенні нового об'єкту класу Flat на основі нашого словника, він автоматично запишеться в  базу даних:
f = Flat(adress = flat['Адреса'].encode('utf-8'),walls = flat['Матеріал стін'].encode('utf-8'), price = flat['Ціна'].encode('utf-8'), area = flat['Загальна площа'].encode('utf-8'), living_area = flat['Житлова площа'].encode('utf-8'), kitchen_area = flat['Площа кухні'].encode('utf-8'), dollar_price = flat['Ціна $'].encode('utf-8'), building_type = flat['Тип будівлі'].encode('utf-8'), floors_number = int(flat['Поверховість будівлі']), floor = int(flat['Поверх']), days = int(flat['Днів на сайті']), balcony = int(flat['Кількість балконів']), rooms = int(flat['Кімнат']), code = int(flat['Код квартири']), updated = flat['Оновлено'].encode('utf-8'), condition = flat['Стан'].encode('utf-8')) 
Чекаємо, поки обробляться всі записи.
В результаті отримуємо 5181 запис з детальною інформацією про квартири. Це значно більше, ніж попередніх 776. Звичайно, ці дані потрібно ще додатково очистити.
Як це зробити з допомогою Google Refine у наступній статті.
Описані вище скрипти можна знайти на github.

Немає коментарів:

Дописати коментар