如何通过网络抓取从维基百科表格中提取数字(或字符串)数据?
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
我想使用 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