Data scraping - BeautifulSoup

0

Piszę przykładowy skrypt, który ze strony z ogłoszeniami nieruchomości będzie pobierał tytuł ogłoszenia, kategorię i cenę.

Potrafię pobrać tytuł i kategorię i zapisać jako jedną linię do pliku csv ale mam problem z ceną. W sekcji którą wybrałem jako pojedyncze ogłoszenie, nie pokazuje ceny pomimo, że jak wejdę w źródło strony wygląda, że ta cena tam jest. Poradzi ktoś jaką sekcję wybrać żebym miał w niej powyższe informacje? Lub co zrobić aby dopisać cenę do już zapisanych w pliku linii? Cenę potrafię pobrać osobnym kodem. Kod wraz z adresem do strony wklejam poniżej.

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

my_url = 'https://www.morizon.pl/mieszkania/krakow/'
uClient = uReq(my_url)
page_html = uClient.read()
uClient.close()

'''html parsing'''
page_soup = soup(page_html, 'html.parser')

containers = page_soup.findAll('section', {'class': 'single-result__content single-result__content--height'})

file_name = 'scraping.csv'
f = open(file_name, 'w')
names = 'Location, Category, Price\n'
f.write(names)

for container in containers:
    '''grabs each title'''
    headers = container.findAll('h2', {'class': 'single-result__title'})
    header = headers[0].text.strip()

    '''grabs each category'''
    categories = container.findAll('p', {'class': 'single-result__category'})
    category = categories[0].text.strip()

    prices = page_soup.findAll('p', {'class': 'single-result__price'})
    price = prices[0].text

    f.write(header + ',' + category + ', ' + price + '\n')
0
Grzegooo napisał(a):

Piszę przykładowy skrypt, który ze strony z ogłoszeniami nieruchomości będzie pobierał tytuł ogłoszenia, kategorię i cenę.

Potrafię pobrać tytuł i kategorię i zapisać jako jedną linię do pliku csv ale mam problem z ceną. W sekcji którą wybrałem jako pojedyncze ogłoszenie, nie pokazuje ceny pomimo, że jak wejdę w źródło strony wygląda, że ta cena tam jest. Poradzi ktoś jaką sekcję wybrać żebym miał w niej powyższe informacje? Lub co zrobić aby dopisać cenę do już zapisanych w pliku linii? Cenę potrafię pobrać osobnym kodem. Kod wraz z adresem do strony wklejam poniżej.

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

my_url = 'https://www.morizon.pl/mieszkania/krakow/'
uClient = uReq(my_url)
page_html = uClient.read()
uClient.close()

'''html parsing'''
page_soup = soup(page_html, 'html.parser')

containers = page_soup.findAll('section', {'class': 'single-result__content single-result__content--height'})

file_name = 'scraping.csv'
f = open(file_name, 'w')
names = 'Location, Category, Price\n'
f.write(names)

for container in containers:
    '''grabs each title'''
    headers = container.findAll('h2', {'class': 'single-result__title'})
    header = headers[0].text.strip()

    '''grabs each category'''
    categories = container.findAll('p', {'class': 'single-result__category'})
    category = categories[0].text.strip()

    prices = page_soup.findAll('p', {'class': 'single-result__price'})
    price = prices[0].text

    f.write(header + ',' + category + ', ' + price + '\n')

Może cena jest za javascriptem? Ewentualnie złęgo xpatha podałeś

0

Ogólnie z java scriptem nie miałem nigdy nic wspólnego więc to jest całkiem możliwe. Łapcie wycinek kodu z tej strony. Mój container to jest właśnie section class = single-result... i jak dla mnie to ta cena jest dalej pod p class = single-result__price. Ale jak wyprintuje sobie ten container w pythonie to tej ceny już nie ma. Jest tytuł i kategoria.

<section class="single-result__content single-result__content--height">
<header>
<meta itemprop="category" content="Mieszkanie na sprzedaż"/>
<a href="https://www.morizon.pl/oferta/sprzedaz-mieszkanie-krakow-debniki-63m2-mzn2026902513" title=""
class="property_link" itemprop="url">
<div class="row">
<div class="col-xs-8">
<h2 class="single-result__title">
Kraków, Dębniki </h2>
<p class="single-result__category" itemprop="name">
Mieszkanie na sprzedaż, dodane: 03-07-2018 </p>
</div>
<div class="col-xs-4">
<p class="single-result__price">296&nbsp;100&nbsp;zł</p><p class="single-result__price single-result__price--currency">4700 zł/m&#178;</p> <meta itemprop="price" content="296100.00">
<meta itemprop="priceCurrency" content="PLN">
</div>
</div>
</a>
</header>
<div class="info-description single-result__info">
<ul class="param list-unstyled list-inline">
<li><b>3</b> pokoje</li> <li><b>63</b> m²</li> <li><b>2017</b> rok</li> </ul>
</div>
<div class="description single-result__description" itemprop="description">
<p>Prestige City Osiedle zostało tak zaprojektowane by każdy mieszkaniec znalazł tu coś dla siebie. Wiemy że dla każdego człowieka ważne są inne aspekty życia, Jedni chcą prowadzić aktywny styl życia, inni nastawiają się na zdrowie. Część najbardziej ceni sobie bezpieczeństwo, a jeszcze inni mają bzika na punkcie technologii. My zaprojektowaliśmy WSZYSTKIE pożądane cechy osiedla mieszkaniowego w ramach jednego kompletnego projektu. TWORZĄC </p>
</div>
</section>
0

Pokaz co wypluje z samym price = prices[0] bez .text

0

Rozumiem, że w tej chwili masz coś takiego tylko bez ceny?

Location, Category, Price 
Kraków, Dębniki,Mieszkanie na sprzedaż, dodane: 03-07-2018, 296 100 zł
Kraków, Prądnik Czerwony, ul. Reduta 26,Mieszkanie na sprzedaż, dodane: 02-07-2018, 296 100 zł
Kraków, Prądnik Czerwony, ul. Reduta 26,Mieszkanie na sprzedaż, dodane: 11-05-2018, 296 100 zł
.
.
.
Kraków, Bieżanów-Prokocim, ul. Braci Czeczów/ul. Opalowa Pokaż legendę,Mieszkanie na sprzedaż, dodane: 06-08-2018, 296 100 zł
Kraków, Bieżanów-Prokocim, ul. Braci Czeczów/ul. Opalowa Pokaż legendę,Mieszkanie na sprzedaż, dodane: 06-08-2018, 296 100 zł

.
.
.

0
Biały Szewc napisał(a):

Pokaz co wypluje z samym price = prices[0] bez .text

wyrzuca błąd "list index out of range"

0
vitz666 napisał(a):

Rozumiem, że w tej chwili masz coś takiego tylko bez ceny?

Location, Category, Price 
Kraków, Dębniki,Mieszkanie na sprzedaż, dodane: 03-07-2018, 296 100 zł
Kraków, Prądnik Czerwony, ul. Reduta 26,Mieszkanie na sprzedaż, dodane: 02-07-2018, 296 100 zł
Kraków, Prądnik Czerwony, ul. Reduta 26,Mieszkanie na sprzedaż, dodane: 11-05-2018, 296 100 zł
.
.
.
Kraków, Bieżanów-Prokocim, ul. Braci Czeczów/ul. Opalowa Pokaż legendę,Mieszkanie na sprzedaż, dodane: 06-08-2018, 296 100 zł
Kraków, Bieżanów-Prokocim, ul. Braci Czeczów/ul. Opalowa Pokaż legendę,Mieszkanie na sprzedaż, dodane: 06-08-2018, 296 100 zł

.
.
.

Dokładnie tak. To jest przykładowa linia mojego outputu

Kraków, Podgórze, Krasickiego,Mieszkanie na sprzedaż, dodane: 21-09-2018
0

Coś takiego mi działa i daje rezultat taki jak pisałem wyżej

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

my_url = 'https://www.morizon.pl/mieszkania/krakow/'
uClient = uReq(my_url)
page_html = uClient.read()
uClient.close()

'''html parsing'''
page_soup = soup(page_html, 'html.parser')

containers = page_soup.findAll('section', {'class': 'single-result__content single-result__content--height'})

file_name = 'scraping.txt'
with io.open(file_name,'w',encoding='utf8') as f:
    names = 'Location, Category, Price \n'
    f.write(names)

    for container in containers:
        '''grabs each title'''
        headers = container.findAll('h2', {'class': 'single-result__title'})
        header = headers[0].text.strip()

        '''grabs each category'''
        try:
            categories = container.findAll('p', {'class': 'single-result__category'})
            category = categories[0].text.strip()
        except:
            category = "no_category"

        prices = page_soup.findAll('p', {'class': 'single-result__price'})
        price = prices[0].text


        f.write(str(header) + ',' + str(category) + ', ' + str(price) +'\n' )

0
vitz666 napisał(a):

Coś takiego mi działa i daje rezultat taki jak pisałem wyżej

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

my_url = 'https://www.morizon.pl/mieszkania/krakow/'
uClient = uReq(my_url)
page_html = uClient.read()
uClient.close()

'''html parsing'''
page_soup = soup(page_html, 'html.parser')

containers = page_soup.findAll('section', {'class': 'single-result__content single-result__content--height'})

file_name = 'scraping.txt'
with io.open(file_name,'w',encoding='utf8') as f:
    names = 'Location, Category, Price \n'
    f.write(names)

    for container in containers:
        '''grabs each title'''
        headers = container.findAll('h2', {'class': 'single-result__title'})
        header = headers[0].text.strip()

        '''grabs each category'''
        try:
            categories = container.findAll('p', {'class': 'single-result__category'})
            category = categories[0].text.strip()
        except:
            category = "no_category"

        prices = page_soup.findAll('p', {'class': 'single-result__price'})
        price = prices[0].text


        f.write(str(header) + ',' + str(category) + ', ' + str(price) +'\n' )

Tak, kod rzeczywiście działa, tylko do każdej linii podaje tą samą cenę. On po prostu wyszukuje wszystkie ceny na stronie i do każdej linii wrzuca pierwszą pozycję z listy.

Ciągle nie wiem czemu nie mogę rozpisać wyszukiwania ceny tak jak nagłówków i kategorii ;/

0

Faktycznie nie spojrzałem na to, że wszędzie cena jest ta samo

1

Teraz musi działać

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

my_url = 'https://www.morizon.pl/mieszkania/krakow/'
uClient = uReq(my_url)
page_html = uClient.read()
uClient.close()

'''html parsing'''
page_soup = soup(page_html, 'html.parser')

containers = page_soup.findAll('section', {'class': 'single-result__content single-result__content--height'})

file_name = 'scraping.txt'
with io.open(file_name,'w',encoding='utf8') as f:
    names = 'Location, Category, Price \n'
    f.write(names)

    for container in containers:
        '''grabs each title'''
        headers = container.findAll('h2', {'class': 'single-result__title'})
        header = headers[0].text.strip()

        '''grabs each category'''
        try:
            categories = container.findAll('p', {'class': 'single-result__category'})
            category = categories[0].text.strip()
        except:
            category = "no_category"

        try:
            prices = container.findAll('p', {'class': 'single-result__price'})
            price = prices[0].text.strip()
        except:
            price = "no_price"


        print(str(header) + ',' + str(category) + ', ' + str(price) +'\n' )

0

@vitz666: Jesteś wielki! Działa jak należy. Dziękuje bardzo za pomoc! Zabieram się za analizę :)

0
  1. Sprawdź sobie jeszcze czy jak jest podana cena "od - do" to działa, bo sądze ze może nie działać i wpisywać "no_price".
  2. Reklama to też kontener i można go pewnie jakoś pominąć -> Chcesz wziąć kredyt i potrzebujesz porady?,Nowa oferta morizon.pl dla osób rozważających wzięcie kredytu., no_price
  3. Separator warto zmienić na inny np ";" zamiast przecinka, bo adresy są nim oddzielane.
  4. Do zapisu CSV warto wykorzystać inne libki a nie zwykły zapis >>txt, chyba ze program w ktorym to analizujesz łyka taki format jak mas obecnie

1 użytkowników online, w tym zalogowanych: 0, gości: 1