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.
1import sys
2import time
3import shutil
4
5import pyvirtualdisplay
6import selenium
7
8
9def make_screenshot(url, img, window_size=(1280, 1024), browser_timeout=15, sleep_time=5):
10 window_width = window_size[0]
11 window_height = window_size[1]
12 screen_size = (window_width + 100, window_height + 100)
13
14 # Create virtual display
15 display = pyvirtualdisplay.Display(visible=False, size=screen_size)
16 display.start()
17
18 # Select best webdriver
19 if shutil.which("geckodriver"):
20 browser = selenium.webdriver.Firefox(service_log_path="/dev/null")
21
22 elif shutil.which("chromedriver"):
23 browser = selenium.webdriver.Chrome()
24
25 else:
26 print("Errror: Neither geckodriver nor chromedriver found in $PATH!", file=sys.stderr)
27 print("Please install at least one of them (geckodriver is preferred, but not", file=sys.stderr)
28 print("available on Raspberry Pi OS for example.)", file=sys.stderr)
29 sys.exit(1)
30
31 # Resize browser
32 browser.set_window_size(
33 window_width,
34 window_height
35 )
36
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.
37 # Load URL
38 browser.get(url)
39
40 # Set timeouts
41 browser.set_script_timeout(browser_timeout)
42 browser.set_page_load_timeout(browser_timeout)
43
44 # Wait a few seconds so the page get's rendered...
45 time.sleep(sleep_time)
46
47 # Hide scrollbars (if not we might get a white border at the right)
48 browser.execute_script('document.querySelector("body").style.overflow="hidden";')
49
Screenshot erstellen
Zu guter Letzt wird der Screenshot erstellt und Browser sowie virtueller Display beendet.
50 # Save screenshot
51 browser.save_screenshot(img)
52
53 # Bye bye...
54 browser.quit()
55 display.stop()
56
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()
.
57def main():
58 url = sys.argv[1]
59 img = sys.argv[2]
60 if os.path.exists(img):
61 print("File exists: {}".format(img), file=sys.stderr)
62 return 1
63
64 make_screenshot(url, img)
65
66 return 0
67
68
69if __name__ == "__main__":
70 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