I'm using BeautifulSoup to parse a simple HTML table. Due to some inconsistency in the data BeautifulSoup seems to fail parsing and tagging the content correctly. Here is the code:
import requests
from bs4 import BeautifulSoup
page = 1
city = 'vantaa'.capitalize()
URL = 'https://asuntojen.hintatiedot.fi/haku/?cr=1&t=3&l=0&search=1&sf=0&so=a&renderType=renderTypeTable&print=1&z={}&c={}'.format(page, city)
page = requests.get(URL)
soup = BeautifulSoup(page.content, "html.parser")
tables = soup.find_all('tbody', attrs={'class':'odd'})
table = max(tables, key=len)
rows = table.find_all('tr')
One correctly tagged row looks like this:
<tr>
<td class="area">Area 1</td>
<td>Random string 1 1q, d</td>
<td class="type">xb</td>
<td class="cellAlignRight">38,00</td>
<td class="cellAlignRight">132000</td>
<td class="cellAlignRight">3474</td>
<td class="cellAlignRight">1661</td>
<td>1/1</td>
<td>no</td>
<td>less.</td>
<td>oma
<td>G<sub>2013</sub></td>
</td>
</tr>
However in the middle of the document something fails and the last rows are merged into one huge string
<tr>
<td class="neighborhood">Itä-hakkila</td>
<td>1h, avokeitti&#...</td>
<td class="houseType">rt</td>
<td class="cellAlignRight">21,50</td>
<td class="cellAlignRight">149000</td>
<td class="cellAlignRight">6930</td>
<td class="cellAlignRight">2017</td>
<td>1/2</td>
<td>ei</td>
<td>hyvä</td>
<td>oma <td>C<sub>2013</sub></td>
</tr>
<tr>
<td class="neighborhood">Kivist&#246;</td>
<td>1h kt</td>
<td class="houseType">kt</td>
<td class="cellAlignRight">27,00</td>
<td class="cellAlignRight">132000</td>
<td class="cellAlignRight">4889</td>
<td class="cellAlignRight">2018</td>
<td>5/6</td>
<td>on</td>
<td>hyvä</td>
<td>vuokra <td>C<sub>2013</sub></td>
</tr>
which seems to be caused by this cell 1h, avokeitti&#...
, which BeautifulSoup turns into <td>1h, avokeitti&#...</td>
where as in the actual HTML on the webpage there is no such issue
<tr>
<td class="neighborhood">Itä-hakkila</td>
<td>1h, avokeitti&#...</td>
<td class="houseType">rt</td>
<td class="cellAlignRight">21,50</td>
<td class="cellAlignRight">149000</td>
<td class="cellAlignRight">6930</td>
<td class="cellAlignRight">2017</td>
<td>1/2</td>
<td>ei</td>
<td>hyvä</td>
<td>oma <td>C<sub>2013</sub></td>
</tr>
I've tried using unicode.unescape()
to the whole table which gives TypeError: 'NoneType' object is not callable
, I've tried using re.sub(r'<', '<', text)
to clean the whole table or single rows but that gives TypeError: expected string or bytes-like object
.
I circumvented this issue by just doing df_list = pd.read_html(page.text)
to get the table out as a dataframe (and had to deal with other formatting issues instead), but the original issue was not solved.
CodePudding user response:
It parses this HTML correctly with parser html5lib
soup = BeautifulSoup(page.content, "html5lib")
It may need to install module html5lib
using pip
See more information about different parsers in documentation: Installing a parser
There is table with advantages
and disadvantages
.
CodePudding user response:
You can do that only using Pandas
DataFrame
Code:
import requests
import pandas as pd
url = "https://asuntojen.hintatiedot.fi/haku/?cr=1&t=3&l=0&search=1&sf=0&so=a&renderType=renderTypeTable&print=1&c=VANTAA"
req = requests.get(url)
table = pd.read_html(req.text, attrs = {"id":"mainTable"} )
df = table[0]#.to_csv('score.csv',index = False)
print(df)
Output:
Kaupunginosa ◄ Huoneisto Talot. ◄ ... Kunto ◄ Tontti ◄ Energial. ◄
0 1 1 1 ... 1 1 1
1 NaN 1 NaN ... NaN NaN NaN
2 Yksiö Yksiö Yksiö ... Yksiö Yksiö Yksiö
3 Hiekkaharju 1h kk kh kt ... tyyd. oma E2007
4 Pähkinärinne 1h k ransk.parveke kt ... hyvä vuokra C2013
5 Kaivoksela kerrostalo, yli... kt ... hyvä oma C2018
6 Pähkinärinne 1h, kk kt ... hyvä oma F2013
7 Hakunila 1 h kk kt ... tyyd. oma D2007
8 Hämeenkylä 1h tupak. alkovi kt ... hyvä oma D2013
9 Vaarala/ kuussilta 1h, kt, parvi rt ... hyvä oma B2018
10 Rajakylä 1h kk rt ... hyvä oma D2013
11 Kivistö 1h, kt, kph, la... kt ... hyvä oma C2018
12 Rajatorppa 1h, kk, kph kt ... tyyd. oma E2007
13 Viertola 1h, kt, kph, ra... kt ... hyvä NaN C2013
14 Malminiitty 1h, kt, kph, pa... kt ... hyvä oma B2018
15 Tikkurila 1h, k, lasitett... kt ... tyyd. oma D2007
16 Koivukylä 1h kk kph vh kt ... tyyd. oma F
17 Kivistö 1h, kt, kph, la... kt ... hyvä oma C2013
18 Martinlaakso 1h, pk. kph ja ... kt ... hyvä oma E2013
19 Kaivoksela 1H kk kph kt ... tyyd. oma G2013
20 Myyrmäki 1h kt alkovi kt ... hyvä oma B2018
21 Kivistö 1H KT kt ... hyvä oma C2013
22 Tikkurila 1h, kk, kh, par... kt ... tyyd. oma D2007
23 Asola 1h, kk, alk, vh... kt ... hyvä oma D2007
24 Martinlaakso 1h kt lasitettu... kt ... hyvä oma C2013
25 Varisto 1h, avokeitti... kt ... hyvä NaN C2013
26 Leppäkorpi 1h kph,s rt ... tyyd. oma G2013
27 Itä-hakkila 1h, avokeitti... rt ... hyvä oma C2013
28 Kivistö 1h kt kt ... hyvä vuokra C2013
29 Hakunila 1h, kk, alkovi,... kt ... hyvä oma F2013
30 Martinlaakso 1h kk kt ... huono oma F2013
31 Martinlaakso 1H KT kt ... hyvä oma C2013
32 Tikkurila 1h, kk, psh kt ... tyyd. oma D2007
33 Tikkurila 1h, k, kph, las... kt ... hyvä oma C2013
34 Hiekkaharju 1h, kk, kph, la... kt ... tyyd. oma E2007
35 Rajatorppa 1h kk kph kt ... tyyd. oma E2018
36 Kaivoksela 1h kt parv kt ... hyvä oma B2018
37 Martinlaakso autopaikka kt ... hyvä oma C2013
38 Jokiniemi 1h tupak. kt ... hyvä oma NaN
39 Kivistö 1 h k kt ... hyvä oma C2013
40 Tikkurila 1h,kt,kph kt ... hyvä oma C2013
41 Myyrmäki 1h, k, kph kt ... hyvä oma D2007
42 Asola 1h,kk, kph, ran... kt ... hyvä vuokra C2013
43 Vantaanpuisto 1h, k, kph, ete... kt ... hyvä oma D2007
44 Mikkola 1h kk kt ... tyyd. oma E2007
45 Viertola 1h kt parveke kt ... hyvä oma C2013
46 Simonsilta 1h kk kt ... tyyd. oma D2013
47 Myyrmäki 1h,k,kph,vh,par... kt ... tyyd. oma E2013
48 Myyrmäki 1h kt kt ... hyvä oma C2013
49 Tikkurila 1 h kk kph kt ... hyvä oma C2013
50 Hiekkaharju 1h kk rt ... tyyd. oma F2013
51 Havukoski 1h k kph parveke rt ... hyvä oma E2007
52 Vantaanlaakso 1h kk kt ... huono oma E2018
53 Havukoski 1h kk kt ... tyyd. oma F2013
54 Matari 1h,kk,s,vaatehu... kt ... hyvä oma D2018
55 1 1 1 ... 1 1 1
56 NaN 1 NaN ... NaN NaN NaN
[57 rows x 12 columns]