用Python和beautifulsou进行房地产市场的报废

2024-05-29 03:04:14 发布

您现在位置:Python中文网/ 问答频道 /正文

我需要一些概念如何解析房地产市场使用Python。我搜索了一些关于解析网站的信息,我甚至用VBA做了这个,但是我想用python做。你知道吗

这是一个网站,将被解析(这是一个报价只有现在,但它将在全系列的房地产提供工作,从多个网站)kontrakt.szczecin.pl公司): http://www.kontrakt.szczecin.pl/mieszkanie-sprzedaz-100m2-335000pln-grudziadzka-pomorzany-szczecin-zachodniopomorskie,351149

首先,程序将使用3条信息:

1/信息所在的表格(主要参数): 房号:351149,Liczba pokoi 3,Cena 335 000 PLN,Cena za m2 3 350 PLN(报价数量,房间号,价格,每平方米价格等)。然而,信息的数量取决于房地产报价:有时是14,有时是12,有时是16等

2/在段落中描述属性(它是程序的另一部分,现在可以跳过):有时在表(1/)中有车库或阳台的信息。但在第段有一句话,车库是额外的价格(这意味着我的财产没有车库)或阳台是法国式的(这是没有阳台我)。 我管理的程序应该在段落中找到正确的单词(比如garage),并从段落中复制文本,在左右两侧添加额外的文本(例如:两边都有20个字母,但是如果单词放在第一位怎么办?)你知道吗

3/附加参数- 不是每个报价都有,但像这个(http://www.kontrakt.szczecin.pl/mieszkanie-sprzedaz-6664m2-339600pln-potulicka-nowe-miasto-szczecin-zachodniopomorskie,351165)有关于酒店阳台数量的信息。有时也有地下室的信息。它应该是类似于1/问题的代码。你知道吗

所以我尝试了类似的方法,使用了一些互联网资源(它仍然是不完整的):

from urllib.request import urlopen as uReq
from bs4 import BeautifulSoup as soup

my_url = "http://www.kontrakt.szczecin.pl/mieszkanie-sprzedaz-6664m2-339600pln-potulicka-nowe-miasto-szczecin-zachodniopomorskie,351165"

#PL: otwiera połączenie z wybraną stroną, pobieranie zawartości strony (urllib)
#EN: Opens a connection and grabs url

uClient = uReq(my_url)
page_html = uClient.read()
uClient.close()

#html parsing (BeautifulSoup)
page_soup = soup(page_html, "html.parser") #html.parser -> zapisujemy do html, nie np. do xml

#PL: zbiera tabelkę z numerami ofert, kuchnią i innymi danymi o nieruchomości z tabelki
#EN: grabs the data about real estate like kitchen, offer no, etc.
containers = page_soup.findAll("section",{"class":"clearfix"},{"id":"quick-summary"})

# print(len(containers)) - len(containers) sprawdza ile takich obiektów istnieje na stronie
#PL: Co prawda na stronie jest tylko jedna taka tabelka, ale dla dobra nauki zrobię tak jak gdyby tabelek było wiele.
#EN: There is only one table, but for the sake of knowledge I do the container variable
container = containers[0]
find_dt = container.findAll("dt")
find_dd = container.findAll("dd")
print(find_dt[0].text + " " + find_dd[0])

它是有效的,但仍然是不完整的。我现在不继续了,因为有一个重大的缺陷。正如您看到的上一次打印,它需要索引,但不是每个属性都有相同的顺序(因为正如我提到的,有时有10条信息,有时更多,有时更少)。这将是一个巨大的混乱。你知道吗

我的VBA程序是这样工作的:

  1. 将表格复制到Excel(表1)
  2. 在表2中有程序正在寻找的参数(如价格)
  3. 快捷方式中的机制:从第2页(价格)复制参数,转到第1页(其中是解析信息),查找价格字符串(从第2页粘贴信息:“价格”),转到下面的行,复制价格值,转到第2页,查找价格,转到下面,粘贴价格值。等等。你知道吗

寻求帮助与概念和编码也。你知道吗

编辑: 第一部分和第二部分已经准备好了。但我对第三部分有很大的意见。代码如下:

from urllib import request as uReq
import requests
#dzięki temu program jest zamykany odrazu, i nie kontynuuje wykonywania reszty kodu. Po imporcie wystarczy exit(0)
from sys import exit
from urllib.request import urlopen as uReq2
from bs4 import BeautifulSoup as soup
import csv
import re
import itertools

filename = 'test.txt'

#licznik, potrzebny do obliczenia ilości numerów ofert w pliku .txt
num_lines = 0

# tworzymy listę danych i listę URLi. Wyniki będą dodawane do list, dlatego potrzeba jest ich utworzenia (jako puste)
list_of_lines = ['351238', '351237', '111111', '351353']
list_of_lines2 = []
list_of_URLs = []
list_of_redictered_URLs = []
KONTRAKT = 'http://www.kontrakt.szczecin.pl'

with open(filename, 'r') as file:
    for line in file:
        #dodajemy linię (ofertę) do listy
        list_of_lines.append(line.strip())
        #num_lines jest licznikiem, wskazuje ile wierszy zawiera lista, zmienna jest istotna w zakresię tworzenia pętli z adresami URL
        num_lines += 1

#tworzymy URLe z Numerów Ofert zawartych w filename

for i in range(num_lines):
    nr_oferty = list_of_lines[i]
    my_url = "http://www.kontrakt.szczecin.pl/lista-ofert/?f_listingId=" + nr_oferty + "&f=&submit=Szukaj"
    list_of_URLs.append(my_url)
print(list_of_URLs)




#Cześć druga: konwertowanie listy linków na listę linków przekierowanych

#Program wchodzi na stronę, która powinna być przekierowana, jednak ze względu na użyscie Java Scriptu,
#zadanie zostało utrudnione. Dlatego, też celem programu jest symulowanie przeglądarki, pobranie
#zawartości strony, a następnie 'wyłuskanie' odpowiedniego linku do przekierowania

i = 0
for i in range(num_lines):
    url_redirect = list_of_URLs[i]
    my_url = url_redirect
    BROWSER = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'}
    response = requests.get(my_url, headers=BROWSER)
    script1 = '<script>'
    script2 = '</script>'
    content_URL = str(response.content)
    find_script1 = (content_URL.find(script1))
    find_script2 = (content_URL.find(script2))
    url_ready = content_URL[find_script1:find_script2]
    print(i+1,'z', num_lines, '-', 'oferta nr:', str(my_url[57:57+6]))
    list_of_redictered_URLs.append(url_ready)

#usuwanie zbędnych tagów i znaków, w celu uzyskania czystego przekierowanego linku
list_of_redictered_URLs = [w.replace('<script>window.location=\\\'','') for w in list_of_redictered_URLs]
list_of_redictered_URLs = [w.replace('\\\';','') for w in list_of_redictered_URLs]
#print(list_of_redictered_URLs)
#usuwanie pustych wierszy z listy (oferty, które są nieakutalne na liste "wchodzą jako puste" !!! item: jest to zmienna, można zamienić np. na janusz.
filtered_list = list(filter(lambda item: item.strip(), list_of_redictered_URLs))
filtered_list = [KONTRAKT + item for item in filtered_list]
#zmiana na tuple, ze względu iż mutowalność (dodawanie kolejnych linków) nie będzie potrzebne
filtered_list = tuple(filtered_list)

#print(str(filtered_list))

print('Lista linków:\n',filtered_list)

# Kolejną częścią programu jest pobieranie istotnych informacji (parametrów podstawowych)
# ze strony kontrakt.szczecin.pl, a następnie ich zapisanie w pliku csv.

# Nagłówki w csv oraz nazwy parametrów na stronie (muszą być identyczne jak na stronie, aby mogły
# zostać odpowiednio przyporządkowane w .csv)

HEADERS = ['Numer oferty',
           'Liczba pokoi',
           'Cena',
           'Cena za m2',
           'Powierzchnia',
           'Piętro',
           'Liczba pięter',
           'Typ kuchni',
           'Balkon',
           'Czynsz administracyjny',
           'Rodzaj ogrzewania',
           'Umeblowanie',
           'Wyposażona kuchnia',
           'Gorąca woda',
           'Rodzaj budynku',
           'Materiał',
           'Rok budowy',
           'Stan nieruchomości',
           'Rynek',
           'Dach:',
           'Liczba balkonów:',
           'Liczba tarasów:',
           'Piwnica:',
           'Ogród:',
           'Ochrona:',
           'Garaż:',
           'Winda:',
           'Kształt działki:',
           'Szerokość działki (mb.):',
           'Długość działki (mb.):',
           'Droga dojazdowa:',
           'Gaz:',
           'Prąd:',
           'Siła:','piwnica',
            'komórk',
            'strych',
            'gospodarcze',
            'postojow',
            'parking',
            'przynależn',
            'garaż',
            'ogród',
            'ogrod',
            'działka',
            'ocieplony',
            'moderniz',
            'restaur',
            'odnow',
            'ociepl',
            'remon',
            'elew',
            'dozór',
            'dozor',
            'monitoring',
            'monit',
            'ochron',
            'alarm',
            'strzeż',
            'portier',
            'wspólnot',
            'spółdziel',
            'kuchni',
            'aneks',
            'widna',
            'ciemna',
            'prześwit',
            'oficyn',
            'linia',
            'zabudow',
            'opłat',
            'bezczynsz',
            'poziom',
            'wind',
            'francuski',
            'ul.',
            'w cenie',
            'dodatkową']

LINKI = ["Link"]

#HEADERS2 = ['Liczba balkonów:',
#           'Liczba tarasów:',
#           'Piwnica:',
#           'Ogród:',
#           'Ochrona:',
#           'Garaż:',
#           'Winda:']

HEADERS3 = ['piwnica',
            'komórk',
            'strych',
            'gospodarcze',
            'postojow',
            'parking',
            'przynależn',
            'garaż',
            'ogród',
            'ogrod',
            'działka',
            'ocieplony',
            'moderniz',
            'restaur',
            'odnow',
            'ociepl',
            'remon',
            'elew',
            'dozór',
            'dozor',
            'monitoring',
            'monit',
            'ochron',
            'alarm',
            'strzeż',
            'portier',
            'wspólnot',
            'spółdziel',
            'kuchni',
            'aneks',
            'widna',
            'ciemna',
            'prześwit',
            'oficyn',
            'linia',
            'zabudow',
            'opłat',
            'bezczynsz',
            'poziom',
            'wind',
            'francuski',
            'ul.',
            'w cenie',
            'dodatkową',]

csv_name = 'data.csv'
print('Dane zostaną zapisane do pliku:',csv_name + '.csv')
print('\n>>>>Program rozpoczyna pobieranie danych')
#Pobieranie linków

i = 0  
#Tworzy plik csv o nazwie csv
#writerow może mieć tylko jeden argument, dlatego jest nim suma poszczególnych list. Lista
#linki ma jędną pozycję, ponieważ można sumować dane jednego typu. Nie można sumować listy ze stringami.
with open(csv_name + '.csv', 'w', newline='') as csvfile:
    csvwriter = csv.writer(csvfile, delimiter=',', quotechar='"')
    HEADERS_ALL = HEADERS+HEADERS3+LINKI
    csvwriter.writerow(HEADERS_ALL)

    for i in range(len(filtered_list)):
        my_url = filtered_list[i]
        with uReq2(my_url) as uClient:
            page_soup = soup(uClient.read(), 'lxml')
            print('\t\t-----------',i+1,'-----------\n',my_url)


        #<dt> - nazwa parametru np. Kuchnia
        #<dd> - wartość parametru np. widna   
        row = ['-'] * len(HEADERS) + ['-'] * len(HEADERS3) + ['-'] * len(LINKI)
        # Parametry podstawowe (kontrakt.szczecin.pl)
        for dt, dd in zip(page_soup.select('section#quick-summary dt'), page_soup.select('section#quick-summary dd')):
            if dt.text.strip() not in HEADERS:
                print("\n 1(dt,dd):UWAGA!, kolumna [{}] nie istnieje w nagłówkach! (stała: HEADERS)\n".format(dt.text.strip()))
                continue
            row[HEADERS.index(dt.text.strip())] = dd.text.strip()

        # Parametry dodatkowe
        for span, li in zip(page_soup.select('section#property-features span'), page_soup.select('section#property-features li')):
            if span.text.strip() not in HEADERS:
                print("\n 2:UWAGA(span,li), kolumna [{}] nie istnieje w nagłówkach (stała HEADERS)!\n".format(span.text.strip()))
                continue
            row[HEADERS.index(span.text.strip())] = li.text.strip()
        #csvwriter.writerow(row)
        print(row)

#No to zaczynamy zabawę...................................

        # zmienna j odnosi się do indeksu HEADERS3, jest to j nie i, ponieważ i jest w dalszym użyciu
        # w pętli powyżej

        for p in page_soup.select('section#description'):
            p = str(p)
            p = p.lower() 


            for j in range(len(HEADERS3)): 
                #print('j:',j)
                # find_p znajduje wszystkie słowa kluczowe z HEADERS3 w paragrafie na stronie kontraktu.
                find_p = re.findall(HEADERS3[j],p)
                # listy, które wyświetlają pozycję startową poszczególnych słów muszą zaczynać się od '-' lub 0?,
                # ponieważ, gdy dane słowo nie zostanie odnalezione to listy będą puste w pierwszej iteracji pętli
                # co w konsekewncji doprowadzi do błędu out of range
                m_start = []
                m_end = []
                lista_j = []

                for m in re.finditer(HEADERS3[j], p):
                    #print((m.start(),m.end()), m.group())
                    m_start.append(m.start())
                    m_end.append(m.end())

                #print(h)

                for k in range(len(m_start)):
                    #właściwe teraz nie wiem po co to jest..
                    try:
                        x = m_start[k]
                        y = m_end[k]
                    except IndexError:
                        x = m_start[0]
                        y = m_end[0]
                    #print('xy:',x,y)
                    #print(find_p) 
                #print(HEADERS3[j])
                    z = (HEADERS3[j]+':',p[-60+x:y+60]+'    ++-NNN-++') 
                    lista_j.append(z)
                print (lista_j)


        print(str(lista_j))
        row[HEADERS.index(span.text.strip())] = str(lista_j)
        csvwriter.writerow(row)
        #print(row)

Tags: ofcsvinurlforfindurlslist
1条回答
网友
1楼 · 发布于 2024-05-29 03:04:14

此代码段将解析属性url的快速摘要表,并将其保存在csv文件中:

from urllib.request import urlopen as uReq
from bs4 import BeautifulSoup as soup
import csv

# my_url = 'http://www.kontrakt.szczecin.pl/mieszkanie-sprzedaz-6664m2-339600pln-potulicka-nowe-miasto-szczecin-zachodniopomorskie,351165'
my_url = 'http://www.kontrakt.szczecin.pl/mieszkanie-sprzedaz-100m2-335000pln-grudziadzka-pomorzany-szczecin-zachodniopomorskie,351149'

with uReq(my_url) as uClient:
    page_soup = soup(uClient.read(), 'lxml')


with open('data.csv', 'w', newline='') as csvfile:
    csvwriter = csv.writer(csvfile, delimiter=',', quotechar='"')

    for dt, dd in zip(page_soup.select('section#quick-summary dt'), page_soup.select('section#quick-summary dd')):
        csvwriter.writerow([dt.text.strip(), dd.text.strip()])

结果显示在data.csv,my LibreOffice的屏幕截图中:

enter image description here

要转换表,可以使用以下代码:

from urllib.request import urlopen as uReq
from bs4 import BeautifulSoup as soup
import csv

# my_url = 'http://www.kontrakt.szczecin.pl/mieszkanie-sprzedaz-6664m2-339600pln-potulicka-nowe-miasto-szczecin-zachodniopomorskie,351165'
my_url = 'http://www.kontrakt.szczecin.pl/mieszkanie-sprzedaz-100m2-335000pln-grudziadzka-pomorzany-szczecin-zachodniopomorskie,351149'

with uReq(my_url) as uClient:
    page_soup = soup(uClient.read(), 'lxml')

headers = ['Numer oferty',
           'Liczba pokoi',
           'Cena',
           'Cena za m2',
           'Powierzchnia',
           'Piętro',
           'Liczba pięter',
           'Typ kuchni',
           'Balkon',
           'Czynsz administracyjny',
           'Rodzaj ogrzewania',
           'Gorąca woda',
           'Rodzaj budynku',
           'Materiał',
           'Rok budowy',
           'Stan nieruchomości',
           'Rynek',
           'Dach:',
           'Liczba balkonów:',
           'Piwnica:',
           'Kształt działki:',
           'Szerokość działki (mb.):',
           'Długość działki (mb.):',
           'Droga dojazdowa:',
           'Gaz:',
           'Prąd:',
           'Siła:']

with open('data.csv', 'w', newline='') as csvfile:
    csvwriter = csv.writer(csvfile, delimiter=',', quotechar='"')
    csvwriter.writerow(headers)

    row = ['-'] * len(headers)
    for dt, dd in zip(page_soup.select('section#quick-summary dt'), page_soup.select('section#quick-summary dd')):
        if dt.text.strip() not in headers:
            print("Warning, column [{}] doesn't exist in headers!".format(dt.text.strip()))
            continue
        row[headers.index(dt.text.strip())] = dd.text.strip()
    csvwriter.writerow(row)

结果将出现在csv文件中,如下所示(不存在的值将替换为“-”):

enter image description here

相关问题 更多 >

    热门问题