Fehler bei Abfrage (Tuples)

mit matplotlib, NumPy, pandas, SciPy, SymPy und weiteren mathematischen Programmbibliotheken.
Assassin4711
User
Beiträge: 77
Registriert: Mittwoch 8. September 2021, 14:22

Hi Zusammen,

folgenden Code benutze ich um eine Tabelle auf der Seite "Oddsportal" auszulesen:

https://www.oddsportal.com/matches/tennis/

Code: Alles auswählen

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import pandas as pd

browser = webdriver.Chrome()
browser.get("https://www.oddsportal.com/matches/tennis/")

timeList = []
locationList = []
gameList = []
result = []
home_odds = []
away_odds = []
bookies = []

for row in df.itertuples():
    if not isinstance(row[1], str):
        continue
    elif ':' not in row[1]:
        location = row[1].split('-')[0]
        continue
    locationList.append(location)
    timeList.append(row[1])
    gameList.append(row[3])
    result.append(row[4])
    home_odds.append(row[5])
    away_odds.append(row[6])
    bookies.append(row[7])

result = pd.DataFrame({'Location':locationList,
                       'Time':timeList,
                       'Game':gameList,
                       'Result':result,
                       'Home':home_odds,
                       'Away':away_odds,
                      'Bookies':bookies})

print(result)
Aber wieso auch immer erhalte ich diesen Fehler:

Code: Alles auswählen

---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_19500/1404744629.py in <module>
      5         location = row[1].split('-')[0]
      6         continue
----> 7     locationList.append(location)
      8     timeList.append(row[1])
      9     gameList.append(row[3])

NameError: name 'location' is not defined
Kann mir einer sagen was ich hier genau falsch gemacht habe?

Viele Grüße und DANKE
Dirk
Benutzeravatar
pillmuncher
User
Beiträge: 1482
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

Wo glaubst du denn wird location bei dir im Code definiert? Wird die Stelle immer erreicht?
In specifications, Murphy's Law supersedes Ohm's.
Assassin4711
User
Beiträge: 77
Registriert: Mittwoch 8. September 2021, 14:22

pillmuncher hat geschrieben: Samstag 11. September 2021, 08:59 Wo glaubst du denn wird location bei dir im Code definiert? Wird die Stelle immer erreicht?
Ich denke wenn das if not greift wird location nicht definiert. Aber wie kann ich es da auch definieren mit location = "" geht es nicht.
Assassin4711
User
Beiträge: 77
Registriert: Mittwoch 8. September 2021, 14:22

Code: Alles auswählen

ich verstehe es einfach nicht .... wieso bekomme ich ein ergebnis wenn ich die location in date umändere wie es bei dem Ursprungscode war?

[code]
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import pandas as pd

browser = webdriver.Chrome('C:\webdrivers\Chromedriver.exe')
browser.get("https://www.oddsportal.com/matches/tennis/")

df= pd.read_html(browser.page_source, header=0)[0]

timeList = []
dateList = []
gameList = []
home_odds = []
#draw_odds = []
away_odds = []
countBookies = []

for row in df.itertuples():
    if not isinstance(row[1], str):
        continue
    elif ':' not in row[1]:
        date = row[1].split('-')[0]
        continue
    dateList.append(date)    
    timeList.append(row[1])
    gameList.append(row[2])
    home_odds.append(row[5])
    #draw_odds.append(row[5])
    away_odds.append(row[6])
    countBookies.append(row[7])

result = pd.DataFrame({'location':dateList,
                       'time':timeList,
                       'game':gameList,
                       'Home':home_odds,
                       #'Draw':draw_odds,
                       'Away':away_odds,
                       'Bookies':countBookies})
print(result)
location time \
0 USA»WTA US Open (hard) 07:00
1 Czech Republic»ITF W25 Frydek Mistek Women (clay) 08:00
2 Egypt»ITF M15 Cairo 13 Men (clay) 08:00
3 Egypt»ITF M15 Cairo 13 Men (clay) 08:00
4 Egypt»ITF W15 Cairo 13 Women (clay) 08:00
.. ... ...
57 USA»US Open Mixed Doubles (hard) 17:00
58 Colombia»ITF M15 Ibague Men Doubles (clay) 18:00
59 Colombia»ITF W15 Ibague Women Doubles (clay) 18:00
60 Spain»Seville Challenger Men (clay) 18:00
61 USA»WTA US Open (hard) 20:00

game Home Away Bookies
0 Bojovic J. - Terziyska J. 2.91 1.37 12
1 Udvardy P. - Kolodziejova M. 1.57 2.28 8
2 Gramaticopolo B. - De La Fuente S. 2.62 1.44 12
3 Mora M. - Ragazzi A. 2.46 1.51 10
4 Kovapitukted P. - Alhussein L. 2.15 1.64 12
.. ... ... ... ...
57 Olmos G./Arevalo M. - Krawczyk D./Salisbury J. 2.74 1.43 12
58 Arias B./Dellien Velasco M. A. - Gomez A./Hoyo... 2.23 1.57 6
59 Ccuno R./Torres Murcia M. C. - Rusova A./Samud... 2.24 1.58 8
60 Carballes Baena R. - Martinez P. 2.13 1.69 14
61 Raducanu E. - Fernandez L. A. 1.56 2.53 14

[62 rows x 6 columns]

Und warum bekomme ich nur 32 Zeilen geliefert obwohl es mehr sind ... ich verstehe das nicht ... Kann mir jemand bitte auf die Sprünge helfen. Ich bin nicht wirklich versiert mit python kenne mich nur mit VBA aus ...

Ich verstehe auch nicht wieso das erste Turnier USA WTA US Open ist, es müsste eigentlich Bulgarien sein ...

Bitte bitte helft mir ...
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

@Assassin4711,

bei diesem Code-Ausschnitt ist jetzt "date" nicht definiert.
Das liegt daran, dass du es hier zwar definierst:

Code: Alles auswählen

elif ':' not in row[1]:
        date = row[1].split('-')[0]
        continue
wegen "continue" aber nichts damit machst.

Diese Seite ist sehr dynamisch, wenn du weniger Ergebnisse erhältst als du erwartest, liegt dass sicher daran, dass etwas mit deiner Filterung nicht stimmt.
Assassin4711
User
Beiträge: 77
Registriert: Mittwoch 8. September 2021, 14:22

rogerb hat geschrieben: Samstag 11. September 2021, 11:03 @Assassin4711,

bei diesem Code-Ausschnitt ist jetzt "date" nicht definiert.
Das liegt daran, dass du es hier zwar definierst:

Code: Alles auswählen

elif ':' not in row[1]:
        date = row[1].split('-')[0]
        continue
wegen "continue" aber nichts damit machst.

Diese Seite ist sehr dynamisch, wenn du weniger Ergebnisse erhältst als du erwartest, liegt dass sicher daran, dass etwas mit deiner Filterung nicht stimmt.


Kannst du mir erklären was dieser code hier genau macht?:

Code: Alles auswählen

df= pd.read_html(browser.page_source, header=0)[0]

Code: Alles auswählen

for row in df.itertuples():
    if not isinstance(row[1], str):
        continue
    elif ':' not in row[1]:
        date = row[1].split('-')[0]
        continue
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

@Assassin4711,

pandas.read_html durchsucht den gesamten HTML Code der Seite nach HTML-Tabellen.
https://pandas.pydata.org/docs/referenc ... -read-html
Es gibt davon 8 Stück. Mit dem Index 0 wählst du die erste aus und speicherst sie in ein Pandas Dataframe. Mit header=0 wird die erste Zeile als Kopfzeile definiert.

Mit pandas.itertuples
https://pandas.pydata.org/docs/referenc ... itertuples

iterierst du zeilenweise über diesen Dataframe.
"row" enthält dann immer alle Zellen eine Zeile als Pandas-Tuple.
Die erste if-Anweisung prüft ob die zweite Zelle keinen String enthält. Ist es kein String wird einfach mit der nächsten Tabellen Zeile weitergearbeitet (dafür sorgt continue)
Bei "elif", also wenn die zweite Zelle der Zeile ein String ist, wird geprüft, ob es einen Doppelpunkt in diesem String gibt. Falls ja, wird dieser String an den "-" aufgetrennt und elementweise in eine Liste gepackt. Mit Index [0] speichert man aber nur das erste Element in "date".
Jetzt geht es wegen "continue" einfach mit der nächsten Zeile weiter und was auch immer in "date" steht, kann jetzt in "dateList" gepackt werden.

Da es aber vorkommen kann, dass die Zeile

Code: Alles auswählen

dateList.append(date) 
erreicht wird, ohne dass "date" zuvor definiert wurde, gibt es hier einen Fehler.
Assassin4711
User
Beiträge: 77
Registriert: Mittwoch 8. September 2021, 14:22

rogerb hat geschrieben: Samstag 11. September 2021, 11:46 @Assassin4711,

pandas.read_html durchsucht den gesamten HTML Code der Seite nach HTML-Tabellen.
https://pandas.pydata.org/docs/referenc ... -read-html
Es gibt davon 8 Stück. Mit dem Index 0 wählst du die erste aus und speicherst sie in ein Pandas Dataframe. Mit header=0 wird die erste Zeile als Kopfzeile definiert.

Mit pandas.itertuples
https://pandas.pydata.org/docs/referenc ... itertuples

iterierst du zeilenweise über diesen Dataframe.
"row" enthält dann immer alle Zellen eine Zeile als Pandas-Tuple.
Die erste if-Anweisung prüft ob die zweite Zelle keinen String enthält. Ist es kein String wird einfach mit der nächsten Tabellen Zeile weitergearbeitet (dafür sorgt continue)
Bei "elif", also wenn die zweite Zelle der Zeile ein String ist, wird geprüft, ob es einen Doppelpunkt in diesem String gibt. Falls ja, wird dieser String an den "-" aufgetrennt und elementweise in eine Liste gepackt. Mit Index [0] speichert man aber nur das erste Element in "date".
Jetzt geht es wegen "continue" einfach mit der nächsten Zeile weiter und was auch immer in "date" steht, kann jetzt in "dateList" gepackt werden.

Da es aber vorkommen kann, dass die Zeile

Code: Alles auswählen

dateList.append(date) 
erreicht wird, ohne dass "date" zuvor definiert wurde, gibt es hier einen Fehler.
Ah ich glaube jetzt komme ich langsam dahinter ... elif ist also wie in VBA else if ...

Eine Frage noch: wie kommst du darauf das es 8 html Tabellen auf der Seite gibt? Kann ich das irgendwo sehen?
Assassin4711
User
Beiträge: 77
Registriert: Mittwoch 8. September 2021, 14:22

Oh man jetzt verstehe ich das ... habe mit jetzt einfach mit

Code: Alles auswählen

print(row[1])
Einfach mal anzeigen lassen was er da findet:

07:00
Czech Republic»ITF W25 Frydek Mistek Women (clay)
08:00
Egypt»ITF M15 Cairo 13 Men (clay)
08:00
08:00
Egypt»ITF W15 Cairo 13 Women (clay)
08:00
08:00

Jetzt brauche ich ja nur noch schauen ob es eine Uhrzeit ist oder eben str dann ist es ein Spielort. Das ist ja mal echt angenehm.

Aber warum zeigt er mir bei dem Ergebnis oben nicht den ersten Spielort USA WTA US Open an. Ist es weil er diese erste Zeile als Überschriftenzeile ansieht? Wie kann ich das lösen? Muss ich da was an dieser Zeile ändern und ggfs. mit -1 arbeiten, oder so?

Code: Alles auswählen

df= pd.read_html(browser.page_source, header=0)[0]
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

@Assassin4711,

leider interpretiert "read_html" wohl die "<th>" tags als header. Da die erste Zeile fälschlicherweise "<th>" statt "<td>" Tags verwendet wird die als Header genommen.

Es wäre vielleicht besser, direkt nach "id" und "class" attributen zu suchen. Damit hättest du mehr Kontrolle.
Assassin4711
User
Beiträge: 77
Registriert: Mittwoch 8. September 2021, 14:22

rogerb hat geschrieben: Samstag 11. September 2021, 15:00 @Assassin4711,

leider interpretiert "read_html" wohl die "<th>" tags als header. Da die erste Zeile fälschlicherweise "<th>" statt "<td>" Tags verwendet wird die als Header genommen.

Es wäre vielleicht besser, direkt nach "id" und "class" attributen zu suchen. Damit hättest du mehr Kontrolle.
So habe ich es als erstes versucht. Aber da bin ich garnicht klar gekommen. Hast du da einen Code für mich?
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

@Assassin4711,

dies ist zumindest mal ein Anfang. Es wird zunächst unterschieden ob es Zeile für den Ort oder ein Match ist. Dann werden die einzelnen Zellen in Variablen gespeichert. Aber das kannst du ja nach deinen Bedürfnissen anpassen.

Code: Alles auswählen

from selenium import webdriver


def main():
    browser = webdriver.Chrome('C:\webdrivers\Chromedriver.exe')
    browser.get("https://www.oddsportal.com/matches/tennis/")

    # tabelle mit den Matches
    match_table = browser.find_element_by_id("table-matches")
    rows = match_table.find_elements_by_tag_name("tr")

    for row in rows:
        if "dark" in row.get_attribute("class"):
            # dark: alle Zeilen die den Autragungsort enthalten
            cells = row.find_elements_by_tag_name("th")

            data_field1 = cells[0].text.replace("\n", "").strip()
            data_field2 = cells[1].text.replace("\n", "").strip()
            # usw.

        elif "deactivate" or "odd" in row.get_attribute("class"):
            # deactivate oder odd: alle Zeilen, die ein Match enthalten
            cells = row.find_elements_by_tag_name("th")

            data_field1 = cells[0].text.replace("\n", "").strip()
            data_field2 = cells[1].text.replace("\n", "").strip()
            # usw.


if __name__ == "__main__":
    main()
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@rogerb: `or` macht nicht das, was Du denkst. Auf `odd` solltest Du auch gar nicht testen.

Und warum gibt es jetzt zwei Threads zum selben Thema? viewtopic.php?f=1&t=52959#p393225
Assassin4711
User
Beiträge: 77
Registriert: Mittwoch 8. September 2021, 14:22

ja stimmt ... das waren vom Ursprung her zwei unterschiedliche Themen die jetzt aber irgendwie parallel laufen. Wie kann man denn hier im Forum einen Thread schliessen bzw. als gelöst markieren?
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

Ja, @Assassin4711, da hast du gleich mehrere Leute gleichzeitig ans Arbeiten gebracht :)
Das mit dem "or" stimmt, das hab ich etwas zu schnell geschrieben.

Es gibt halt leider auch Zeilen dir nur "odd" im Klassennamen habe. Daher hab ich das verwendet.
Aber es gibt natürlich viele mehr oder weniger robuste Ansätze.
Wenn dir die Lösung von Sirius geholfen hat, dann mach einfach damit weiter.

Threads Schließen kann und braucht man nicht
Assassin4711
User
Beiträge: 77
Registriert: Mittwoch 8. September 2021, 14:22

rogerb hat geschrieben: Samstag 11. September 2021, 16:51 @Assassin4711,

dies ist zumindest mal ein Anfang. Es wird zunächst unterschieden ob es Zeile für den Ort oder ein Match ist. Dann werden die einzelnen Zellen in Variablen gespeichert. Aber das kannst du ja nach deinen Bedürfnissen anpassen.

Code: Alles auswählen

from selenium import webdriver


def main():
    browser = webdriver.Chrome('C:\webdrivers\Chromedriver.exe')
    browser.get("https://www.oddsportal.com/matches/tennis/")

    # tabelle mit den Matches
    match_table = browser.find_element_by_id("table-matches")
    rows = match_table.find_elements_by_tag_name("tr")

    for row in rows:
        if "dark" in row.get_attribute("class"):
            # dark: alle Zeilen die den Autragungsort enthalten
            cells = row.find_elements_by_tag_name("th")

            data_field1 = cells[0].text.replace("\n", "").strip()
            data_field2 = cells[1].text.replace("\n", "").strip()
            # usw.

        elif "deactivate" or "odd" in row.get_attribute("class"):
            # deactivate oder odd: alle Zeilen, die ein Match enthalten
            cells = row.find_elements_by_tag_name("th")

            data_field1 = cells[0].text.replace("\n", "").strip()
            data_field2 = cells[1].text.replace("\n", "").strip()
            # usw.


if __name__ == "__main__":
    main()
Assassin4711
User
Beiträge: 77
Registriert: Mittwoch 8. September 2021, 14:22

eh wo ist mein Text hin ...

Frage /n ist ein Zeilenumbruch?

Und zweite Frage, wie kann ich die Zeile mit der Uhrzeit und den Spielen ansprechen? Ich habe es so probiert, aber das geht leider nicht:

Code: Alles auswählen

        elif "table-time" in row.get_attribute("class"):
            cells = row.find_elements_by_tag_name("tr")
Assassin4711
User
Beiträge: 77
Registriert: Mittwoch 8. September 2021, 14:22

so jetzt dachte ich ich hätte die Lösung gefunden, aber leider gibt es noch einen kleinen Hinkelstein:

Code: Alles auswählen

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import pandas as pd

#def main():
driver = webdriver.Chrome('C:\webdrivers\Chromedriver.exe')
driver.get("https://www.oddsportal.com/matches/tennis/")
    # tabelle mit den Matches
match_table = driver.find_element_by_id("table-matches")
rows = match_table.find_elements_by_tag_name("tr")
    
for row in rows:
        if "dark" in row.get_attribute("class"):
            # dark: alle Zeilen die den Autragungsort enthalten
            cells = row.find_elements_by_tag_name("a")

            data_field1_country = cells[0].text.replace("\n", "").strip()
            data_field2_tournament = cells[1].text.replace("\n", "").strip()
            
            # usw.

        elif not "dark" in row.get_attribute("class"):
            cells = row.find_elements_by_tag_name("td")

            data_field3_time = cells[0].text.replace("\n", "").strip()
            data_field4_player = cells[1].text.replace("\n", "").strip()
            data_field5_homeodd = cells[2].text.replace("\n", "").strip()
            data_field6_awayodd = cells[3].text.replace("\n", "").strip()
  
            print (data_field1_country + ";" + data_field2_tournament + ";" + data_field3_time + ";" \
                   + data_field4_player + ";" + data_field5_homeodd + ";" + data_field6_awayodd)   
Wenn die Spiele live sind erscheint neben der Quote das Live Ergebnis. Und anscheinend wird das dann als neue Spalte angesehen. Bei live Spielen wird dann das Ergebnis als Heim Quote erkannt. Wie kann ich denn den value der Spalte auf z.B. ":" (Ergebnisse haben ja immer dieses Zeichen mit drin) prüfen und in dem Fall dann eine Spalte daneben nehmen?
Assassin4711
User
Beiträge: 77
Registriert: Mittwoch 8. September 2021, 14:22

habe es jetzt so gelöst, vielleicht nicht schön aber es funktioniert erstmal:

Code: Alles auswählen

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import pandas as pd

#def main():
driver = webdriver.Chrome('C:\webdrivers\Chromedriver.exe')
driver.get("https://www.oddsportal.com/matches/tennis/")
    # tabelle mit den Matches
match_table = driver.find_element_by_id("table-matches")
rows = match_table.find_elements_by_tag_name("tr")
    
for row in rows:
        if "dark" in row.get_attribute("class"):
            # dark: alle Zeilen die den Autragungsort enthalten
            cells = row.find_elements_by_tag_name("a")

            data_field1_country = cells[0].text.replace("\n", "").strip()
            data_field2_tournament = cells[1].text.replace("\n", "").strip()
            
            # usw.

        elif not "dark" in row.get_attribute("class"):
            cells = row.find_elements_by_tag_name("td")

            data_field3_time = cells[0].text.replace("\n", "").strip()
            data_field4_player = cells[1].text.replace("\n", "").strip()
            if ":" in cells[2].text.replace("\n", "").strip():
                data_field5_homeodd = cells[3].text.replace("\n", "").strip()
                data_field6_awayodd = cells[4].text.replace("\n", "").strip()
            elif not ":" in cells[2].text.replace("\n", "").strip():
                data_field5_homeodd = cells[2].text.replace("\n", "").strip()
                data_field6_awayodd = cells[3].text.replace("\n", "").strip()
            

            print (data_field1_country + ";" + data_field2_tournament + ";" + data_field3_time + ";" \
                   + data_field4_player + ";" + data_field5_homeodd + ";" + data_field6_awayodd)
 
DANKE euch allen. Werde euch bestimmt bald wieder nerven ...
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Assassin4711: Bei Zeichenkettenliteralen mit Backslashes sollte man entweder alle escapen oder ein ”rohes” Zeichenkettenliteral verwenden.

Den Backslash um logische Zeilen fortzuführen braucht man nur sehr selten. Solange es noch ausstehende schliessende Klammern gibt, wie bei dem `print()`-Aufruf, weiss der Compiler auch so, dass die logische Zeile noch nicht zuende sein kann.

Statt die Zeilen in zwei Schritten über ID und Tag-Namen zu ermitteln, könnte man das auch in *einen* CSS-Selektor stecken.

Statt ``not a in b`` würde man eher ``a not in b`` schreiben. Ersteres sind zwei Operatoren, letzteres nur ein Operator. Jup ``not in`` ist *ein* Operator der aus zwei Schlüsselwörtern besteht.

Aber die Bedingung braucht man nicht, denn da wird ja nur das Gegenteil von dem ``if`` davor geprüft, und dazu braucht man keine explizite Prüfung, da kann man einfach ``else`` verwenden.

Die nummerierten `data_field*`-Präfixe sollten nicht sein.

Ist das ``.replace("\n", "")`` vor jedem ``.strip()`` tatsächlich notwendig/sinnvoll? `strip()` entfernt auch Zeilenendezeichen an beiden Enden. Das `replace()` bringt also nur etwas wenn auch Zeilenendezeichen innerhalb der Zeichenkette vorkommen. Dann ist aber das ersetzen durch eine leere Zeichenkette eventuell keine gute Idee, sondern man möchte da vielleicht eher ein Leerzeichen haben, weil sonst das Ende von der ersten Zeile *direkt* an den Anfang der nächsten Zeile angefügt wird. Aber auf den ersten Blick sehen die Daten nicht aus, als wären da mehrzeilige Texte‽ Auch im Code sieht das eher so aus als wenn das einfach Cargo-Cult-mässig einfach an jeden Zugriff auf `text`-Attribute drangehängt ist, denn um zu prüfen ob ein Doppelpunkt in einem Text enthalten ist, braucht man weder Zeilenendezeichen entfernen, noch Whitespace an den beiden Enden.

Bei dem Test auf ":" ist auch wieder unnötigerweise ein ``elif`` mit genau der gegensätzlichen Bedingung statt einfach einem ``else``.

Die beiden Zweige machen auch nahezu das gleiche, die unterscheiden sich nur durch den Versatz welche beiden Tabellenzellen verwendet werden.

Ich würde den Code so schreiben, dass er nicht in einen `NameError` läuft, wenn nicht zuerst ein Spielort in der Tabelle erkannt wurde.

Zusammenstückeln von Zeichenketten und Werten mit ``+`` ist eher BASIC als Python. In diesem Fall soll die gleiche Zeichenkette zwischen Werte gesetzt werden. Dafür gibt's die `join()`-Methode auf Zeichenketten. Falls das am Ende in einer CSV-Datei landen soll, würde sich das `csv`-Modul aus der Standardbibliothek anbieten. Das kann nämlich auch mit so Sachen wie Trennzeichen *innerhalb* von Zellen korrekt umgehen.

Code: Alles auswählen

#!/usr/bin/env python3
from selenium import webdriver


CHROME_DRIVER = R"C:\webdrivers\Chromedriver.exe"


def iter_stripped_texts(elements, start_index=None, end_index=None):
    return (
        element.text.strip()
        for element in elements[slice(start_index, end_index)]
    )


def main():
    driver = webdriver.Chrome(CHROME_DRIVER)
    driver.get("https://www.oddsportal.com/matches/tennis/")
    country = tournament = None
    for row in driver.find_elements_by_css_selector("#table-matches tr"):
        if "dark" in row.get_attribute("class"):
            # dark: alle Zeilen die den Autragungsort enthalten
            country, tournament = iter_stripped_texts(
                row.find_elements_by_tag_name("a")
            )
        else:
            if country is None:
                raise ValueError(
                    "expected row with country and tournament first."
                )

            cells = row.find_elements_by_tag_name("td")
            time, player = iter_stripped_texts(cells, 0, 2)
            offset = 3 if ":" in cells[2].text else 2
            home_odd, away_odd = iter_stripped_texts(cells, offset, offset + 2)

            print(
                ";".join(
                    [country, tournament, time, player, home_odd, away_odd]
                )
            )


if __name__ == "__main__":
    main()
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Antworten