Seite 1 von 1

Scraping JS generierte HTML-Elemente mit BeautifulSoup

Verfasst: Samstag 24. April 2021, 21:55
von TenchiMuyo1984
Hallo zusammen,
ich habe ein Problem mit dem Scraping von JavaScript-generierten HTML-Elementen.

Wenn ich den HTML-Quelltext anschaue, steht das darin:
(ein Auszug)

Code: Alles auswählen

<div class="other_item"></div>

<div class="recomend">
    <h4>Recommend items</h4>
    <div class="recommend_edi"></div>
    <div class="recommend_aix"></div>
</div>

<div class="recomend">
    <h4>Other items from this category</h4>
    <div class="recommend_same_category thumsmall"></div>
</div>
Dann habe ich mir das mal über die "Untersuchen"-Funktion von Google-Chrome angeschaut, und da steht dies darin:
Bild
Wie man sehen kann, bedeutend mehr.
Jetzt meine Frage. Wie kann ich die Inhalte auslesen?

Habe bereits folgendes probiert:
1. selenium:

Code: Alles auswählen

from selenium import webdriver
from selenium.webdriver.chrome.service import Service

service = Service('C:\Webdrivers\chromedriver.exe')
service.start()
driver = webdriver.Remote(service.service_url)
driver.get('url zensiert')
Klappt nicht immer vollständig.
Das liegt daran, dass der Browser den Erfolg des Ladens zurück meldet, obwohl das Generieren über JS noch nicht abgeschlossen ist.
Je nach Timing habe ich von den generierten Elementen zwischen 0 und 100% verfügbar.
Darum kann ich nicht darauf vertrauen.
Ich weiß auch nicht, wie ich die Wartezeit verlängern kann. Der Browser sendet "fertig" zurück, obwohl die JS-Elemente noch nicht fertig generiert wurden.

2. requests_html:

Code: Alles auswählen

from bs4 import BeautifulSoup
from requests_html import HTMLSession

session = HTMLSession()
resp = session.get('url zensiert')
resp.html.render()
soup = BeautifulSoup(resp.html.html, 'lxml')
Klappt nicht. Ich bekomme nur den normalen Quelltext, ohne die JS-Ergänzungen zurück.

3. PyQt5

Code: Alles auswählen

from bs4 import BeautifulSoup
from requests_html import HTMLSession
import requests
import time

import sys
from PyQt5.QtWidgets import QApplication
from PyQt5.QtCore import QUrl
from PyQt5.QtWebEngineWidgets import QWebEnginePage


class Page(QWebEnginePage):

    def __init__(self, url):
        self.app = QApplication(sys.argv)
        QWebEnginePage.__init__(self)
        self.loadFinished.connect(self.on_load_finished)
        self.load(QUrl(url))
        self.app.exec_()

    def on_load_finished(self):
        self.html = self.toHtml(self.Callable)
        print('Load Finished')

    def Callable(self, html_str):
        self.html = html_str
        self.app.quit()
        
page = Page('url zensiert')
soup = BeautifulSoup(page.html, 'lxml')
Klappt nicht. Ich bekomme nur den normalen Quelltext, ohne die JS-Ergänzungen zurück.

Ich hoffe mir kann jemand dabei helfen :(

Grüße
TenchiMuyo1984

Re: Scraping JS generierte HTML-Elemente mit BeautifulSoup

Verfasst: Montag 26. April 2021, 06:49
von Sirius3
Wenn Du wirklich die Seite scrappen willst, ist Selenium schon das richtige. Du mußt halt so lange warten, bis alle Daten geladen sind.

Re: Scraping JS generierte HTML-Elemente mit BeautifulSoup

Verfasst: Montag 26. April 2021, 08:56
von TenchiMuyo1984
Moin und danke für die Rückmeldung,

das mit dem Warten ist mir schon klar, aber wie mache ich das?
Mein Problem ist der Befehl:

Code: Alles auswählen

driver.get('url zensiert')
So wie ich das verstanden und auch gesehen habe, liefert die Methode get() den Inhalt der HTML-Seite zurück, wenn der

Code: Alles auswählen

service = Service('C:\Webdrivers\chromedriver.exe')
in diesem Fall der Google-Chrome über den chromedriver alle HTML-Elemente geladen hat.
Die Generierung der "fehlenden" HTML-Elemente mittels JS ist da aber noch nicht beendet.

Habe da auch schon mit Wartezeiten gearbeitet:

Code: Alles auswählen

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
import time

service = Service('C:\Webdrivers\chromedriver.exe')
time.sleep(10) # macht hier keinen Sinn, weil ich noch keine URL aufgerufen habe.
service.start()
time.sleep(10) # macht hier keinen Sinn, weil ich noch keine URL aufgerufen habe.
driver = webdriver.Remote(service.service_url)
time.sleep(10) # macht hier keinen Sinn, weil ich noch keine URL aufgerufen habe.
driver.get('url zensiert')
time.sleep(10) # Hier ist der einzige Punkt bei dem es Sinn machen würde, funktioniert aber nicht...
Hilft nicht.

Ebenso die drei in selenium eingebaute methoden:
  • Implicit Wait
  • Explicit Wait
  • Fluent Wait
klappen auch nicht.
Selbst wenn ich die Wartezeit auf 10 Minuten (ja, richtig, Minuten) stelle, braucht die gesamte Ausführung nur ~42 Sekunden (inkl. der vier: "time.sleep(10)").
Somit werden diese jeweiligen 10 Minuten ignoriert.

PyQt5 ~ 4,5 Sekunden
requests_html ~ 4 Sekunden

Ich grübel über dieses Problem nun schon seit fast 2 Wochen. :(

Grüße
TenchiMuyo1984

Re: Scraping JS generierte HTML-Elemente mit BeautifulSoup

Verfasst: Montag 26. April 2021, 09:37
von Sirius3
Ein "klappen auch nicht" ist wenig hilfreich. Wenn Du konkrete Hilfe willst, mußt Du konkreter werden.

Re: Scraping JS generierte HTML-Elemente mit BeautifulSoup

Verfasst: Montag 26. April 2021, 09:55
von TenchiMuyo1984
Sirius3 hat geschrieben: Montag 26. April 2021, 09:37 Ein "klappen auch nicht" ist wenig hilfreich. Wenn Du konkrete Hilfe willst, mußt Du konkreter werden.
STeht doch da Oo
klappen auch nicht.
Selbst wenn ich die Wartezeit auf 10 Minuten (ja, richtig, Minuten) stelle, braucht die gesamte Ausführung nur ~42 Sekunden (inkl. der vier: "time.sleep(10)").
Somit werden diese jeweiligen 10 Minuten ignoriert.
Grüße
TenchiMuyo1984

Re: Scraping JS generierte HTML-Elemente mit BeautifulSoup

Verfasst: Montag 26. April 2021, 10:41
von __deets__
Die drei Selenium-Waits sind der Weg Das du die irgendwie versucht hast zu verwenden ist ja schoen, aber man sieht nicht, wie - also kann man auch nur sagen 'benutz die'. Oder zeig eben, was du *wirklich* tust.