Python - BS4 - 仅使用表头+保存为字典从维基百科表中提取子表
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python - BS4 - 仅使用表头+保存为字典从维基百科表中提取子表相关的知识,希望对你有一定的参考价值。
我试图定义一个函数,它提取网站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的新手,对我来说这是一个非常具有挑战性的问题。
这应该做
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)
以上是关于Python - BS4 - 仅使用表头+保存为字典从维基百科表中提取子表的主要内容,如果未能解决你的问题,请参考以下文章
python beautifulsoup bs4爬虫 爬取糗事百科
使用python3 requests和bs4进行爬虫(二)爬取文章