|
199 | 199 | " driver.get(\"https://www.airbnb.com/\")\n", |
200 | 200 | "\n", |
201 | 201 | " wait = WebDriverWait(driver, timeout=10)\n", |
202 | | - " unterkunft= wait.until(lambda x: x.find_element(By.CLASS_NAME, \"t1ms2xzu\")).is_visible()\n", |
203 | | - " unterkunft.text\n" |
| 202 | + " unterkunft = wait.until(lambda x: x.find_element(By.CLASS_NAME, \"t1ms2xzu\"))\n", |
| 203 | + "\n", |
| 204 | + " if unterkunft.is_displayed():\n", |
| 205 | + " print(unterkunft.text)\n" |
204 | 206 | ], |
205 | 207 | "metadata": { |
206 | 208 | "collapsed": false |
|
236 | 238 | { |
237 | 239 | "cell_type": "markdown", |
238 | 240 | "source": [ |
239 | | - "Bei beiden Versionen wird so lange gewartet, bis das gesuchte Element bzw. die gesuchten Elemente mit der angegeben Klasse sichtbar sind (also gerendert wurden, mehr dazu [hier](https://www.selenium.dev/selenium/docs/api/py/webdriver_support/selenium.webdriver.support.expected_conditions.html#selenium.webdriver.support.expected_conditions.presence_of_all_elements_located)). Die erste Version lässt sich allerdings nicht so leicht für die Suche nach mehreren Elementen umschreiben. Für unser Airbnb-Beispiel verwenden wir deswegen die zweite Strategie.\n", |
| 241 | + "Bei beiden Versionen wird so lange gewartet, bis das gesuchte Element bzw. die gesuchten Elemente mit der angegeben Klasse sichtbar sind (also einfach gesagt, bis sie gerendert wurden, mehr Details dazu [hier](https://www.selenium.dev/selenium/docs/api/py/selenium_webdriver_support/selenium.webdriver.support.expected_conditions.html)). Die erste Version lässt sich allerdings nicht so leicht für die Suche nach mehreren Elementen umschreiben. Für unser Airbnb-Beispiel verwenden wir deswegen die zweite Strategie.\n", |
240 | 242 | "\n", |
241 | 243 | "Mit dieser Strategie des expliziten Wartens kann auch auf eine Reihe anderer Ereignisse gewartet werden. Eine ausführliche Erläuterung dazu findet ihr [hier](https://selenium-python.readthedocs.io/waits.html), und eine Liste aller Ereignisse, auf die gewartet werden kann sowie der entsprechenden Methoden findet ihr [hier](https://www.selenium.dev/selenium/docs/api/py/webdriver_support/selenium.webdriver.support.expected_conditions.html)." |
242 | 244 | ], |
|
355 | 357 | "\n", |
356 | 358 | " driver.get(\"https://www.airbnb.com/\")\n", |
357 | 359 | " time.sleep(5) # nur damit wir sehen, können, was passiert\n", |
358 | | - " # Variablen für das Scrollen festlegen\n", |
359 | | - " scroll_step = 300 # Schrittgröße für jeden Scroll-Vorgang (in Pixeln)\n", |
360 | 360 | "\n", |
361 | 361 | " # Seite bis zum Ende scrollen\n", |
362 | 362 | " while True:\n", |
|
401 | 401 | "\n", |
402 | 402 | "Veranschaulichung der JavaScript-Objekteigenschaften zur Formulierung der Abbruchbedingung.\n", |
403 | 403 | ":::\n", |
404 | | - "\n", |
405 | | - "Das JavaScript-Code-Snippet, das wir zur Formulierung der Abbruchbedingung verwendet haben, können wir auch in Python-Variablen übersetzen. Das ist etwas sauberer, weil wir die Formulierung der Abbruchbedingung direkt in Python formulieren und nicht in einen String auslagern. Außerdem kann so z.B. die Höhe des Viewports (Eigenschaft .clientHeight) bereits außerhalb der while-Schleife einmalig abgefragt werden, da diese Höhe sich nicht ändert:\n" |
406 | | - ], |
407 | | - "metadata": { |
408 | | - "collapsed": false |
409 | | - } |
410 | | - }, |
411 | | - { |
412 | | - "cell_type": "code", |
413 | | - "execution_count": null, |
414 | | - "outputs": [], |
415 | | - "source": [ |
416 | | - "# Scrollstrategie 1 mit Variablen\n", |
417 | | - "with webdriver.Chrome() as driver:\n", |
418 | | - "\n", |
419 | | - " driver.get(\"https://www.airbnb.com/\")\n", |
420 | | - " time.sleep(5) # nur damit wir sehen was passiert\n", |
421 | | - " # Variablen für das Scrollen festlegen\n", |
422 | | - " scroll_step = 300 # Schrittgröße für jeden Scroll-Vorgang (in Pixeln)\n", |
423 | | - " viewport_height = driver.execute_script(\"return document.documentElement.clientHeight;\")\n", |
424 | | - " # Seite bis zum Ende scrollen\n", |
425 | | - " while True:\n", |
426 | | - " driver.execute_script(f\"window.scrollBy(0, {scroll_step});\")\n", |
427 | | - " time.sleep(2) # nur damit wir sehen was passiert\n", |
428 | | - " scroll_height = driver.execute_script(\"return document.documentElement.scrollHeight;\")\n", |
429 | | - " scroll_position = driver.execute_script(\"return document.documentElement.scrollTop;\")\n", |
430 | | - "\n", |
431 | | - " if scroll_height - viewport_height - scroll_position <= 1:\n", |
432 | | - " break" |
| 404 | + "\n" |
433 | 405 | ], |
434 | 406 | "metadata": { |
435 | 407 | "collapsed": false |
|
465 | 437 | "\n", |
466 | 438 | "Anschließend muss wieder bis zum Seitenende gescrollt werden, damit alle Unterkünfte laden. \"Laden\" bedeutet hier zur Erinnerung, dass die neuen Inhalte in das HTML-Gerüst eingefügt werden und dadurch addressierbar werden. Der manuelle Scrollvorgang hat gezeigt, dass die Inhalte dynamisch geladen werden, sobald sie durch Scrollen in den sichtbaren Bereich gelangen. Aber anders als bei einem Infinite Scrolling endet die Seite nach einigen Scrollvorgängen. Wir könnten also beim Scrollen genauso vorgehen, wie beim Scrollen zum \"Show more\"-Button. Allerdings war dieser Scrollvorgang recht langsam, weil in jedem Schleifendurchlauf nur um 300 Pixel gescrollt wurde. Wir könnten also, um den Vorgang etwas zu beschleunigen, zum Beispiel die Pixelanzahl vergrößern. Hierbei sollte allerdings Folgendes bedacht werden: Je nachdem, wie groß das Browserfenster auf unterschiedlichen Geräten ist, haben auch die Kacheln mit den Unterkünften eine unterschiedliche Größe und es gibt unterschiedlich viele Kacheln in einer Zeile. Es werden also je nach Größe des Browserfensters verschieden viele Kacheln geladen, wenn um 300, 500 oder 800 Pixel gescrollt wird. Wenn zu schnell gescrollt wird, dann können Inhalte nicht rechtzeitig geladen werden, und wenn das passiert, werden sie folglich von unserem Webscraper nicht gefunden.\n", |
467 | 439 | "\n", |
468 | | - "Zum Scrollen verwenden wir deswegen diesmal einen etwas zeiteffizienteren alternativen **Ansatz, bei dem in jedem Schleifendurchlauf nicht um eine feste Pixelanzahl gescrollt wird, sondern um die innere Höhe des Browserfensters.**" |
| 440 | + "Zum Scrollen verwenden wir deswegen diesmal einen etwas zeiteffizienteren alternativen **Ansatz, bei dem in jedem Schleifendurchlauf nicht um eine feste Pixelanzahl gescrollt wird, sondern um die innere Höhe des Browserfensters (\"Viewport\" bzw. Eigenschaft .clientHeight).** Das JavaScript-Code-Snippet, das wir bei der ersten Strategie zur Formulierung der Abbruchbedingung verwendet haben, übersetzen wir außerdem bei dieser Scrollstrategie in Python-Variablen. Das ist etwas sauberer, weil wir die Formulierung der Abbruchbedingung direkt in Python formulieren und nicht in einen String auslagern." |
469 | 441 | ], |
470 | 442 | "metadata": { |
471 | 443 | "collapsed": false |
|
527 | 499 | " driver.get(\"https://www.airbnb.com/\")\n", |
528 | 500 | " wait = WebDriverWait(driver, 10)\n", |
529 | 501 | " footer = wait.until(\n", |
530 | | - " EC.visibility_of_element_located((By.TAG_NAME, \"footer\"))\n", |
| 502 | + " EC.presence_of_element_located((By.TAG_NAME, \"footer\"))\n", |
531 | 503 | " )\n", |
532 | 504 | " ActionChains(driver)\\\n", |
533 | 505 | " .scroll_to_element(footer)\\\n", |
|
0 commit comments