Python - BS4 - 仅使用表头+保存为字典从维基百科表中提取子表

问题描述 投票:0回答:1

我试图定义一个函数,它提取网站https://de.wikipedia.org/wiki/Stuttgart上的'Basisdaten'表的所有行,并返回一个字典,其键和值对应于表的每一行中的第一个和第二个单元格。

'Basisdaten'表是更大表的一部分,如以下代码的结果所示:

from bs4 import BeautifulSoup 
import requests
r=requests.get("https://de.wikipedia.org/wiki/Stuttgart")
soup=BeautifulSoup(r.text,"html.parser")
soup.find('th', text=re.compile('Basisdaten')).find_parent('table')

不幸的是,没有唯一的ID我只能选择组成'Basisdaten'表的那些行。这些是我希望以HTML格式提取的行:

<tr>
<th colspan="2">Basisdaten
</th></tr>
<tr class="hintergrundfarbe2">
<td><a href="/wiki/Land_(Deutschland)" title="Land (Deutschland)">Bundesland</a>:</td>
<td><a href="/wiki/Baden-W%C3%BCrttemberg" title="Baden-Württemberg">Baden-Württemberg</a>
</td></tr>
<tr class="hintergrundfarbe2">
<td><a href="/wiki/Regierungsbezirk" title="Regierungsbezirk">Regierungsbezirk</a>:
</td>
<td><a href="/wiki/Regierungsbezirk_Stuttgart" title="Regierungsbezirk Stuttgart">Stuttgart</a>
</td></tr>
<tr class="hintergrundfarbe2">
<td><a href="/wiki/H%C3%B6he_%C3%BCber_dem_Meeresspiegel" title="Höhe über dem Meeresspiegel">Höhe</a>:
</td>
<td>247 m ü. <a href="/wiki/Normalh%C3%B6hennull" title="Normalhöhennull">NHN</a>
</td></tr>
<tr class="hintergrundfarbe2">
<td><a href="/wiki/Katasterfl%C3%A4che" title="Katasterfläche">Fläche</a>:
</td>
<td>207,35 km<sup>2</sup>
</td></tr>
<tr class="hintergrundfarbe2">
<td>Einwohner:
</td>
<td style="line-height: 1.2em;">628.032 <small><i>(31. Dez. 2016)</i></small><sup class="reference" id="cite_ref-Metadaten_Einwohnerzahl_DE-BW_1-0"><a href="#cite_note-Metadaten_Einwohnerzahl_DE-BW-1">[1]</a></sup>
</td></tr>
<tr class="hintergrundfarbe2">
<td><a href="/wiki/Bev%C3%B6lkerungsdichte" title="Bevölkerungsdichte">Bevölkerungsdichte</a>:
</td>
<td>3029 Einwohner je km<sup>2</sup>
</td></tr>
<tr class="hintergrundfarbe2">
<td style="vertical-align: top;"><a href="/wiki/Postleitzahl_(Deutschland)" title="Postleitzahl (Deutschland)">Postleitzahlen</a>:
</td>
<td>70173–70619
</td></tr>
<tr class="hintergrundfarbe2">
<td style="vertical-align: top;"><a href="/wiki/Telefonvorwahl_(Deutschland)" title="Telefonvorwahl (Deutschland)">Vorwahl</a>:
</td>
<td>0711
</td></tr>
<tr class="hintergrundfarbe2">
<td style="vertical-align: top;"><a href="/wiki/Kfz-Kennzeichen_(Deutschland)" title="Kfz-Kennzeichen (Deutschland)">Kfz-Kennzeichen</a>:
</td>
<td>S
</td></tr>
<tr class="hintergrundfarbe2">
<td style="vertical-align: top;"><a href="/wiki/Amtlicher_Gemeindeschl%C3%BCssel" title="Amtlicher Gemeindeschlüssel">Gemeindeschlüssel</a>:
</td>
<td>08 1 11 000
</td></tr>
<tr class="hintergrundfarbe2 metadata">
<td><a href="/wiki/UN/LOCODE" title="UN/LOCODE">LOCODE</a>:
</td>
<td>DE STR
</td></tr>
<tr class="hintergrundfarbe2 metadata">
<td><a href="/wiki/NUTS" title="NUTS">NUTS</a>:
</td>
<td>DE111
</td></tr>
<tr class="hintergrundfarbe2">
<td style="vertical-align: top;">Stadtgliederung:
</td>
<td>23 <a href="/wiki/Liste_der_Stadtbezirke_und_Stadtteile_von_Stuttgart" title="Liste der Stadtbezirke und Stadtteile von Stuttgart">Stadtbezirke</a><br/>mit 152 Stadtteilen
</td></tr>
<tr class="hintergrundfarbe2">
<td style="vertical-align: top;">Adresse der<br/>Stadtverwaltung:
</td>
<td>Marktplatz 1<br/>70173 Stuttgart
</td></tr>
<tr class="hintergrundfarbe2" style="vertical-align: top;">
<td>Webpräsenz:
</td>
<td style="max-width: 10em; overflow: hidden; word-wrap: break-word;"><a class="external text" href="//www.stuttgart.de/" rel="nofollow">www.stuttgart.de</a>
</td></tr>
<tr class="hintergrundfarbe2">
<td style="vertical-align: top;"><a href="/wiki/Oberb%C3%BCrgermeister" title="Oberbürgermeister">Oberbürgermeister</a>:
</td>
<td><a href="/wiki/Fritz_Kuhn" title="Fritz Kuhn">Fritz Kuhn</a> (<a href="/wiki/B%C3%BCndnis_90/Die_Gr%C3%BCnen" title="Bündnis 90/Die Grünen">Bündnis 90/Die Grünen</a>)
</td></tr>

我成功编写了这段代码,它以字典形式给出了我想要的结果:

data = []
def extractDict(y):
    results = y.find("th", {"colspan" : "2"}).find_parent('table').select('td')[3:35]
    for row in results:
        data.append(row.text.strip().replace('\xa0', '').replace(':', '').replace('[1]', ''))
    return dict(zip(data[::2], data[1::2]))
basisdaten=extractDict(soup)
basisdaten

结果:

{'Adresse derStadtverwaltung': 'Marktplatz 170173 Stuttgart',
 'Bevölkerungsdichte': '3029Einwohner je km2',
 'Bundesland': 'Baden-Württemberg',
 'Einwohner': '628.032 (31.Dez.2016)',
 'Fläche': '207,35km2',
 'Gemeindeschlüssel': '08111000',
 'Höhe': '247m ü.NHN',
 'Kfz-Kennzeichen': 'S',
 'LOCODE': 'DE STR',
 'NUTS': 'DE111',
 'Oberbürgermeister': 'Fritz Kuhn (Bündnis 90/Die Grünen)',
 'Postleitzahlen': '70173–70619',
 'Regierungsbezirk': 'Stuttgart',
 'Stadtgliederung': '23 Stadtbezirkemit 152 Stadtteilen',
 'Vorwahl': '0711',
 'Webpräsenz': 'www.stuttgart.de'}

但是我正在寻找一个更好的解决方案,它不涉及从父表中选择第4到第35行。我随后打算在其他类似的维基百科网址上使用此代码,并且“Basisdaten”表格在行数方面可能因网站而异。

所有'Basisdaten'表之间的相似之处在于它们都嵌入在第一个表中,并且它们都有两列,因此所有表都以'th colspan =“2”'开头。父表包含其他子表,例如在这种情况下,“巴登 - 符腾堡州的Lage der Stadt Stuttgart”子表位于'Basisdaten'之后。

是否有可能编写一个循环来搜索'Basisdaten'子表头并在此后获取所有行,但是当它到达下一个子表头时停止('th colspan =“2”')?

我只能找到包含Basisdaten表开头的行:

soup.find('th', text=re.compile('Basisdaten'))

希望有道理!我是Beautifulsoup和Python的新手,对我来说这是一个非常具有挑战性的问题。

python beautifulsoup wikipedia
1个回答
0
投票

这应该做

from bs4 import BeautifulSoup
import requests

data = requests.get("https://de.wikipedia.org/wiki/Stuttgart").text
soup = BeautifulSoup(data, "lxml")
trs = soup.select('table[id*="Infobox"] tr')
is_in_basisdaten = False
data = {}
clean_data = lambda x: x.get_text().strip().replace('\xa0', '').replace(':', '')
for tr in trs:
    if tr.th:
        if "Basisdaten" in tr.th.string:
                is_in_basisdaten = True
        if is_in_basisdaten and "Basisdaten" not in tr.th.string:
            break
    elif is_in_basisdaten:
        key, val = tr.select('td')
        data[clean_data(key)] = clean_data(val)

print(data)
© www.soinside.com 2019 - 2024. All rights reserved.