web-dev-qa-db-fra.com

Python 3.x - iloc génère une erreur: "l'indexeur de position unique est hors limites"

Je suis en train d'extraire des données électorales d'un site Web et j'essaie de les stocker dans une base de données. 

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)

Chaque itération de content.text me fournira essentiellement une valeur que je vais renseigner dans le tableau. La boucle va renseigner les valeurs sur df dans l’ordre suivant - 

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

etc. Malheureusement, iloc a généré une erreur: "l'indexeur de position unique est interdit". La partie amusante est que lorsque j'essaie df.iloc[0,0] = content.text en dehors de la boucle for (dans une cellule distincte à des fins de test), le code fonctionne correctement, mais dans la boucle for, cela crée une erreur. Je crois que cela pourrait être quelque chose de trivial, mais je suis incapable de comprendre.Veuillez aider

6
Rohan Bapat

DataFrame.iloc ne peut pas agrandir son objet cible. C'était le message d'erreur, mais a changé depuis la version 0.15.

En général, une DataFrame n'est pas conçue pour être construite ligne à la fois. C'est très inefficace. Au lieu de cela, vous devriez créer une structure de données plus traditionnelle et y renseigner une 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)

En examinant la page dans votre demande, il semble que vous vous trouviez derrière la table avec l'id "table1", qui a pour première rangée l'en-tête (un mauvais choix des auteurs de cette page, aurait dû être en <thead>, pas le corps ). Donc, ignorez la première ligne ([1:]) puis construisez une liste de listes à partir des cellules des lignes.

Bien sûr, vous pouvez également laisser les pandas s’inquiéter de l’analyse syntaxique et ainsi de suite:

url = "http://myneta.info/up2007/index.php?action=show_candidates&constituency_id=341"
df = pd.read_html(url, header=0)[2]  # Pick the 3rd table in the page
13
Ilja Everilä

C'est une solution de contournement. Je reçois la même erreur iloc avec ma version de pandas. Ce code modifié le surmonte en créant un enregistrement vide (en créant un cadre de données d'une ligne et en ajoutant à un existant) à chaque itération avant de leur affecter des valeurs.

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
0
user3404344