python pd.read_html给出错误

时间:2017-08-27 14:26:38

标签: python pandas web-scraping

我一直在使用pandas并请求提取一些表来获取NFL统计数据。它一直很顺利,我已经能够从其他网站拉桌子,直到我试图从这个特定网站获得NFL组合表。

它在df_list = pd.read_html(html)

之后给出了错误消息

我得到的错误是:

TypeError: ufunc 'add' did not contain a loop with signature matching types dtype('<U1') dtype('<U1') dtype('<U1')

以下是我在其他网站上使用的代码,这些代码效果非常好。

import requests
import pandas as pd
df = pd.DataFrame()

url = 'http://nflcombineresults.com/nflcombinedata_expanded.php?
       year=1987&pos=&college='
html = requests.get(url).content
df_list = pd.read_html(html)
df = df_list[-1]

我已经阅读并看到了一些关于BeautifulSoup的内容,但pd.read_html()的简洁性非常好而且紧凑。所以我不知道是否有一个我不知道的快速修复,或者我是否需要在1987年至2017年期间深入了解BeautifulSoup来获取这些表格。

2 个答案:

答案 0 :(得分:1)

这不短,但可能更强大:

import requests
import pandas as pd
from bs4 import BeautifulSoup

便利功能:

def souptable(table):
    for row in table.find_all('tr'):
        yield [col.text for col in row.find_all('td')]

返回一个DataFrame,其中包含为给定年份加载的数据:

def getyear(year):
    url = 'http://nflcombineresults.com/nflcombinedata_expanded.php?year=%d&pos=&college=' % year
    r = requests.get(url)
    soup = BeautifulSoup(r.text, 'lxml')
    data = list(souptable(soup.table))
    df = pd.DataFrame(data[1:], columns=data[0])
    df = df[pd.notnull(df['Name'])]
    return df.apply(pd.to_numeric, errors="ignore")

此函数在创建DataFrame时切出标题行,使用第一行作为列名,并过滤掉任何具有空Name值的行。

最后,将所需的多年连接到单个DataFrame中:

dfs = pd.concat([getyear(year) for year in range(1987, 1990)])

答案 1 :(得分:0)

确定。做了一些更多的研究。我看起来问题是最后一行是一个合并的单元格,这可能是问题的来源。所以我确实开始使用BeautifulSoup来提取数据。这是我的解决方案:

import requests
import pandas as pd
from bs4 import BeautifulSoup 

我想从1987年到2017年每年拉一次

seasons = list(range(1987, 2018))
df = pd.DataFrame()
temp_df = pd.DataFrame()

所以它会贯穿每一年。将每个单元格附加到新行。然后再次知道最后一个单元格是&#34;空白&#34;,我通过在数据框循环之前将数据框定义为df[:-1]来消除最后一行,并附加下一年的数据。

for i in seasons:
    df = df[:-1] 
    url = 'http://nflcombineresults.com/nflcombinedata_expanded.php?
       year=%s&pos=&college=' % (i)
    r = requests.get(url) 
    soup = BeautifulSoup(r.text, 'lxml')
    for tr in soup.table.find_all('tr'):
        row = [td.text for td in tr.find_all('td')]
        temp_df = row
        df = df.append(temp_df, ignore_index = True)

最后,由于没有新的一年要追加,我需要消除最后一行。然后我将数据帧重新整形为16列,重命名第一行中的列,然后消除数据帧中的行标题。

df = df[:-1]    
df = (pd.DataFrame(df.values.reshape(-1, 16)))
df.columns = df.iloc[0]
df = df[df.Name != 'Name']

我还在学习python,所以任何意见,建议,任何尊重的建设性批评都会受到欢迎。也许有更好,更合适的解决方案?