Home > Software engineering >  How to seperate and replace specific scraped strings?
How to seperate and replace specific scraped strings?

Time:05-13

I want to clean up scraped text from <dd> and <dt>, output looks like this:

Įrengimas:': 'Dalinė apdailaNAUDINGA:Interjero dizaineriai', 'Ypatybės:': 'Nauja kanalizacijaNauja elektros instaliacija',

My desired outputd:

Įrengimas:': 'Dalinė apdaila, 'Ypatybės:': 'Nauja kanalizacija, Nauja elektros instaliacija',

My code block, to get that text:

def get_dl(soup):
    d_list = {}

    for dl in soup.findAll("dl", {"class": "obj-details"}):
        for el in dl.find_all(["dt", "dd"]):
            if el.name == 'dt':
                key = el.get_text(strip=True)
            elif key in ['Plotas:', 'Buto numeris:', 'Metai:', 'Namo numeris:', 'Kambarių sk.:', 'Aukštas:', 'Aukštų sk.:', 'Pastato tipas:', 'Šildymas:', 'Įrengimas:', 'Pastato energijos suvartojimo klasė:', 'Ypatybės:', 'Papildomos patalpos:', 'Papildoma įranga:', 'Apsauga:']:
                d_list[key] = el.get_text(strip=True)

    return d_list

So, what is best practice to fix text in this situation ?

Adding full code, to see whole picture:

from selenium import webdriver
from bs4 import BeautifulSoup
import re
import csv


PATH = 'C:\Program Files (x86)\chromedriver.exe'
driver = webdriver.Chrome(PATH)
data = []


def get_dl(soup):
    d_list = {}

    for dl in soup.findAll("dl", {"class": "obj-details"}):
        for el in dl.find_all(["dt", "dd"]):
            if el.name == 'dt':
                key = el.get_text(strip=True)
            elif key in ['Plotas:', 'Buto numeris:', 'Metai:', 'Namo numeris:', 'Kambarių sk.:', 'Aukštas:', 'Aukštų sk.:', 'Pastato tipas:', 'Šildymas:', 'Įrengimas:', 'Pastato energijos suvartojimo klasė:', 'Ypatybės:', 'Papildomos patalpos:', 'Papildoma įranga:', 'Apsauga:']:
                d_list[key] = el.get_text(strip=True)

    return d_list



for puslapis in range(2, 3):
    driver.get(f'https://www.aruodas.lt/butai/vilniuje/puslapis/{puslapis}')
    response = driver.page_source
    soup = BeautifulSoup(response, 'html.parser')
    blocks = soup.find_all('tr', class_='list-row')
    stored_urls = []

    for url in blocks:
        try:
            stored_urls.append(url.a['href'])
        except:
            pass

    for link in stored_urls:
        driver.get(link)
        response = driver.page_source
        soup = BeautifulSoup(response, 'html.parser')
        h1 = soup.find('h1', 'obj-header-text')
        price = soup.find('div', class_ = 'price-left')

        try:
            address1 = h1.get_text(strip=True)
            address2 = re.findall(r'(.*),[^,]*$', address1)
            address = ''.join(address2)
            city, district, street = address.split(',')
        except:
            address = 'NaN'

        try:
            full_price = price.find('span', class_ = 'price-eur').text.strip()
        except:
            full_price = 'NaN'

        try:
            price_sq_m = price.find('span', class_ = 'price-per').text.strip()
        except:
            price_sq_m = 'NaN'

        try:
            price_change = price.find('div', class_ = 'price-change').text.strip()
        except:
            price_change = 'NaN'

        data.append({'city': city, 'district': district, 'street': street, 'full_price': full_price, 'price_sq_m': price_sq_m, 'price_change:': price_change, **get_dl(soup)})

for entry in data:

    print(entry)

driver.quit()

CodePudding user response:

Labas. Is the "Naudinga" part the main issue, are there any other words/phrases that can occur? If not, try this.

#Replace your line code: 
d_list[key] = el.get_text(strip=True)

#With this mess:
d_list[key] = ' '.join(el.text.strip().replace("\n", ", ").split('NAUDINGA')[0].split())

CodePudding user response:

If there is only a single string to replace() shortest approach would be to go with get_text() and its parameters to strip and join / separate bits by whitespace:

d_list[key] = el.get_text(' ', strip=True).replace(' NAUDINGA: Interjero dizaineriai','')

If there are multiple strings I would recommend to use stripped_strings, what would nearly the same, and a list comprehension to check / exclude unwanted strings:

d_list[key] = ' '.join([e for e in list(el.stripped_strings) if e not in ['NAUDINGA:','Interjero dizaineriai']])
Example based on your function
def get_dl(soup):
    d_list = {}

    for dl in soup.find_all("dl", {"class": "obj-details"}):
        for el in dl.find_all(["dt", "dd"]):
            if el.name == 'dt':
                key = el.get_text(strip=True)
            elif key in ['Plotas:', 'Buto numeris:', 'Metai:', 'Namo numeris:', 'Kambarių sk.:', 'Aukštas:', 'Aukštų sk.:', 'Pastato tipas:', 'Šildymas:', 'Įrengimas:', 'Pastato energijos suvartojimo klasė:', 'Ypatybės:', 'Papildomos patalpos:', 'Papildoma įranga:', 'Apsauga:']:
                d_list[key] = ' '.join([e for e in list(el.stripped_strings) if e not in ['NAUDINGA:','Interjero dizaineriai']])
    return d_list

Sample output:

{'Namo numeris:': '10', 'Plotas:': '35,08 m²', 'Kambarių sk.:': '2', 'Aukštas:': '1', 'Aukštų sk.:': '5', 'Metai:': '2022', 'Pastato tipas:': 'Mūrinis', 'Šildymas:': 'Centrinis kolektorinis', 'Įrengimas:': 'Dalinė apdaila', 'Pastato energijos suvartojimo klasė:': 'A  ', 'Apsauga:': 'Šarvuotos durys Kodinė laiptinės spyna Vaizdo kameros'}
{'Namo numeris:': '10', 'Plotas:': '50,97 m²', 'Kambarių sk.:': '2', 'Aukštas:': '5', 'Aukštų sk.:': '5', 'Metai:': '2022', 'Pastato tipas:': 'Mūrinis', 'Šildymas:': 'Centrinis kolektorinis', 'Įrengimas:': 'Dalinė apdaila', 'Pastato energijos suvartojimo klasė:': 'A  ', 'Papildomos patalpos:': 'Balkonas', 'Apsauga:': 'Šarvuotos durys Kodinė laiptinės spyna Vaizdo kameros'}
{'Namo numeris:': '10', 'Plotas:': '47,25 m²', 'Kambarių sk.:': '2', 'Aukštas:': '4', 'Aukštų sk.:': '5', 'Metai:': '2022', 'Pastato tipas:': 'Mūrinis', 'Šildymas:': 'Centrinis kolektorinis', 'Įrengimas:': 'Dalinė apdaila', 'Pastato energijos suvartojimo klasė:': 'A  ', 'Papildomos patalpos:': 'Balkonas', 'Apsauga:': 'Šarvuotos durys Kodinė laiptinės spyna Vaizdo kameros'}
{'Namo numeris:': '55', 'Plotas:': '34,8 m²', 'Kambarių sk.:': '1', 'Aukštas:': '8', 'Aukštų sk.:': '9', 'Metai:': '1988', 'Pastato tipas:': 'Mūrinis', 'Šildymas:': 'Centrinis', 'Įrengimas:': 'Įrengtas', 'Ypatybės:': 'Nauja kanalizacija Nauja elektros instaliacija Internetas', 'Papildomos patalpos:': 'Sandėliukas Balkonas Drabužinė', 'Papildoma įranga:': 'Skalbimo mašina Su baldais Šaldytuvas Virtuvės komplektas Viryklė Plastikiniai vamzdžiai Indaplovė Dušo kabina', 'Apsauga:': 'Šarvuotos durys Signalizacija Kodinė laiptinės spyna'}

Just in case, you also can go with css selectors to select your elements more specific:

def get_dl(soup):
    d_list = {}
    for el in soup.select('dl.obj-details dt:has( dd)'):
        key = el.get_text(strip=True)
        if key in ['Plotas:', 'Buto numeris:', 'Metai:', 'Namo numeris:', 'Kambarių sk.:', 'Aukštas:', 'Aukštų sk.:', 'Pastato tipas:', 'Šildymas:', 'Įrengimas:', 'Pastato energijos suvartojimo klasė:', 'Ypatybės:', 'Papildomos patalpos:', 'Papildoma įranga:', 'Apsauga:']:
            d_list[key] = ' '.join([e for e in list(el.find_next('dd').stripped_strings) if e not in ['NAUDINGA:','Interjero dizaineriai']])
    return d_list
  • Related