Fehlermeldung IndexError: list index out of range

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
wovo42
User
Beiträge: 4
Registriert: Sonntag 12. Mai 2019, 01:41

Hallo und Guten Tag, liebes Forum,
bin neu hier und habe ein Problem, mit dem ich ganz und gar nicht klar komme:

Folgendes Jupyter Notebook, welches auch sehr gut funktioniert:

from datetime import datetime
import bs4
import requests
from bs4 import BeautifulSoup

def parsePrice():
r=requests.get('https://finance.yahoo.com/quote/ALV.SG?p=ALV.SG')
soup=bs4.BeautifulSoup(r.text,"xml")
price=soup.find_all('div',{'class':'My(6px) Pos(r) smartphone_Mt(6px)'})[0].find('span').text
return price

while True:
print('the current price: '+str(parsePrice()))
rst = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
with open("verbrauch2.csv", "a") as f:
f.write('ALV.SG'+','+rst+','+parsePrice()+'\n')

Nach ca 1000 - 1200 Durchgängen dann Abbruch mit folgender Fehlermeldung:

...
the current price: 200.30
the current price: 200.30
the current price: 200.30
the current price: 200.30

---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
<ipython-input-21-ef7611d30e04> in <module>
6
7 while True:
----> 8 print('the current price: '+str(parsePrice()))
9 rst = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
10 with open("verbrauch2.csv", "a") as f:

<ipython-input-21-ef7611d30e04> in parsePrice()
2 r=requests.get('https://finance.yahoo.com/quote/ALV.SG?p=ALV.SG')
3 soup=bs4.BeautifulSoup(r.text,"xml")
----> 4 price=soup.find_all('div',{'class':'My(6px) Pos(r) smartphone_Mt(6px)'})[0].find('span').text
5 return price
6

IndexError: list index out of range

wo baut sich welche Liste auf ?
wo wird ein Index erstellt, den ich kontrollieren kann ?

Für jede Hilfe oder auch Tipps bin ich sehr dankbar

wovo42
__deets__
User
Beiträge: 14539
Registriert: Mittwoch 14. Oktober 2015, 14:29

Na an der einzigen Stelle, wo ein Index Zugriff stattfindet: [0]

Das findAll kehrt wohl leer zurück. Musst du dich halt gegen wappne.
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

Wenn Du den Fehler in der Zeile nicht verstehst, dann teile die, sowieso viel zu lange Zeile, in mehrere auf, und versuche zu verstehen, was jedes Teil tut.
Benutzeravatar
__blackjack__
User
Beiträge: 13103
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@wovo42: Anmerkungen zum Quelltext:

Es wird das Modul `bs4` importiert und dann zusätzlich noch einmal `BeautifulSoup` aus diesem Modul. Letzteres wird dann im weiteren Verlauf aber gar nicht verwendet, der Import kann also wegfallen.

Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (MixedCase). Also `parse_price()` statt `parsePrice()`.

Einbuchstabige Namen sind selten gut. Mit `r` und `f` sind wohl `response` und mit `file` gemeint.

Nicht viel besser sind Abkürzungen. Namen sollen dem Leser verraten was der Wert dahinter bedeutet und nicht zum raten animieren was `rst` denn wohl bedeuten mag.

Leerzeichen um Zuweisungen ausserhalb von Argumentlisten, um binäre Operatoren, und nach Kommas erhöhen die Lesbarkeit.

Werte und Zeichenkettenliterale mit ``+`` und `str()` zusammenstückeln ist eher BASIC als Python. In Python gibt es dafür Zeichenkettenformatierung mit der `format()`-Methode auf Zeichenketten oder ab Python 3.6 f-Zeichenkettenliterale.

`strftime()` kann man sich dann auch sparen, weil man das Format beim Platzhalter in der Zeichenkette angeben kann.

Du fragst den aktuellen Preis *zweimal* pro Schleifendurchlauf ab – einmal um ihn mit `print()` auszugeben und einmal um ihn in die Datei zu schreiben. Eine Abfrage für beides würde ausreichen.

Und Du machst das ganze in einer Endlosschleife so schnell der Rechner und die Internetleitung das erlauben – ich vermute mal ganz stark diese Unverschämtheit lässt sich Yahoo nicht bieten, weshalb dann auch der Preis nicht mehr gefunden werden kann. Grundsätzlich ist die Frage ob es erlaubt ist die Seite automatisiert auszuwerten. Üblicherweise nicht.

Man sollte Code oder Daten nicht wiederholen – das verletzt das DRY-Prinzip („Don't Repeat Yourself“). Das Aktiensymbol sollte nicht zwei mal im Code stehen.

Die `parse_price()`-Funktion macht deutlich mehr als nur zu parsen. Auf der anderen Seite parst sie den Preis nicht wirklich, denn dann würde sie eine Zahl zurückgeben und keine Zeichenkette. `get_price()` wäre ein passenderer Name.

Die Antwort vom `request.get()` wird nicht auf den HTTP-Status geprüft.

Yahoo liefert da HTML5 aus – das als XML zu parsen ist mindestens fragwürdig. Kann es sein, dass Du ein 'l' vergessen hast?

An CSS-Klassen wie `My(6px)`, `Pos(r)`, und `smartphone_Mt(6px)`, die sehr generiert und so gar nicht semantisch aussehen, sollte man sich eher nicht orientieren. Semantisch wirkende IDs sind gut, und zur Not dann die Struktur - was Du letztlich neben diesen Klassen ja auch machst. Zum Beispiel das zweite <span> innerhalb des <div> mit der ID `quote-header-info` sieht robuster aus als Klassen in denen Pixelwerte im Namen stehen.

Code: Alles auswählen

from datetime import datetime

import bs4
import requests


def get_price(symbol):
    response = requests.get(f'https://finance.yahoo.com/quote/{symbol}')
    response.raise_for_status()
    soup = bs4.BeautifulSoup(response.text, 'lxml')
    try:
        return soup.find('div', id='quote-header-info')('span')[1].text
    except (TypeError, IndexError):
        raise ValueError('cannot find price')


# 
# FIXME Hammering Yahoo in a tight, busy loop isn't going to work.
# 
symbol = 'ALV.SG'
while True:
    now = datetime.now()
    price = get_price(symbol)
    print('the current price:', price)
    with open('verbrauch2.csv', 'a') as file:
        file.write(f'{symbol},{now:%Y-%m-%d %H:%M:%S},{price}\n')
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
wovo42
User
Beiträge: 4
Registriert: Sonntag 12. Mai 2019, 01:41

Hallo Sirius3,

vielen Dank für Deine spontane Bereitschaft zu helfen! Wie meinst Du das mit "Zeile zerlegen" ? Zeig mir das, wie Du da rangehen würdest ( ich will lernen !!! und weiterkommen !!! jeder Ansatz ist wertvoll )

Danke

wovo42
wovo42
User
Beiträge: 4
Registriert: Sonntag 12. Mai 2019, 01:41

Hallo __deets__ !

Auch Dir vielen Dank für die spontane Antwort ! Hat mir gezeigt: Alte Regel: Denke erst einmal nach ( ich meine mich ! ! !) bevor du rumlaberst. Mir war einfach nicht klar, dass das Körbchen, sprich die Liste 'parsePrice' , auch einmal leer sein könnte ( warum auch immer - zweites Problem !). Habe versucht eine bool() Prüfung einzubauen - bisher allerdings ohne Erfolg. Skript bricht weiterhin ab. Ich bleibe dran.

Vielen Dank

wovo42
wovo42
User
Beiträge: 4
Registriert: Sonntag 12. Mai 2019, 01:41

Hallo __blackjack__ !

Vielen, vielen Dank für die 'Privatvorlesung' .

1. Es gibt noch so viel zu lesen und zu lernen bevor man ein bestenfalls durchschnittlicher eher ' nicht so guter ' Python Anwender ist. Schlimm nur: Das kleine Skript wurde auf Youtube entwickelt von jemandem ( Firmenmitglied ) der damit sein Geld verdient. Inspiration holen ja, blindwütiges ( und tumbes ) Abschreiben nein.

2. Mir ist mit Sicherheit nicht wohl dabei, Yahoo derart mit traffic zu belästigen. Werde das auch so nicht weiter betreiben. Als Alternative fällt mir ein legitimes Mithorchen der Datenströme mittels 'wireshark' und co ein, was für meinen Erkenntnisstand und jetzigen Programmierkenntnisse mindestens 5,72 Nummern zu hoch ist, who knows ....

3. Ich werde Deine Vorlesung Punkt - für - Punkt durcharbeiten und beherzigen, damit die ganze Aktion wenigstens einen Sinn hatte ...
Denn eins will ich sicher: Wenigstens ein durchschnittlicher bis guter Pythonanwender werden

PS: Das Skript hat schon wieder abgebrochen ... Werde das versuchen zu erforschen.

the current price: 200.30
the current price: 200.30
the current price: 200.30

---------------------------------------------------------------------------
HTTPError Traceback (most recent call last)
<ipython-input-2-54d42db2d41f> in <module>
21 while True:
22 now = datetime.now()
---> 23 price = get_price(symbol)
24 print('the current price:', price)
25 with open('verbrauch2.csv', 'a') as file:

<ipython-input-2-54d42db2d41f> in get_price(symbol)
7 def get_price(symbol):
8 response = requests.get(f'https://finance.yahoo.com/quote/{symbol}')
----> 9 response.raise_for_status()
10 soup = bs4.BeautifulSoup(response.text, 'lxml')
11 try:

~\Anaconda3\lib\site-packages\requests\models.py in raise_for_status(self)
938
939 if http_error_msg:
--> 940 raise HTTPError(http_error_msg, response=self)
941
942 def close(self):

HTTPError: 503 Server Error: Service Unavailable for url: https://finance.yahoo.com/quote/ALV.SG
Benutzeravatar
__blackjack__
User
Beiträge: 13103
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@wovo42: Ich gehe einfach mal davon aus das Yahoo sich das nicht gefallen lässt das Du ohne Unterbrechung immer und immer wieder die gleiche Seite anforderst.

Wie Du das mit Wireshark beheben willst ist mir nicht so ganz klar. Du müsstest halt als erstes mal eine Pause einbauen nach jedem herunterladen und schauen ob es dann besser wird.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Antworten