pandas read_html ValueError:未找到表

Posted

技术标签:

【中文标题】pandas read_html ValueError:未找到表【英文标题】:pandas read_html ValueError: No tables found 【发布时间】:2019-04-23 05:43:31 【问题描述】:

我正在尝试从“https://www.wunderground.com/personal-weather-station/dashboard?ID=KMAHADLE7#history/tdata/s20170201/e20170201/mcustom.html”天气地下页面中删除历史天气数据。我有以下代码:

import pandas as pd 

page_link = 'https://www.wunderground.com/personal-weather-station/dashboard?ID=KMAHADLE7#history/tdata/s20170201/e20170201/mcustom.html'
df = pd.read_html(page_link)
print(df)

我有以下回应:

Traceback (most recent call last):
 File "weather_station_scrapping.py", line 11, in <module>
  result = pd.read_html(page_link)
 File "/anaconda3/lib/python3.6/site-packages/pandas/io/html.py", line 987, in read_html
  displayed_only=displayed_only)
 File "/anaconda3/lib/python3.6/site-packages/pandas/io/html.py", line 815, in _parse raise_with_traceback(retained)
 File "/anaconda3/lib/python3.6/site-packages/pandas/compat/__init__.py", line 403, in raise_with_traceback
  raise exc.with_traceback(traceback)
ValueError: No tables found

虽然,这个页面显然有一个表格,但它并没有被 read_html 选中。我曾尝试使用 Selenium,以便在阅读之前加载页面。

from selenium import webdriver
from selenium.webdriver.common.keys import Keys

driver = webdriver.Firefox()
driver.get("https://www.wunderground.com/personal-weather-station/dashboard?ID=KMAHADLE7#history/tdata/s20170201/e20170201/mcustom.html")
elem = driver.find_element_by_id("history_table")

head = elem.find_element_by_tag_name('thead')
body = elem.find_element_by_tag_name('tbody')

list_rows = []

for items in body.find_element_by_tag_name('tr'):
    list_cells = []
    for item in items.find_elements_by_tag_name('td'):
        list_cells.append(item.text)
    list_rows.append(list_cells)
driver.close()

现在,问题是它找不到“tr”。我将不胜感激任何建议。

【问题讨论】:

该表格在页面html中不存在,它在页面的其余部分之后异步加载。 Pandas 不会等待页面加载 java 内容。在尝试解析页面之前,您可能需要某种自动化(如 Selenium)来加载页面 嗨,我尝试过使用 Selenium,但仍然遇到问题。如果可能的话,你介意看看我的编辑并提出任何建议吗? 不同的选择器 df=pd.read_html(driver.find_element_by_id("history_table").get_attribute('outerHTML'))[0] 请参阅下面发布的我的答案 【参考方案1】:

这是一个使用 selenium 实现浏览器自动化的解决方案

from selenium import webdriver
import pandas as pd
driver = webdriver.Chrome(chromedriver)
driver.implicitly_wait(30)

driver.get('https://www.wunderground.com/personal-weather-station/dashboard?ID=KMAHADLE7#history/tdata/s20170201/e20170201/mcustom.html')
    df=pd.read_html(driver.find_element_by_id("history_table").get_attribute('outerHTML'))[0]

Time    Temperature Dew Point   Humidity    Wind    Speed   Gust    Pressure  Precip. Rate. Precip. Accum.  UV  Solar
0   12:02 AM    25.5 °C 18.7 °C 75 %    East    0 kph   0 kph   29.3 hPa    0 mm    0 mm    0   0 w/m²
1   12:07 AM    25.5 °C 19 °C   76 %    East    0 kph   0 kph   29.31 hPa   0 mm    0 mm    0   0 w/m²
2   12:12 AM    25.5 °C 19 °C   76 %    East    0 kph   0 kph   29.31 hPa   0 mm    0 mm    0   0 w/m²
3   12:17 AM    25.5 °C 18.7 °C 75 %    East    0 kph   0 kph   29.3 hPa    0 mm    0 mm    0   0 w/m²
4   12:22 AM    25.5 °C 18.7 °C 75 %    East    0 kph   0 kph   29.3 hPa    0 mm    0 mm    0   0 w/m²

编辑并详细说明正在发生的事情,因为上面的单行实际上不是很好的自记录代码:

设置驱动程序后,我们选择带有 ID 值的表(谢天谢地,这个网站实际上使用了合理且描述性的 ID)

tab=driver.find_element_by_id("history_table")

然后,从那个元素,我们得到 HTML 而不是 web 驱动元素对象

tab_html=tab.get_attribute('outerHTML')

我们使用 pandas 来解析 html

tab_dfs=pd.read_html(tab_html)

来自docs:

"read_html 返回一个 DataFrame 对象的列表,即使只有 HTML 内容中包含的单个表格”

所以我们用我们唯一的表索引到那个列表中,索引为零

df=tab_dfs[0]

【讨论】:

您好,非常感谢。这很有效,但如果您能稍微说明一下我们为什么选择一个属性并选择索引 0 处的值,我将不胜感激。 已按细分编辑 非常感谢。这真的很有帮助。【参考方案2】:

您可以使用requests 并避免打开浏览器。

您可以使用以下方法获取当前条件:

https://stationdata.wunderground.com/cgi-bin/stationlookup?station=KMAHADLE7&units=both&v=2.0&format=json&callback=jQuery1720724027235122559_1542743885014&_=15

从左边去掉'jQuery1720724027235122559_1542743885014(',从右边去掉')'。然后处理json字符串。

您可以通过以下方式调用API获取摘要和历史记录

https://api-ak.wunderground.com/api/606f3f6977348613/history_20170201null/units:both/v:2.0/q/pws:KMAHADLE7.json?callback=jQuery1720724027235122559_1542743885015&_=1542743886276

然后你需要从前面去掉'jQuery1720724027235122559_1542743885015(',从右边去掉');'。然后你就有了一个可以解析的 JSON 字符串。

JSON 示例:

您可以通过在浏览器中使用 F12 开发工具并检查网络选项卡中页面加载期间创建的流量来找到这些 URL。

current 的示例,注意到 JSON 中的 nulls 似乎存在问题,因此我将替换为 "placeholder"

import requests
import pandas as pd
import json
from pandas.io.json import json_normalize
from bs4 import BeautifulSoup

url = 'https://stationdata.wunderground.com/cgi-bin/stationlookup?station=KMAHADLE7&units=both&v=2.0&format=json&callback=jQuery1720724027235122559_1542743885014&_=15'
res = requests.get(url)
soup = BeautifulSoup(res.content, "lxml")
s = soup.select('html')[0].text.strip('jQuery1720724027235122559_1542743885014(').strip(')')
s = s.replace('null','"placeholder"')
data= json.loads(s)
data = json_normalize(data)
df = pd.DataFrame(data)
print(df)

【讨论】:

以上是关于pandas read_html ValueError:未找到表的主要内容,如果未能解决你的问题,请参考以下文章

Pandas pd.read_html() 函数给了我“HTTP 错误 403:禁止”

使用 Pandas 的问题 read_html

Pandas read_html 返回原始 HTML 内容 [对于某些行/单元格/等]

pandas read_html ValueError:未找到表

使用 pandas read_html 抓取时将表行分隔为 2

pandas读写结构化数据(read_csv,read_table, read_excel, read_html, read_sql)