如何通过网络抓取从维基百科表格中提取数字(或字符串)数据?

How to extract numerical (or string) data from wikipedia tables via webscraping?

我想使用 BeautifulSoup 从维基百科文章中抓取数据以创建 HR 图。对于下面的示例,我选择了名为 Arcturus 的恒星,尽管代码的目的是足够通用以适用于(几乎?)任何恒星。每个星号的维基百科页面最右边的 table 包含构建图表所需的所有信息。

例如,考虑 wikipedia page for Arcturus。光谱类型可以在 Characteristics 子标题下找到;绝对大小可以在 Astrometry 子标题下找到;亮度和温度可以在 Details 子标题下找到。由于所有这些信息都包含在同一个主 table 中,我尝试了以下操作:

import requests
from bs4 import BeautifulSoup
# import numpy as np
# import matplotlib.pyplot as plt

hyperlink = 'https://en.wikipedia.org/wiki/Arcturus'
webdata = requests.get(hyperlink)
soup = BeautifulSoup(webdata.text, 'lxml')
# print("\nPRETTY SOUP:\n{}\n".format(soup.prettify()))

res = []
right_table = soup.find('table', class_='infobox')
for row in right_table.findAll('tr'):
    cells = row.findAll('td')
    print("\n .. CELLS:\n{}\n".format(cells))

此代码将为 table 的每一行 运行 一个单独的 print 命令。我使用 ctrl + f 查找单词 "temperature" 的出现次数,从中我找到了相关的 print 语句:

 .. CELLS:
[<td><b><a href="/wiki/Effective_temperature" title="Effective temperature">Temperature</a></b></td>, <td><span class="nowrap"><span data-sort-value="7003428600000000000♠"></span>4286<span style="margin-left:0.3em;margin-right:0.15em;">±</span>30</span><sup class="reference" id="cite_ref-ramirez_prieto_2011_7-3"><a href="#cite_note-ramirez_prieto_2011-7">[7]</a></sup> <a href="/wiki/Kelvin" title="Kelvin">K</a></td>]

实际值为4286 ± 30 K。是否有 easy-to-generalize 方法来解析此 html 字符串?我相信提取其他相关参数(如光谱类型)的方法不会有太大不同。

你可以使用

for row in right_table.findAll('tr'):
    cells = ' '.join([i.get_text() for i in row.findAll('td')])
    print(cells)

但是你会得到例如上级脚本和子脚本。

如果你只想提取特定信息,你可以以此为例(使用CSS selectors获取信息):

import requests
from bs4 import BeautifulSoup

hyperlink = 'https://en.wikipedia.org/wiki/Arcturus'
webdata = requests.get(hyperlink)
soup = BeautifulSoup(webdata.text, 'lxml')

def remove_sup(tag):
    for s in tag.select('sup'):
        s.extract()
    return tag

spectral = remove_sup(soup.select_one(":matches(td, th):contains('Spectral') + td")).get_text(strip=True)
magnitude = remove_sup(soup.select_one(":matches(td, th):contains('Absolute') + td")).get_text(strip=True)
lum = remove_sup(soup.select_one(":matches(td, th):contains('Luminosity') + td")).get_text(strip=True)
temp = remove_sup(soup.select_one(":matches(td, th):contains('Temperature') + td")).get_text(strip=True)

print('{: <25}{}'.format('Spectral type :', spectral))
print('{: <25}{}'.format('Absolute magnitude :', magnitude))
print('{: <25}{}'.format('Luminosity :', lum))
print('{: <25}{}'.format('Temperature :', temp))

打印:

Spectral type :          K0 III
Absolute magnitude :     −0.30±0.02
Luminosity :             170L☉
Temperature :            4286±30K