Automatisierung von Screenshots

Stellt hier eure Projekte vor.
Internetseiten, Skripte, und alles andere bzgl. Python.
Antworten
S0S
User
Beiträge: 50
Registriert: Samstag 9. Februar 2013, 18:59

Ich habe ein kleines Programm geschrieben, mit dessen Hilfe man automatisiert Screenshots erstellen kann. Das Programm fragt zunächst nach den Namen der Bilder, wobei man gleichzeitig auch die Anzahl festlegt, öffnet dann das Snipping Tool von Windows und klickt die entsprechenden Buttons so, dass man nur noch dann, wenn der Bildschirm trüb wird, den entsprechenden Bereich auf dem Bildschirm auswählen muss.

Das ist der Code:

Code: Alles auswählen

import pyautogui
import time
import os

def find_click(button):
    not_open = True
    while not_open:
        try:
            button_name = "Screenshots\{}.png".format(button)
            button_location = pyautogui.locateOnScreen(button_name)
            x,y = pyautogui.center(button_location)
            pyautogui.click(0.8*x,0.8*y)        #???      ggf.: 0.8* weg
            not_open = False
        except:
            print "Looking for", button
            pyautogui.moveRel(1,0)
            not_open = True
        time.sleep(1)

def make_screenshot(name):
    find_click("Neu")
    find_click("Datei")
    find_click("Speichern_unter")
    pyautogui.typewrite("C:\Users\Susanne\Dateien\Verschiedenes\Screenshots\{}.png".format(name)) #Ordner, in den die Screenshots gespeichert werden sollen
    pyautogui.hotkey("enter")

print "Eingabe der Dateinamen (ohne Endung), Beenden der Eingabe: quit"
eingabe = ""
names = []
while eingabe != "quit":
    eingabe = raw_input(">> ")
    if eingabe != "quit":
        names.append(eingabe)
        
pyautogui.hotkey("win", "r")
pyautogui.typewrite("SnippingTool.exe")
pyautogui.press("enter")

for name in names:
    make_screenshot(name)

find_click("Datei")
find_click("Beenden")
Zusätzlich braucht man noch Screenshots von den Buttons Neu, Datei, Speichern unter und Beenden als .png im richtigen Unterordner. Hat man eine deutsche Tastatur, muss man vor dem Ausführen des Programms das Layout auf Englisch umschalten, was - wenn man das richtige Layout installiert hat - mit folgendem Skript geht:

Code: Alles auswählen

import pyautogui
import subprocess

pyautogui.hotkey("win", "space") #changes layout to English

subprocess.call(["C:\Python27\python.exe", "C:\Users\Susanne\Dateien\Verschiedenes\make_screenshot\make_screenshot.py"]) #hinten: Python-Programm, das geoeffnet werden soll

pyautogui.hotkey("win", "space") #changes layout to back to German
Auf manchen PCs muss man Programme, die Maus und Tastatur bedienen, offensichtlich im Admin-Modus ausführen, auf anderen nicht. Warum ich bei meinem Haupt-PC den Faktor 0.8 für das Anklicken der Koordinaten brauche, weiß ich nicht; auf einem anderen PC habe ich das auch nicht gebraucht. (siehe auch: viewtopic.php?f=1&t=38336 und viewtopic.php?f=1&t=38317)

Als Fazit habe ich gelernt, dass pyautogui zwar funktioniert, aber ziemlich nervig ist. Außerdem geht das Klicken auch nicht unbedingt schneller, als wenn man es von Hand machen würde. Die Anwendung lohnt sich daher meiner Meinung nach nur, wenn man etwas programmiert, was keinerlei Eingriffe vom Nutzer erfordert, wo man also das Programm startet und dann einfach geht und nach einer Weile kommt man wieder und das Programm ist fertig. Im konkreten Fall, wo man immer wieder Bildschirmbereiche für die Screenshots erstellen muss, bringt es nicht so viel.
S0S
User
Beiträge: 50
Registriert: Samstag 9. Februar 2013, 18:59

Entweder kann ich meinen Beitrag oben nicht editieren oder ich bin zu doof, um den richtigen Button zu finden...

Ich habe jetzt herausgefunden, dass der Faktor 0,8 wohl von einem Problem mit HD-Displays herrührt. Um dieses zu umgehen, diesen Faktor also weglassen zu können, kann man folgendes machen: Rechtsklick auf python.exe -> Eigenschaften -> Kompatibilität -> "Skalierung bei hohem DPI-Wert deaktivieren" anklicken (siehe die Antwort von zlorb hier: https://github.com/asweigart/pyautogui/issues/61)

Die Funktion find_click sieht dann folgendermaßen aus:

Code: Alles auswählen

def find_click(button):
    not_open = True
    while not_open:
        try:
            button_name = "Screenshots\{}.png".format(button)
            button_location = pyautogui.locateOnScreen(button_name)
            x,y = pyautogui.center(button_location)
            pyautogui.click(x,y)        
            not_open = False
        except:
            print "Looking for", button
            pyautogui.moveRel(1,0)
            not_open = True
        time.sleep(1)
BlackJack

@S0S: Beiträge können nur eine gewisse Zeit erneut bearbeitet werden und auch nur solange noch niemand darauf geantwortet hat.

Ein paar Anmerkungen zum Quelltext:

`os` wird importiert, aber nicht verwendet.

Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst. Dann gibt es auf Modulebene auch keine Variablen mehr, die man aus versehen in Funktionen verwenden könnte.

Die ``while``-Schleifen sind ungünstig gestaltet. In Fällen wo man eigentlich eine nachprüfende Schleife braucht, verwendet man in Python ”Endlosschleifen” die bei Bedarf mit ``break`` verlassen werden. Das spart unnötige Definitionen von Variablen mit “dummy“-Werten vor der Schleife beziehunsgweise im Falle von Flags gleich den Namen komplett.

Bei der Eingabe für das Ende der Namen würde ich eher eine Leereingabe verwenden als 'quit' weil letzeres vom Benutzer ja auch als Dateiname gewünscht sein könnte.

Den Pfad wo die Bildchirmfotos abgelegt werden, würde ich als Konstante herausziehen. Ausserdem sollte man ein ”rohes” Zeichenkettenliteral verwenden wenn die Zeichenkette Backslashes enthält. Sonst kann es leicht passieren das man die Zeichenkette ändert und ohne es zu merken eine Escape-Sequenz einbaut, die man da gar nicht haben möchte.

`find_click()` würde ich `find_and_click()` nennen. Sonst klingt das so als wenn die Funktionen einen Klick sucht/findet, was immer das auch semantisch bedeuten mag.

Die Ausnahmebehandlung mit dem nackten ``except`` ohne konkrete Ausnahme(n) ist eine ganz schlechte Idee. Da werden alle Ausnahmen behandelt, auch solche mit denen Du gar nicht rechnest. Zudem verwendet die `pyautogui`-API (leider) keine Ausnahmen, sondern gibt `None` als Rückgabewert wenn der Bildausschnitt nicht gefunden werden konnte. Der Code im ``try``-Block sollte möchlichst kurz sein, und man sollte nur die Ausnahme(n) behandeln die man an der Stelle tatsächlich erwartet und sinnvoll behandeln kann.

Ich lande dann ungefähr bei so etwas (ungetestet):

Code: Alles auswählen

#!/usr/bin/env python
# coding: utf8
from __future__ import absolute_import, division, print_function
import os
import time
from functools import partial

import pyautogui

SCREENSHOT_PATH = r'C:\Users\Susanne\Dateien\Verschiedenes\Screenshots'


def find_and_click(image_name):
    while True:
        location = pyautogui.locateCenterOnScreen(
            os.path.join('Screenshots', image_name + '.png')
        )
        try:
            x, y = location
        except TypeError:
            print('Looking for', image_name)
            pyautogui.moveRel(1, 0)
            time.sleep(1)
        else:            
            pyautogui.click(x, y)
            break


def make_screenshot(image_name):
    for name in ['Neu', 'Datei', 'Speichern_unter']:
        find_and_click(name)
    pyautogui.typewrite(os.path.join(SCREENSHOT_PATH, image_name + '.png'))
    pyautogui.hotkey('enter')


def main():
    print(
        'Eingabe der Dateinamen (ohne Endung),\n'
        'Enter ohne Eingabe wenn alle Namen eingegeben wurden.'
    )
    image_names = list(iter(partial(raw_input, '>> '), ''))
           
    pyautogui.hotkey('win', 'r')
    pyautogui.typewrite('SnippingTool.exe')
    pyautogui.press('enter')

    for image_name in image_names:
        make_screenshot(image_name)

    for name in ['Datei', 'Beenden']:
        find_and_click(name)


if __name__ == '__main__':
    main()
S0S
User
Beiträge: 50
Registriert: Samstag 9. Februar 2013, 18:59

Vielen Dank für die Anmerkungen!
Antworten