Python 3.x - iloc抛出错误 - “单个位置索引器超出范围”

时间:2016-06-22 05:26:19

标签: python indexing dataframe web-scraping

我正在从网站上搜集选举数据并尝试将其存储在数据框中

import pandas as pd
import bs4
import requests

columns = ['Candidate','Party','Criminal Cases','Education','Age','Total Assets','Liabilities']

df = pd.DataFrame(columns = columns)

ind=1

url = requests.get("http://myneta.info/up2007/index.php?action=show_candidates&constituency_id=341")
soup = bs4.BeautifulSoup(url.content)

for content in soup.findAll("td")[16:]:
    df.iloc[ind//7,ind%7-1] = content.text
    ind=ind+1
print(df)

基本上,content.text的每次迭代都会为我提供一个我将在表中填充的值。循环将按以下顺序将值填充到df -

df[0,0]
df[0,1]
df[0,2]
.
.
.
df[1,0]
df[1,1]
.
.

等等。不幸的是,iloc正在抛出一个错误 - “单个位置索引器超出范围”。有趣的是当我在for循环之外尝试df.iloc[0,0] = content.text(在一个单独的单元格中用于测试目的)时,代码正常工作,但在for循环中它会产生错误。我相信这可能是微不足道的,但我无法理解。请帮助

2 个答案:

答案 0 :(得分:13)

DataFrame.iloc无法扩大其目标对象。这曾经是错误消息,但自版本0.15以来已更改。

通常,DataFrame并不意味着一次构建一行。这是非常低效的。相反,您应该创建一个更传统的数据结构并从中填充DataFrame

table = soup.find(id='table1')
rows = table.find_all('tr')[1:]
data = [[cell.text for cell in row.find_all('td')] for row in rows]
df = pd.DataFrame(data=data, columns=columns)

从您的请求中检查页面看来,您在表格后面是id“table1”,其中第一行是标题(该页面的作者选择不当,应该在{{ 1}},而不是身体)。因此,跳过第一行(<thead>),然后从行的单元格构建列表列表。

当然你也可以让pandas担心解析和所有:

[1:]

答案 1 :(得分:0)

这是一种解决方法。我和我的熊猫版本有同样的iloc错误。这个修改过的代码通过在为每个迭代分配值之前创建一个空白记录(通过创建一行数据帧并附加到现有数据帧)来克服它。

import pandas as pd
import bs4
import requests

columns = ['Candidate','Party','Criminal Cases','Education','Age','Total Assets','Liabilities']

df = pd.DataFrame(columns = columns)

ind=1
url = requests.get("http://myneta.info/up2007/index.php?action=show_candidates&constituency_id=341")
soup = bs4.BeautifulSoup(url.content)

for content in soup.findAll("td")[16:]:
    data = pd.DataFrame({columns[0]:"",
                     columns[1]:"",
                     columns[2]:"",
                     columns[3]:"",
                     columns[4]:"",
                     columns[5]:"",
                     columns[6]:"",
                    },index=[0])
    df=df.append(data,,ignore_index=True)
    df.iloc[ind//7,ind%7-1] = content.text
    ind=ind+1