Schleife in Schleife

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
Assassin4711
User
Beiträge: 77
Registriert: Mittwoch 8. September 2021, 14:22

Hi Zusammen,

ich habe heute mi meinem esten Programm begonnen. Es soll ein Scraper werden.

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

driver = webdriver.Chrome('C:/webdrivers/chromedriver.exe')

driver.get('https://www.oddsportal.com/matches/tennis/')

driver.maximize_window()

Tomorrow = driver.find_element_by_xpath('//div[@class="center spc"]/span/a[3]')
Tomorrow.click()

# Sort = driver.find_element_by_xpath('//li[@class="tab first"]/a[1]/span')
# Sort.click()


# Web Scraping

Spielort = driver.find_elements_by_xpath('//tr[@class="dark center"]/th[1]/a[2]')
Uhrzeit = driver.find_elements_by_xpath('//tr[@class="odd"]/td[1]')

for s in Spielort:
for u in Uhrzeit:

print(s.text + u.text)

Soweit funktioniert auch alles schonmal. Nur bekommen ich es nicht hin die gesammelten Daten richtig auszugeben.

In einer Tabelle stehen immer zuerst die Spielorte und darunter dann die einzelnen Spiele. Als Output möchte ich also haben

Ort xyz1 , Startzeit 1. Match
Ort xyz1 , Startzeit 2. Match
Ort xyz1 , Startzeit 3. Match
Ort xyz2 , Startzeit 1. Match
Ort xyz2 , Startzeit 2. Match
Ort xyz3 , Startzeit 1. Match
Ort xyz4 , Startzeit 1. Match
Ort xyz4 , Startzeit 2. Match

Ich weiss aus VBA das ich es irgendwie mit einer Schleife hinbekomme. Aber wie mache ich das in python.

Vielen Dank vorab für eure Hilfe
Dirk

P.S.: kann man in diesem Forum erledigte Artikel nicht beenden?
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Sportort und Uhrzeit sind ja nicht unabhängige Listen. Du mußt sie also gemeinsam in einer Abfrage abfragen, also eine for-Schleife die alle Zeilen durchgeht und dann entscheidet, ob ein neuer Spielort oder nur eine neues Match drinsteht.
Variablennamen werden immer komplett klein geschrieben, also `tomorrow`. Einbuchstabige Namen vermeiden, weil sie nichtssagend sind. Wenn Du eine Liste hast, dann wird der Name meist im Plural benutzt, also `spielorte`, dann kann `s` zu `spielort` werden.
Assassin4711
User
Beiträge: 77
Registriert: Mittwoch 8. September 2021, 14:22

Sirius3 hat geschrieben: Freitag 10. September 2021, 06:55 Sportort und Uhrzeit sind ja nicht unabhängige Listen. Du mußt sie also gemeinsam in einer Abfrage abfragen, also eine for-Schleife die alle Zeilen durchgeht und dann entscheidet, ob ein neuer Spielort oder nur eine neues Match drinsteht.
Variablennamen werden immer komplett klein geschrieben, also `tomorrow`. Einbuchstabige Namen vermeiden, weil sie nichtssagend sind. Wenn Du eine Liste hast, dann wird der Name meist im Plural benutzt, also `spielorte`, dann kann `s` zu `spielort` werden.
Danke ich hab jetzt schon durch ein wenig lesen hier im forum mitbekommen dass man wohl gewisse Schreibweisen des Codes einhalten sollte.

Meine Frage jetzt, ich arbeite ja lokalisieren Objekte die manchmal einen Wert und manchmal ganz viele Werte beinhalten. Wie kann ich diese denn dann in einer Schleife abfragen?
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Eine Schleife kann auch nur einmal durchlaufen werden.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@Assassin4711: was meinst Du mit "lokalisieren Objekte" und von welchen Werten redest Du?
Funktionen sollten immer nur einen Typ Rückgabewerte haben, das heißt also, falls es nur einen Wert gibt, ist das eine Liste mit nur einem Eintrag. Die kannst Du dann genauso per for-Schleife verarbeiten.
Assassin4711
User
Beiträge: 77
Registriert: Mittwoch 8. September 2021, 14:22

Na ich lese die Werte arts der Tabelle ja quasi mit dem XPath lokalisator aus. Und lese diese in die 1. Variabel Spielorte ein. Und in der 2. variabel lese ich dann die uhrzeiten ein. Aber eigentlich müsste ich die ja quasi ineinander verschachtelt einlesen. Also Spielort1 und dann alle uhrzeiten in spielort1... Dann spielort2 usw....

In vba könnte man das quasi alles in ein 2 Dimensionales array ablegen.... Da habe ich jetzt aber garkeine Idee wie ich das in python mache...
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Du kannst die Daten nur in der Verschachtelung abfragen, wie sie auch im HTML stehen. Wenn das eine flache Tabelle mit Spielorten und Uhrzeiten ist, dann mußt Du, wie ich schon geschrieben hatte, alles Zeilen der Tabelle abfragen und sie selbst zuordnen.
Die Datenstruktur wäre dann eine Liste von Tuplen aus Spielort und einer Liste mit Uhrzeiten.
Assassin4711
User
Beiträge: 77
Registriert: Mittwoch 8. September 2021, 14:22

Sirius3 hat geschrieben: Freitag 10. September 2021, 10:44 Du kannst die Daten nur in der Verschachtelung abfragen, wie sie auch im HTML stehen. Wenn das eine flache Tabelle mit Spielorten und Uhrzeiten ist, dann mußt Du, wie ich schon geschrieben hatte, alles Zeilen der Tabelle abfragen und sie selbst zuordnen.
Die Datenstruktur wäre dann eine Liste von Tuplen aus Spielort und einer Liste mit Uhrzeiten.
ist das eine flache Tabelle???

https://www.oddsportal.com/matches/tennis/20210910/
Assassin4711
User
Beiträge: 77
Registriert: Mittwoch 8. September 2021, 14:22

So ich habe jetzt mal den ganzen Tag rumgegoogled und auch ein paar Code Schnipsel gefunden:

Code: Alles auswählen

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

timeList = []
cityList = []
gameList = []
home_odds = []
draw_odds = []
away_odds = []

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

result = pd.DataFrame({'city':dateList,
                       'time':timeList,
                       'game':gameList,
                       'Home':home_odds,
                       'Draw':draw_odds,
                       'Away':away_odds})
print(result)
Das Ergebnis ist aber leider noch nicht ganz wie gewünscht:

city \
0 USA»ATP US Open (hard)
1 Bulgaria»ITF W15 Varna Women (clay)
2 Bulgaria»ITF W15 Varna Women (clay)
3 Bulgaria»ITF W15 Varna Women (clay)
4 Belgium»ITF M25 Eupen Men (clay)
.. ...
108 USA»ATP US Open (hard)
109 USA»US Open Mixed Doubles (hard)
110 Colombia»ITF M15 Ibague Men Doubles (clay)
111 Colombia»ITF M15 Ibague Men Doubles (clay)
112 USA»ATP US Open (hard)

time \
0 Raducanu E. - Sakkari M.
1 Terziyska J. - Cisovska R.
2 Craciun G. A. - Bojovic J.
3 Matoula M. - Mishina D.
4 Fery A. - Faucon R.
.. ...
108 Auger-Aliassime F. - Medvedev D.
109 Pegula J./Krajicek A. - Krawczyk D./Salisbury J.
110 Gomez J. S./Hernandez J. A. - Gomez A./Hoyos F...
111 Arias B./Dellien Velasco M. A. - Boscardin Dia...
112 Djokovic N. - Zverev A.





game \
0 Raducanu E. - Sakkari M.
1 Terziyska J. - Cisovska R.
2 Craciun G. A. - Bojovic J.
3 Matoula M. - Mishina D.
4 Fery A. - Faucon R.
.. ...
108 Auger-Aliassime F. - Medvedev D.
109 Pegula J./Krajicek A. - Krawczyk D./Salisbury J.
110 Gomez J. S./Hernandez J. A. - Gomez A./Hoyos F...
111 Arias B./Dellien Velasco M. A. - Boscardin Dia...
112 Djokovic N. - Zverev A.

Home Draw Away
0 2:0 2.33 1.64
1 2:0 1.49 2.49
2 0:2 1.32 3.20
3 1:2 2.59 1.44
4 2:0 1.14 5.27
.. ... ... ...
108 Auger-Aliassime F. - Medvedev D. 5.58 1.17
109 Pegula J./Krajicek A. - Krawczyk D./Salisbury J. 2.20 1.65
110 Gomez J. S./Hernandez J. A. - Gomez A./Hoyos F... 2.07 1.66
111 Arias B./Dellien Velasco M. A. - Boscardin Dia... 1.92 1.77
112 Djokovic N. - Zverev A. 1.41 3.07

[113 rows x 6 columns]


Irgendwo scheine ich da noch einen Fehler zu haben. Der Output soll so aussehen:

city / time / game / home / draw / away

Diesen Part verstehe ich hier nicht:

for row in df.itertuples():
if not isinstance(row[1], str):
continue
elif ':' not in row[1]:
city = row[1].split('-')[0]
continue

Was wird hier gemacht bzw. was muss ich ändern?
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Warum machst Du es nicht so, wie ich es Dir geraten habe?
Man schaut sich nicht ohne Not den Typ einer Variable an, oder hofft darauf, dass die Daten irgendwelche Zeichen NICHT enthalten.
Als erstes suchst Du alle <tr>-Elemente, die innerhalb der <table> innerhalb des <div> mit der id="table.matches" sind.
Die Unterscheidung, ob sich um einen Ort handelt oder nicht, entscheidet sich anhand der Klasse `dark`.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Das sollte dann ungefähr so aussehen:

Code: Alles auswählen

rows = driver.find_elements_by_css_selector('div#table-matches > table > tbody > tr')

data = []
place = "unknown"
for row in rows:
    if "dark" in row.get_attribute('class').split():
        place = row.find_element_by_css_selector('th:first-child > a:last-child').text
    else:
        data.append([place] + [td.text for td in row.find_elements_by_css_selector('td')])
Assassin4711
User
Beiträge: 77
Registriert: Mittwoch 8. September 2021, 14:22

puh das sieht schonmal gar nicht so schlecht aus .... DANKE

kannst du mir die Zeilen ggfs. mal ein wenig erklären, damit ich weiss wie ich das für meine Bedürfnisse umbauen kann ....

zum Beispiel hätte ich jetzt keine Idee wie ich überschriften Hinbekomme damit ich die daten mal in eine csv ablegen kann.
Antworten