WebScapper mit Loop

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
Franio
User
Beiträge: 4
Registriert: Mittwoch 7. Dezember 2022, 12:25

Hallöchen liebes Forum,

ich habe ein kleinen web scraper geschrieben, der Standorte von einer Filiale in eine excel-tabelle abspeichert.
Dafür wird einfach auf einer Internetseite , die Postleidzahl eingegeben.
Da es sehr mühselig ist jede Postleidzahl aus Deutschland immer wieder eingeben zu lassen wollte ich eine schleife schreiben die das ganze "Programm",
immer wieder mit einer neuen Postleidzahl auszuführen oder die zu ändern.

Vorab, ich bin kein Profi und arbeite seid einigen Wochen erst mit Python.
Ich habe mir das alles einfach so zusammen gebastelt, kann natürlich sein das ich zu schwer denke oder sowas.

Hat da jemand eine Idee ?

Danke schonmal.

Code: Alles auswählen

from tqdm import tqdm

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.action_chains import ActionChains
import time
import pandas as pd
import xlsxwriter
import os
import sys
import subprocess




S = Service("C:\Program Files (x86)\chromedriver.exe")

chromeOptions = Options()
chromeOptions.headless = False



Post_Zahl = input("Postleidzahl: ")
ExselName = input("DateiName: ") + ".xlsx"

for i in tqdm (range (147),  
               desc="Loading…",  
               ascii=False, ncols=75): 
    time.sleep(0.01) 
      
print("Bot starten.") 



driver = webdriver.Chrome(service=S, options=chromeOptions)
driver.maximize_window()

driver.get(".........") 

time.sleep(2)


x = driver.find_element(by=By.XPATH, value= "//button[@id='onetrust-accept-btn-handler']")
x.send_keys(Keys.ENTER)
#//button[@id='onetrust-accept-btn-handler']

time.sleep(1)

y = driver.find_element(by=By.XPATH, value= "//button[@id='btn-entry-age-allow']")
y.send_keys(Keys.ENTER)

z = driver.find_element(by=By.CLASS_NAME, value= "mapboxgl-ctrl-geocoder--input")



actionChains = ActionChains(driver)
actionChains.double_click(z).perform()

time.sleep(1)

z.send_keys(Keys.DELETE)

v = driver.find_element(by=By.CLASS_NAME, value= "mapboxgl-ctrl-geocoder--input")



actionChains = ActionChains(driver)
actionChains.double_click(v).perform()

time.sleep(1)


v.send_keys(Keys.DELETE)

z_1= driver.find_element(by=By.CLASS_NAME, value= "mapboxgl-ctrl-geocoder--input")

actionChains = ActionChains(driver)
actionChains.double_click(z_1).perform()

time.sleep(1)


z_1.send_keys(Keys.DELETE)

z_2= driver.find_element(by=By.CLASS_NAME, value= "mapboxgl-ctrl-geocoder--input")

actionChains = ActionChains(driver)
actionChains.double_click(z_2).perform()

time.sleep(1)

z_2.send_keys(Keys.DELETE)

z_3= driver.find_element(by=By.CLASS_NAME, value= "mapboxgl-ctrl-geocoder--input")

actionChains = ActionChains(driver)
actionChains.double_click(z_3).perform()

time.sleep(1)

z_3.send_keys(Post_Zahl)

z_4= driver.find_element(by=By.CLASS_NAME, value= "mapboxgl-ctrl-geocoder--input")

time.sleep(1)

z_4.send_keys(Keys.ENTER)

#Locaters


time.sleep(5)



Heandler_Name = driver.find_elements(by=By.XPATH, value= "//div[@class='store-search-results']/ul/li//div[@class='item name']/span")



Heanlder_Adresse = driver.find_elements(by=By.XPATH, value= "//div[@class='store-search-results']/ul/li//div[1][@class='item adress-text']/span[1]") 


    



df_HeandlerListe = pd.DataFrame(columns=['Name', 'Adresse'])

df_HeandlerListe

for i in range(len(Heandler_Name)):

   df_HeandlerListe = df_HeandlerListe.append({'Name': Heandler_Name[i].text, 'Adresse': Heanlder_Adresse[i].text}, ignore_index=True)

df_HeandlerListe   


df_HeandlerListe.to_excel(ExselName, index = False)

driver.close()


print("Fertig")
time.sleep(2)
subprocess.call([sys.executable, os.path.realpath(__file__)] + sys.argv[1:])

Benutzeravatar
__blackjack__
User
Beiträge: 13061
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Franio: Ich vermisse da ja irgendwie eine konkrete Frage. Du willst eine Schleife schreiben — dann schreib eine Schleife. Was ist das konkrete Problem dabei?

Anmerkungen zum Quelltext: Auf Modulebene sollte nur Code stehen, der Konstanten, Funktionen, und Klassen definiert. Das Hauptrogramm steht üblicherweise in einer Funktion die `main()` heisst. Wobei das auch alles zu lang und unstrukturiert ist, für nur eine Funktion.

Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassennamen (PascalCase).

Namen sollten keine kryptischen Abkürzungen enthalten, oder gar nur daraus bestehen. `S` solle beispielsweise `service` heissen, und `x`, `y`, und `z` sind passende Namen für Koordinaten, aber nicht für Elemente auf Webseiten. Man muss auch nicht jedes Zwischenergebnis an einen Namen binden.

14,7 Sekunden sinnlose Wartezeit am Anfang eines Programms braucht kein Mensch.

Wenn man ein Container-Objekt oder etwas iterierbares hat, benennt man das nicht in der Einzahl. `Heandler_Name` (sic) steht hier ja nicht für *einen* Händlernamen, sondern für mehrere, dementsprechend sollte das auch `heandlernamen` heissen.

Ist das tatsächlich notwendig, dass das Element mit der CSS-Klasse "mapboxgl-ctrl-geocoder--input" immer wieder neu gesucht werden muss? Letztlich wird da viermal das gleiche gemacht und das immer wieder als Code dort hingeschrieben. Das macht man nicht, dafür gibt es Schleifen.

``for i in range(len(sequenz))`` nur im `i` dann als Index in die Sequenz zu verwenden ist in Python ein „anti-pattern“ weil man direkt über die Elemente von Sequenzen iterieren kann, ohne den Umweg über einen Laufindex. Wenn man über mehrer eDatenstrukturen ”parallel” iterieren möchte, gibt es die `zip()`-Funktion. Aber a) braucht man das hier nicht, weil sich ein `DataFrame` auch aus mehreren Listen erstellen lässt, allerdings sollte man eigentlich auch gar nicht solche ”parallelen” Listen erstellen, weil das fehleranfällig ist wenn man zusammengehörende Informationen in verschiedenen Listen speichert, statt beispielsweise eine Liste mit Tupeln zu erstellen, die die zusammengehörenden Daten enthalten. Und die sollte man bereits so ermitteln. Also zwei Schritten: erst die HTML-Elemente selectieren die jeweils beide Informationen enthalten, und dann *daraus* die beiden Teilinformatione Name und Adresse ermitteln.

Das sich das am Ende per `subrocess` immer wieder selbst aufruft, ist eine ganz schlechte Idee. Warum ist das nicht einfach eine ``while``-Schleife?

Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python3
import time

import pandas as pd
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys

URL = "…"


def main():
    while True:
        postleitzahl = input("Postleitzahl: ")
        exceldateiname = input("Dateiname: ") + ".xlsx"

        print("Bot starten.")
        options = Options()
        options.headless = False
        with webdriver.Chrome(
            service=Service(R"C:\Program Files (x86)\chromedriver.exe"),
            options=options,
        ) as driver:
            driver.maximize_window()
            driver.get(URL)
            time.sleep(2)

            for xpath in [
                "//button[@id='onetrust-accept-btn-handler']",
                "//button[@id='btn-entry-age-allow']",
            ]:
                driver.find_element(by=By.XPATH, value=xpath).send_keys(
                    Keys.ENTER
                )

            geocoder_input = driver.find_element(
                by=By.CLASS_NAME, value="mapboxgl-ctrl-geocoder--input"
            )
            for _ in range(4):
                ActionChains(driver).double_click(geocoder_input).perform()
                time.sleep(1)
                geocoder_input.send_keys(Keys.DELETE)

            ActionChains(driver).double_click(geocoder_input).perform()
            time.sleep(1)
            geocoder_input.send_keys(postleitzahl)
            time.sleep(1)
            geocoder_input.send_keys(Keys.ENTER)

            time.sleep(5)
            xpath = "//div[@class='store-search-results']/ul/li/"
            haendlernamen = [
                element.text
                for element in driver.find_elements(
                    by=By.XPATH,
                    value=f"{xpath}/div[@class='item name']/span",
                )
            ]
            haendleradressen = [
                element.text
                for element in driver.find_elements(
                    by=By.XPATH,
                    value=f"{xpath}/div[1][@class='item adress-text']/span[1]",
                )
            ]

        pd.DataFrame(
            {"Name": haendlernamen, "Adresse": haendleradressen}
        ).to_excel(exceldateiname, index=False)

        print("Fertig")
        time.sleep(2)


if __name__ == "__main__":
    main()
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Franio
User
Beiträge: 4
Registriert: Mittwoch 7. Dezember 2022, 12:25

@__blackjack__

WOW, erstmal herzlichen dank für die ganzen Verbesserungsvorschläge.
Wenn ich dein Code mit meinem Code vergleiche sind das Welten...

Sorry falls ich meine Frage nicht richtig gestellt habe.
in Zeile 17 "postleitzahl = input("Postleitzahl: ")"

Muss ich ja immer wieder die Postleidzahl Händisch eingeben.
Gibt es da einen weg das ich input ersetze und das dort eine 1000 Steht und beim nächsten lauf in der schleife dann eine 1001 und beim dritten lauf eine 1002 und immer so weiter ?

Danke dir der Code sieht wegen dir schon viel besser aus.
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

@Franio: wie man eine Schleife programmiert, sind ganz fundamentale Grundlagen. Zum Beispiel so:

Code: Alles auswählen

for i in range(18, 29):
    print(i)
Franio
User
Beiträge: 4
Registriert: Mittwoch 7. Dezember 2022, 12:25

Hab ihr dazu ein schleife die dafür funktionieren würde.
Es soll nicht so rüber kommen als hätte ich keine lust, ich habe 3 stunden damit verbracht das jetzt hin zu kriegen.
Ohne Erfolg.

Wäre seht nett ich kenne sonst niemanden der mir dabei helfen könnte.
MfG
Benutzeravatar
sparrow
User
Beiträge: 4183
Registriert: Freitag 17. April 2009, 10:28

Die for-Schleife aus Sirius3 letztem Beitrag ist das Mittel der Wahl. Sie steht also schon da.
Die ausfürhliche Erklärung steht im offiziellen Tutorial.

Ich bin auch etwas verwirrt, weil du for-Schleifen ja bereits in deinem Code benutzt.
Franio
User
Beiträge: 4
Registriert: Mittwoch 7. Dezember 2022, 12:25

Die schleife die geschrieben worden ist war von @__blackjack__
Ich dachte nicht das, dass ganze so schwer ist
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

Ob etwas schwer ist, hängt auch vom jeweiligen Kenntnisstand ab. Wenn es für Dich zu schwer ist, dann mußt Du nochmal ein paar Schritte zurück gehen und mit Hilfe eines Python-Tutorials Dir die Grundlagen aneignen.
In Deinem eigenen Code sind auch schon zwei for-Schleifen.
Antworten