@Andorso: Anmerkungen zum Quelltext:
Die Importe sollte man mal aufräumen. Also mindestens mal etwas sortieren und unbenutzes entfernen.
`time` wird importiert um daraus `sleep()` aufzurufen, aber `sleep()` wird auch noch mal explizit importiert. Wonach wurde denn entschieden wann welcher Weg gewählt wird? Das sollte vereinheitlicht werden. Ebenso `pyautogui` und was daraus importiert wird.
Namen sollten keine kryptischen Abkürzungen enthalten oder gar nur daraus bestehen. Der Name soll dem Leser vermitteln was der Wert dahinter im Programm bedeutet, nicht zum rätseln zwingen. `structural_similarity()` beim Import als `ssim()` abzukürzen bringt nicht wirklich etwas.
Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.
``global`` hat in einem sauberen Programm nichts zu suchen. Das ist hier ja auch nur ein übler Hack wo man eigentlich einen Rückgabewert verwenden würde. So richtig übel ist auch das viele `find_image()`-Aufrufe diese globale Variable verändern, aber nur ein einziger davon etwas mit einem grünen Stern zu tun hat. Bei allen anderen wird der Wert einfach ignoriert. *Dafür* eine globale Variable zu verwenden die von völlig unbeteiligten Aufrufen verändert wird ist extrem unübersichtlich und auch fehleranfällig. Zudem wird der Initialwert der ganz am Anfang gesetzt wird, nie irgendwo verwendet.
Statt `os.path` & Co verwendet man in neuem Code `pathlib`.
Das Verzeichnis des Programms sollte man einmal am Anfang als Konstante ermitteln.
`click_image()` und `doubleclick_image()` sind fast identisch. Die sollten eigentlich noch ähnlicher sein, denn die unterscheiden sich ja einzig durch die Anzahl der Mausklicks.
Die Tests auf den Rückgabewert von `locateCenterOnScreen()` machen keinen Sinn, denn die Funktion gibt entweder ein Tupel zurück oder löst eine Ausnahme aus. Damit macht dann aber auch der Rückgabewert keinen Sinn denn der ist *immer* `True` weil im anderen Fall ja eine Ausnahme ausgelöst wird. Das gilt auch für `find_image()`.
Das starten eines Browsers mittels `webdriver` passiert zweimal mit identischem Code und beide male vor einem Bildschirmfoto. Das sollte mindestens in eine eigene Funktion herausgezogen werden, oder in die `make_screenshot()` wandern.
``if screenshot1_path and screenshot2_path:`` ist immer wahr, kann also raus.
Und auch `similarity_score` und `result_path` braucht man nicht prüfen, denn die Bilder sollten ja beide existieren.
Selbst wenn `findContours()` das Array verändern *würde*, macht ``thresh.copy()`` keinen Sinn, weil das Array sonst nirgends verwendet wird.
Zwischenstand (ungetestet):
Code: Alles auswählen
import json
import os
from datetime import datetime as DateTime
from functools import partial
from pathlib import Path
from time import sleep
import cv2
import numpy as np
import pyautogui
from selenium import webdriver
from skimage.metrics import structural_similarity
SELF_PATH = Path(__file__).parent
def locate_image(image):
return pyautogui.locateCenterOnScreen(SELF_PATH / image, confidence=0.9)
def click_image(image, clicks=1):
x, y = locate_image(image)
pyautogui.click(x, y, clicks=clicks, interval=0.25)
doubleclick_image = partial(click_image, clicks=2)
def make_screenshot(url, image_folder):
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument("--start-maximized")
driver = webdriver.Chrome(options=chrome_options)
driver.get(url)
sleep(4)
screenshot = pyautogui.screenshot()
screenshot_path = (
image_folder / f"Screenshot_{DateTime.now():%Y%m%d_%H%M%S}.png"
)
screenshot.save(screenshot_path)
print(f"Screenshot gespeichert: {screenshot_path}")
sleep(1)
driver.quit()
sleep(2)
return screenshot_path
def compare_images(image1_path, image2_path, output_folder):
images = list(map(cv2.imread, [image1_path, image2_path]))
score, diff = structural_similarity(
*(cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) for image in images),
full=True,
)
contours, _ = cv2.findContours(
cv2.threshold(
(diff * 255).astype("uint8"),
0,
255,
cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU,
)[1],
cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE,
)
for x, y, w, h in map(cv2.boundingRect, contours):
for image in images:
cv2.rectangle(image, (x, y), (x + w, y + h), (0, 0, 255), 2)
result_path = (
output_folder / f"Vergleich_vom_{DateTime.now():%Y%m%d_%H%M%S}.png"
)
cv2.imwrite(result_path, np.concatenate(images, axis=1))
return score, result_path
def main():
with open("data.json", "rb") as file:
config = json.load(file)
images = config["images"]["url_screenshot"]
image_ordner = config["images"]["folders"]
for key, url in images.items():
image_folder = Path(image_ordner[key]).expanduser()
screenshot_before_path = make_screenshot(url, image_folder)
click_image(images["chrome"])
print("Öffne Chromebrowser")
sleep(1)
click_image(images["double_arrows"])
print("Benutze Doppelpfeile oben rechts")
sleep(1)
website_image = images["website"][key]
try:
locate_image(website_image)
print("erstes Bild gefunden")
sleep(1)
click_image(website_image)
print("Öffne die Webseite")
except pyautogui.ImageNotFoundException:
try:
print("erste Bild nicht gefunden, da kein Fullscreen")
doubleclick_image(images["fullscreen"])
sleep(1)
click_image(website_image)
print("Öffne die Webseite")
sleep(1)
except pyautogui.ImageNotFoundException:
try:
click_image(website_image)
print("Öffne die Webseite")
except pyautogui.ImageNotFoundException:
sleep(1)
click_image(website_image)
sleep(1)
try:
click_image(images["bitwarden"])
print("Öffne Bitwarden")
except pyautogui.ImageNotFoundException:
click_image(images["bitwarden2"])
print("Öffne Bitwarden")
sleep(1)
click_image(images["zugangsdaten"][key])
print("Benutze Zugangsdaten")
sleep(2)
click_image(images["login"])
print("Klicke auf Login... bitte Yubikey verwenden")
sleep(10)
click_image(images["components"])
print("Öffne Komponenten")
sleep(1)
click_image(images["akeeba"])
print("Öffne Akeeba Backup")
sleep(1)
click_image(images["control_panel"])
print("Öffne Controlpanel")
sleep(1)
click_image(images["start"])
print("Beginne mit dem Backup")
sleep(5)
while True:
try:
locate_image(images["back_control_panel"])
break
except pyautogui.ImageNotFoundException:
print("Update noch im Gange...")
sleep(5)
sleep(3)
click_image(images["back_control_panel"])
sleep(3)
click_image(images["yoomla_home"])
sleep(3)
try:
locate_image(images["green_star"])
green_star = True
except pyautogui.ImageNotFoundException:
print("Sieht aus als müssten Updates gemacht werden.")
green_star = False
sleep(3)
if green_star:
print("updates sind akutell")
click_image(images["green_star"])
sleep(5)
click_image(images["yoomla_home"])
else:
print("müssen aktualisiert werden")
click_image(images["red_star"])
sleep(3)
while True:
try:
click_image(images["checkbox"])
sleep(3)
click_image(images["update_btn"])
sleep(15)
click_image(images["yoomla_home"])
break
except pyautogui.ImageNotFoundException:
print("warte auf weiterleitung....")
sleep(5)
sleep(3)
click_image(images["close_window"])
sleep(3)
screenshot_after_path = make_screenshot(url, image_folder)
similarity_score, result_path = compare_images(
screenshot_before_path,
screenshot_after_path,
Path(folders[key]).expanduser(),
)
print(f"Ähnlichkeitsindex (SSIM): {similarity_score}")
print(f"Vergleich gespeichert: {result_path}")
if __name__ == "__main__":
main()