{"id":8394,"date":"2022-03-13T14:34:37","date_gmt":"2022-03-13T12:34:37","guid":{"rendered":"https:\/\/u-labs.de\/portal\/?p=8394"},"modified":"2022-12-12T16:48:17","modified_gmt":"2022-12-12T14:48:17","slug":"webbrowser-automatisieren-web-scraper-mit-python-selenium-auf-dem-raspberry-pi-fuer-anfaenger","status":"publish","type":"post","link":"https:\/\/u-labs.de\/portal\/webbrowser-automatisieren-web-scraper-mit-python-selenium-auf-dem-raspberry-pi-fuer-anfaenger\/","title":{"rendered":"Webbrowser automatisieren: Web Scraper mit Python + Selenium auf dem Raspberry Pi f\u00fcr Anf\u00e4nger"},"content":{"rendered":"<h2 class=\"wp-block-heading\" id=\"was-ist-web-scraping\">Was ist &#8222;Web Scraping&#8220;?<\/h2>\n<p>&#8222;Scraping&#8220; hei\u00dft kratzen oder absch\u00fcrfen. Beim Web Scraping lie\u00dft man bestimmte Dateien einer Internetseite automatisiert aus, um sie weiterverwenden zu k\u00f6nnen. Beispielsweise um sie irgendwo anzuzeigen oder Analysen durchzuf\u00fchren. Das wohl bekannteste Beispiel sind Bots von Google und anderen Suchmaschinen: Sie durchsuchen Internetseiten und speichern Informationen in ihrer Datenbank, um sie f\u00fcr die Suchergebnisse zu nutzen. Auch Preisvergleichsportale durchsuchen automatisiert die Shops zur Ermittlung der g\u00fcnstigsten Preise.<\/p>\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/03\/vlcsnap-2022-03-13-13h34m05s832.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"576\" src=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/03\/vlcsnap-2022-03-13-13h34m05s832-1024x576.png\" alt=\"\" class=\"wp-image-8677\" srcset=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/03\/vlcsnap-2022-03-13-13h34m05s832-1024x576.png 1024w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/03\/vlcsnap-2022-03-13-13h34m05s832-300x169.png 300w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/03\/vlcsnap-2022-03-13-13h34m05s832-768x432.png 768w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/03\/vlcsnap-2022-03-13-13h34m05s832-1536x864.png 1536w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/03\/vlcsnap-2022-03-13-13h34m05s832-70x39.png 70w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/03\/vlcsnap-2022-03-13-13h34m05s832.png 1920w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n<p>Wenn es keine Programmierschnittstelle (API) gibt, um die gew\u00fcnschten Daten zu erhalten, ist Scraping oft die einzige M\u00f6glichkeit. Bei \u00f6ffentlichen Daten ist es rechtlich legal, sofern das Urheberrecht beachtet wird. In anderen F\u00e4llen variiert die Legalit\u00e4t je nach Umst\u00e4nden.<\/p>\n<p>Der Raspberry Pi eignet sich perfekt f\u00fcr Scraping, da er durch seinen geringen Stromverbrauch problemlos l\u00e4ngere Zeit 24\/7 laufen und regelm\u00e4\u00dfig Daten einsammeln kann. Grunds\u00e4tzlich funktioniert es aber auch auf jedem X86 Server.<\/p>\n<h2 class=\"wp-block-heading\" id=\"was-ist-selenium\">Was ist Selenium?<\/h2>\n<p>Selenium ist ein quelloffenes Framework, um Webseiten und Webanwendungen automatisiert zu testen. Dazu wird ein Browser ferngesteuert. Das kostet zwar etwas Ressourcen, hat aber einen gro\u00dfen Vorteil: CSS und vor allem JavaScript wird ausgef\u00fchrt. N\u00fctzlich f\u00fcr Seiten, auf denen Inhalte dynamisch nachgeladen werden, etwa per Ajax oder WebSockets. F\u00fcr Softwaretests ist das essenziell, bei Crawlern n\u00fctzlich.<\/p>\n<h2 class=\"wp-block-heading\" id=\"das-beispiel-szenario\">Das Beispiel-Szenario<\/h2>\n<p>Es gibt <a href=\"http:\/\/www.ebesucher.de\/?ref=DMW007\" title=\"auf eBesucher\" target=\"_blank\" rel=\"nofollow\">auf eBesucher<\/a> eine Preisseite. Sie zeigt, wie viele Besuchertauschpunkte (BTP) ein Werbetreibender bezahlen muss, wenn er seine Seite f\u00fcr 15 Sekunden in der Surfbar angezeigt haben m\u00f6chte.<\/p>\n<figure class=\"wp-block-image size-large is-resized\"><a href=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-3.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-3-1024x696.png\" alt=\"\" class=\"wp-image-8395\" width=\"840\" height=\"570\" srcset=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-3-1024x696.png 1024w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-3-300x204.png 300w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-3-768x522.png 768w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-3-70x48.png 70w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-3.png 1226w\" sizes=\"auto, (max-width: 840px) 100vw, 840px\" \/><\/a><figcaption class=\"wp-element-caption\">So sieht die <a href=\"https:\/\/www.ebesucher.de\/werbung\/preise\" title=\"Preisliste \" target=\"_blank\" rel=\"nofollow\">Preisliste <\/a>aus, die wir als Beispiel-Anwendungsszenario &#8222;scrapen&#8220; m\u00f6chten<\/figcaption><\/figure>\n<p>In diesem Beispiel soll also ausgelesen werden, dass eine Einblendung in Deutschland derzeit 1,45 BTP kostet. Dieser Preis kann sich \u00e4ndern, in welchen Abst\u00e4nden ist nicht bekannt. Unter anderem das k\u00f6nnen wir mit unserem Scraping versuchen herauszufinden.<\/p>\n<p><strong>Vornweg<\/strong>: Diese Seite ist recht simpel aufgebaut und lie\u00df sich relativ einfach mit h\u00e4ndischen HTTP-Anfragen auslesen &#8211; das ist in der Ausf\u00fchrung effizienter, aber weniger vielseitig bzw. bei komplexeren Internetseiten deutlich aufw\u00e4ndiger\/fehleranf\u00e4lliger zu implementieren als Selenium. Gerade weil diese Seite nicht \u00fcberm\u00e4\u00dfig komplex ist, eignet sie sich gut zur ersten Demonstration. So kann ein Einsteiger die Funktion verstehen, statt gleich zu Beginn mit der Komplexit\u00e4t von Sonderf\u00e4llen erschlagen zu werden.<\/p>\n<h2 class=\"wp-block-heading\" id=\"das-beispiel-szenario\">Was brauche ich?<\/h2>\n<p>Wir nutzen die verbreitete Skriptsprache Python in Version 3.7 oder h\u00f6her. Selenium wurde aber mittlerweile in nahezu alle g\u00e4ngigen Sprachen portiert, dort kann es mit einigen Anpassungen ebenfalls verwendet werden. Python3 sollte unter dem Raspberry Pi OS bereits installiert sein:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\n$ python3 --version\nPython 3.9.2\n<\/pre>\n<\/div>\n<p>Der Python-Paketmanger <strong>Pip<\/strong> ist standardm\u00e4\u00dfig nicht vorhanden, daher installieren wir ihn zun\u00e4chst:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nsudo apt install python3-pip\n<\/pre>\n<\/div>\n<p>Da wir Pip-Abh\u00e4ngigkeiten ben\u00f6tigen, empfehle ich eine virtuelle Python-Umgebung. Anschlie\u00dfend mit pip das Selenium-Paket installieren, dies integriert Selenium in Python.<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\n$ virtualenv ebesucher-scraper\n$ cd ebesucher-scraper\n$ source bin\/activate\n\n$ pip3 install selenium\n<\/pre>\n<\/div>\n<p>Nun ben\u00f6tigen wir einen WebDriver. Dies ist die Selenium-Implementierung f\u00fcr einen einzelnen Browser, der ferngesteuert wird. F\u00fcr Tests gibt es auch andere Varianten, etwa Grid zur parallen ausf\u00fchrung mehrere Tests. Es gibt verschiedene WebDriver-Implementierungen, da man Webseiten ja in der Regel nicht nur in einem Browser testet. <\/p>\n<p>Normal nutze ich hierf\u00fcr den quelloffenen, freien Browser Firefox. Leider gibt es f\u00fcr den notwendigen Geckodriver f\u00fcr die ARM-Architektur des Raspberry Pi weder in der Paketverwaltung, noch zum Download. Daher weichen wir auf Chromium auf. <\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nsudo apt install chromium-driver\n<\/pre>\n<\/div>\n<p><strong>Hinweis<\/strong>: Die Pakete sind recht gro\u00df und installiert den Chromium-Webbrowser als Abh\u00e4ngigkeit, sofern noch nicht vorhanden. Insgesamt werden ca. 137 MB heruntergeladen und 520 MB auf euere Speicherkarte entpackt.<\/p>\n<h2 class=\"wp-block-heading\" id=\"das-beispiel-szenario\">Grundger\u00fcst und ein erster Test<\/h2>\n<p>Beginnen wir mit einem einfachen Beispiel: Erzeugen eines Chrome WebDriver-Objektes, dass wir Headless aufrufen. Dadurch seht ihr das Browserfenster nicht. Zur Fehlersuche kann es n\u00fctzlich sein, dies auszukommentieren, sodass wir sehen, was Selenium tut. Funktioniert aber nur, wenn ihr entweder eine grafische Oberfl\u00e4che nutzt, oder aber mittels X-Forwarding die Fenster lokal \u00f6ffnet.<\/p>\n<p>Unser Chromium-Browser soll die Startseite Qwant \u00f6ffnen und uns dem Titel ausgeben. Den seht ihr beim Surfen normal in der Titelleiste des Browsers bzw. teile davon in der Registerkarte.<\/p>\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-4.png\"><img loading=\"lazy\" decoding=\"async\" width=\"822\" height=\"132\" src=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-4.png\" alt=\"\" class=\"wp-image-8398\" srcset=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-4.png 822w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-4-300x48.png 300w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-4-768x123.png 768w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-4-70x11.png 70w\" sizes=\"auto, (max-width: 822px) 100vw, 822px\" \/><\/a><\/figure>\n<p>Legt f\u00fcr folgenden Code ein Python-Skript an, ich nenn es <strong>crawler.py<\/strong> und \u00f6ffnet dies mit einem Texteditor.<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\nfrom selenium import webdriver\nfrom selenium.webdriver.common.by import By\n\n# Verhindert, dass das Browserfenster geoffnet wird (per SSH ohne GUI\/X-Forwarding zwingend notwendig)\nchromeOptions = webdriver.ChromeOptions()\nchromeOptions.add_argument(&quot;headless&quot;)\n\ndriver = webdriver.Chrome(options=chromeOptions)\ndriver.get(&#039;https:\/\/qwant.com&#039;)\nprint(driver.title)\ndriver.quit()\n<\/pre>\n<\/div>\n<p>Anschlie\u00dfend das Skript ausf\u00fchren. Es sollte der entsprechende Titel ausgegeben werden:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\n$ python3 scrape.py\nQwant - The search engine that respects your privacy\n<\/pre>\n<\/div>\n<p>Hier auf Englisch, weil das die Standard-Sprache von Chromium ist. Dies lesen manche Internetseiten aus und passen ihre Sprache entsprechend an. In Selenium k\u00f6nnte man die Sprache auf Deutsch \u00e4ndern, das ist hier aber nicht relevant.<\/p>\n<h2 class=\"wp-block-heading\" id=\"das-beispiel-szenario\">Auslesen des Deutschen BTP-Preises mit Selenium<\/h2>\n<p>Nun geht es mit eBesucher weiter. Zun\u00e4chst \u00e4ndern wir die Adresse, die Selenium aufrufen soll:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\n# Statt vorher: driver.get(&#039;https:\/\/qwant.com&#039;)\ndriver.get(&#039;https:\/\/www.ebesucher.de\/werbung\/preise&#039;)\n<\/pre>\n<\/div>\n<p>Wird das Skript erneut mit dem Python-Befehl wie zuvor gezeigt gestartet, sollten wir den Seitentitel von eBesucher sehen k\u00f6nnen:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\n$ python scrape.py\nPreise f\u00fcr Webseitenbesucher | Preisrechner | eBesucher.de\n<\/pre>\n<\/div>\n<p>Nun hilft der Seitentitel f\u00fcrs Auslesen von Daten nicht weiter, das war nur als Test zum aufw\u00e4rmen gedacht. Um Daten auszulesen, m\u00fcssen wir uns zun\u00e4chst mit der HTML-Struktur der Seite besch\u00e4ftigen. Am besten f\u00e4ngt man mit dem Element an, dass man auslesen m\u00f6chte: Im Firefox dort einen Rechtsklick auf das gew\u00fcnschte Element (hier der BTP Kurs, aktuell &#8222;1,45&#8220;) und dann auf <strong>Untersuchen<\/strong> im Kontextmen\u00fc.<\/p>\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-5.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"278\" src=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-5-1024x278.png\" alt=\"\" class=\"wp-image-8399\" srcset=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-5-1024x278.png 1024w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-5-300x82.png 300w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-5-768x209.png 768w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-5-70x19.png 70w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-5.png 1401w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n<p>Die blaue Zeile ist das Element, auf das wir den Rechtsklick durchgef\u00fchrt haben. Mit dem Pfeil links kann man das Element aufklappen. Es ist also ein <strong>&lt;td&gt;<\/strong> Element (Feld einer Tabelle), in dem der Wert steht. <\/p>\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-6.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"494\" src=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-6-1024x494.png\" alt=\"\" class=\"wp-image-8400\" srcset=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-6-1024x494.png 1024w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-6-300x145.png 300w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-6-768x370.png 768w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-6-1536x741.png 1536w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-6-70x34.png 70w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-6.png 1547w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n<p>Interessant ist vor allem der linke Bereich mit der HTML-Struktur. Die m\u00fcssen wir analysieren und einen Selektor finden, um das gew\u00fcnschte Element zu finden. Hilfreich sind dabei vor allem Ids, damit l\u00e4sst sich ein Element am einfachsten identifizieren. Alternativ gibt es Klassen, manchmal muss man auch auf die Verschachtelung der Elemente gehen.<\/p>\n<p>In diesem Falle funktioniert leider alles nicht: Das <strong>&lt;td&gt;<\/strong> Element hat nur eine Klasse &#8222;nobr&#8220; &#8211; und die wird in jedem anderen &lt;td&gt; Element auch gesetzt, ist daher zur Filterung nutzlos. Schauen wir daher mal etwas \u00fcber den Tellerrand, wie sieht es mit dem linken Tabellenfeld (&#8222;Deutschland&#8220;) aus? Wesentlich besser, die Flagge des <strong>&lt;span&gt;<\/strong> Elements enth\u00e4lt eine Klasse <strong>flag-icon-de<\/strong>. Das L\u00e4nderk\u00fcrzel scheint eindeutig:<\/p>\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-7.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1022\" height=\"450\" src=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-7.png\" alt=\"\" class=\"wp-image-8401\" srcset=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-7.png 1022w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-7-300x132.png 300w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-7-768x338.png 768w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-7-70x31.png 70w\" sizes=\"auto, (max-width: 1022px) 100vw, 1022px\" \/><\/a><\/figure>\n<p>Allerdings zeigt eine Suche: Es wird an zwei anderen Stellen ebenfalls noch verwendet. Eine unsichtbare, gleich aufgebaute Tabelle und die Auswahlbox links unten, \u00fcber die man die Sprache der gesamten Seite \u00e4ndern kann.<\/p>\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-9.png\"><img loading=\"lazy\" decoding=\"async\" width=\"848\" height=\"134\" src=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-9.png\" alt=\"\" class=\"wp-image-8403\" srcset=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-9.png 848w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-9-300x47.png 300w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-9-768x121.png 768w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-9-70x11.png 70w\" sizes=\"auto, (max-width: 848px) 100vw, 848px\" \/><\/a><\/figure>\n<p>Bei n\u00e4herer Betrachtung der Struktur f\u00e4llt auf, dass unsere Preistabelle aus der wir die Daten haben m\u00f6chten, eine Id <strong>preisstaffelung<\/strong> besitzt:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n&lt;table class=&quot;grayedtable&quot; id=&quot;preisstaffelung&quot; style=&quot;width: 1095px;&quot;&gt;\n...\n<\/pre>\n<\/div>\n<p>Damit k\u00f6nnen wir die zwei unerw\u00fcnschten Elemente herausfiltern. Jedoch m\u00fcssen wir nun noch einen zweiten Sprung machen, da wir ja nicht die Bezeichnung des Landes, sondern den BTP-Preis daneben haben m\u00f6chten.<\/p>\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-8.png\"><img loading=\"lazy\" decoding=\"async\" width=\"787\" height=\"232\" src=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-8.png\" alt=\"\" class=\"wp-image-8402\" srcset=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-8.png 787w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-8-300x88.png 300w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-8-768x226.png 768w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2022\/02\/grafik-8-70x21.png 70w\" sizes=\"auto, (max-width: 787px) 100vw, 787px\" \/><\/a><\/figure>\n<p>Bei <strong>(1) <\/strong>sind wir, dieses Element befindet sich in <strong>(2)<\/strong>, wenn man eine Ebene h\u00f6her geht. Es folgt ein zweites <strong>&lt;td&gt;<\/strong> Element, in dem sich der Balken f\u00fcr das Diagramm befindet. Schlussendlich bei <strong>(3)<\/strong> das letzte <strong>&lt;td&gt;<\/strong> Element, mit unserem gew\u00fcnschten Wert. Unser Filter muss daher vom <strong>&lt;span&gt;<\/strong> Element mit der Klasse <strong>flag-icon-de<\/strong> ausgehend zwei Elemente zur\u00fcck (Eltern-Elemente) und dann das dritte <strong>&lt;td&gt;<\/strong> Element ausw\u00e4hlen.<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\nprice = driver.find_element(By.CSS_SELECTOR, &quot;#preisstaffelung .flag-icon-de&quot;)\nparentRow = price.find_element(By.XPATH, &quot;..\/..&quot;)\npriceElement = parentRow.find_element(By.CSS_SELECTOR, &quot;td:nth-child(3)&quot;)\nrawPrice = priceElement.get_attribute(&quot;innerHTML&quot;).strip()\nprint(rawPrice)\n<\/pre>\n<\/div>\n<p>Hier nutzen wir den CSS-Selektor, um das Element mit der Flagge zu finden. Anschlie\u00dfend navigieren wir mit XPath zwei Elemente weiter nach oben in das <strong>&lt;td&gt;<\/strong> Element (<strong>2<\/strong> auf dem obigen Screenshot). Wir k\u00f6nnten die Abfrage theoretisch auch komplett mit XPath umsetzen, das ist an der Stelle aber meiner Meinung nach als Einstieg zu komplex. Daher belassen wir es hier bei dem einfachen Selektor, der &#8211; \u00e4hnlich wie man es von Linux-Verzeichnissen her kennt, mit ..\/.. zwei Ebenen h\u00f6her wechselt. Schlussendlich suchen wir das dritte <strong>&lt;td&gt;<\/strong> Element <strong>(3)<\/strong>.<\/p>\n<p>Die Ausgabe enth\u00e4lt jedoch Leerzeichen aus dem HTML, der strip() Aufruf entfernt vor- und nachgestellte Leerzeichen, sodass wir eine saubere Ausgabe erhalten:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\n$ python scrape.py\n1,47\n<\/pre>\n<\/div>\n<h2 class=\"wp-block-heading\" id=\"weitere-hinweise-und-tipps\">Weitere Hinweise und Tipps<\/h2>\n<h3 class=\"wp-block-heading\" id=\"zombie-chromium-prozesse-durch-exceptions-ausnahmen-beim-testen\">Performance<\/h3>\n<p>Wie Anfangs erw\u00e4hnt, wird im Hintergrund ein kompletter Chromium-Browser gestartet und ferngesteuert &#8211; bei jedem Aufruf des Skriptes. Dementsprechend betr\u00e4gt die Ausf\u00fchrungszeit auf einem Raspberry Pi 4 mit 4GB RAM und dem Raspberry Pi OS 11 auf einer schnellen Micro-SD Karte ungef\u00e4hr 13 Sekunden. F\u00fcr finale Skripte, welche automatisch gestartet werden, ist das oft wenig relevant. Beim testen kann man ein Upgrade der Hardware versuchen, oder am besten gleich auf einer st\u00e4rkeren Workstation entwickeln.<\/p>\n<h3 class=\"wp-block-heading\" id=\"zombie-chromium-prozesse-durch-exceptions-ausnahmen-beim-testen\">&#8222;Zombie&#8220; Chromium-Prozesse durch Exceptions (Ausnahmen) beim Testen<\/h3>\n<p>Durch <strong>driver.quit()<\/strong> wird der Browser am Ende des Skriptes beendet. Falls beim Testen eine Exception auftritt, wird dieser Code aber nie erreicht &#8211; der Chromium-Prozess l\u00e4uft dadurch weiter! Ohne grafische Oberfl\u00e4che merkt man dies nicht sofort bzw. erst, wenn nach einigen Tests der Arbeitsspeicher voll l\u00e4uft. Die Prozesse sollte man in diesem Falle von Hand beenden:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\n$ ps -ax | grep chromium | egrep -v &quot;(&lt;defunct&gt;|grep)&quot; | wc -l\n7\n$ pkill chromium\n\n$ ps -ax | grep chromium | egrep -v &quot;(&lt;defunct&gt;|grep)&quot; | wc -l\n0\n<\/pre>\n<\/div>\n<p>Eine sinnvolle Alternative ist es, w\u00e4hrend der Tests den Code mit einem Try-Except-Block zu umschlie\u00dfen. Der &#8222;Finally&#8220; Teil wird in jedem Falle ausgef\u00fchrt, auch beim Auftreten einer Ausnahme. So kommt es im Fehlerfall zu keinen &#8222;Zombie Chromium-Prozessen&#8220;.<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\ntry:\n    driver.get(&#039;https:\/\/www.ebesucher.de\/werbung\/preise&#039;)\n    # ...\nfinally:\n    driver.quit()\n<\/pre>\n<\/div>\n<h2 class=\"wp-block-heading\" id=\"weitere-schritte-und-fazit\">Weitere Schritte und Fazit<\/h2>\n<p>In diesem Beispiel haben wir haupts\u00e4chlich mithilfe von CSS-Selektoren die Elemente gefiltert und erhalten mit jedem Aufruf des Skriptes den aktuellen Werbepreis f\u00fcr Deutschland. Als N\u00e4chstes sollten wir zumindest eine grundlegende Validierung einbauen, etwa ob die Elemente existieren und wir einen Zahlenwert erhalten.<\/p>\n<p>Anschlie\u00dfend folgt das Abspeichern des Kurses zusammen mit dem Zeitstempel in einer Datenbank. Damit regelm\u00e4\u00dfig Daten erhoben werden, sollte das Skript in einem sinnvollen Intervall per Cron automatisch starten. Nach einiger Zeit kann man die Daten auswerten, visualisieren und daraus Schl\u00fcsse ziehen: Wie hat sich der Kurs entwickelt, wo gibt es Auff\u00e4lligkeiten etc.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Was ist &#8222;Web Scraping&#8220;? &#8222;Scraping&#8220; hei\u00dft kratzen oder absch\u00fcrfen. Beim Web Scraping lie\u00dft man bestimmte Dateien einer Internetseite automatisiert aus, um sie weiterverwenden zu k\u00f6nnen. Beispielsweise um sie irgendwo anzuzeigen oder Analysen durchzuf\u00fchren. Das wohl bekannteste Beispiel sind Bots von Google und anderen Suchmaschinen: Sie durchsuchen Internetseiten und speichern Informationen in ihrer Datenbank, um sie &#8230;<\/p>\n","protected":false},"author":5,"featured_media":8676,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[671,61],"tags":[188,1025,1028],"class_list":["post-8394","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-raspberry-pi","category-softwareentwicklung","tag-chrome","tag-python","tag-selenium"],"_links":{"self":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts\/8394","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/comments?post=8394"}],"version-history":[{"count":13,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts\/8394\/revisions"}],"predecessor-version":[{"id":9768,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts\/8394\/revisions\/9768"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/media\/8676"}],"wp:attachment":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/media?parent=8394"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/categories?post=8394"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/tags?post=8394"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}