Website-Screenshots mit Python und Selenium
Mit Hilfe von Selenium und PyVirtualDisplay lassen sich auch ohne laufende grafische Oberfläche Screenshots von Webseiten anfertigen.
PyVirtualDisplay nutzt dabei den virtuellen XServer Xvfb, und Selenium steuert einen so genannten WebDriver, eine programmierbare Instanz eines Webbrowsers (im Falle von Geckodriver ein Firefox, oder Chromium/Chrome mit Chromedriver).
Im folgenden zeige ich, wie sich ein einfaches Skript erstellen lässt, das in einer Funktion (make_screenshot()
) einen Screenshot von einer Webseite erstellt, und sich über die Kommandozeile bedienen lässt.
Virtuellen Display und WebDriver einrichten
In der Funktion make_screenshot()
wird zunächst der virtuelle Bildschirm erstellt. Dabei wird sicherheitshalber die Höhe und Breite des Browserfensters um 100 Pixel erweitert.
Danach wird versucht, eine Instanz des Firefox-Treibers GeckoDriver erstellt. Da dieser zum Beispiel unter Raspbian nicht verfügbar ist, wird ein Fallback auf ChromeDriver eingerichtet. Damit GeckoDriver keine Log-Datei erstellt, was das Standardverhalten ist, wird /dev/null
als Logdatei-Pfad eingerichtet. (Bei ChromeDriver ist das nicht notwendig.) Danach wird die Größe des Browserfensters gesetzt.
import sys
import time
import shutil
import pyvirtualdisplay
import selenium
def make_screenshot(url, img, window_size=(1280, 1024), browser_timeout=15, sleep_time=5):
window_width = window_size[0]
window_height = window_size[1]
screen_size = (window_width + 100, window_height + 100)
# Create virtual display
display = pyvirtualdisplay.Display(visible=False, size=screen_size)
display.start()
# Select best webdriver
if shutil.which("geckodriver"):
browser = selenium.webdriver.Firefox(service_log_path="/dev/null")
elif shutil.which("chromedriver"):
browser = selenium.webdriver.Chrome()
else:
print("Errror: Neither geckodriver nor chromedriver found in $PATH!", file=sys.stderr)
print("Please install at least one of them (geckodriver is preferred, but not", file=sys.stderr)
print("available on Raspberry Pi OS for example.)", file=sys.stderr)
sys.exit(1)
# Resize browser
browser.set_window_size(
window_width,
window_height
)
URL laden und Scrollbars entfernen
Nun wird die URL geladen, und ein Timeout für das Laden der Webseite gesetzt. Damit auch aufwendigere Seiten Zeit haben z.B. via JavaScript externe Inhalte nachzuladen, wird mit time.sleep()
fünf Sekunden gewartet.
Um am rechten Rand keinen weißen Bereich durch Scrollbars zu haben, wird die CSS-Eigenschaft overflow
des <body>
-Elements via JavaScript auf hidden
gesetzt.
# Load URL
browser.get(url)
# Set timeouts
browser.set_script_timeout(browser_timeout)
browser.set_page_load_timeout(browser_timeout)
# Wait a few seconds so the page get's rendered...
time.sleep(sleep_time)
# Hide scrollbars (if not we might get a white border at the right)
browser.execute_script('document.querySelector("body").style.overflow="hidden";')
Screenshot erstellen
Zu guter Letzt wird der Screenshot erstellt und Browser sowie virtueller Display beendet.
# Save screenshot
browser.save_screenshot(img)
# Bye bye...
browser.quit()
display.stop()
main()
-Funktion
Die main()
-Funktion nimmt den ersten und zweiten Komandozeilen-Parameter für die URL und den Screenshot-Dateinamen; und erstellt, solange die Bilddatei nicht existiert den Screenshot mithilfe der Funktion make_screenshot()
.
def main():
url = sys.argv[1]
img = sys.argv[2]
if os.path.exists(img):
print("File exists: {}".format(img), file=sys.stderr)
return 1
make_screenshot(url, img)
return 0
if __name__ == "__main__":
sys.exit(main())
Screenshot erstellen
Nun kann das Skript genutzt werden, um einen Screenshot zu erstellen:
python3 website-screenshot.py \
"https://malte70.de/blog/website-screenshots-python-selenium/" \
blogpost.png