Wie kann ich eine Seite mit dynamischem Inhalt (erstellt durch JavaScript) in Python kratzen?

Lesezeit: 12 Minuten

Benutzeravatar von mocopera
mokopera

Ich versuche, einen einfachen Web-Scraper zu entwickeln. Ich möchte einfachen Text ohne HTML-Markup extrahieren. Mein Code funktioniert mit einfachem (statischem) HTML, aber nicht, wenn Inhalte durch in die Seite eingebettetes JavaScript generiert werden.

Insbesondere wenn ich benutze urllib2.urlopen(request) um den Seiteninhalt zu lesen, wird nichts angezeigt, was durch den JavaScript-Code hinzugefügt würde, da dieser Code wird nicht ausgeführt überall. Normalerweise würde es vom Webbrowser ausgeführt, aber das ist nicht Teil meines Programms.

Wie kann ich in meinem Python-Code auf diesen dynamischen Inhalt zugreifen?


Siehe auch Kann scrapy verwendet werden, um dynamische Inhalte von Websites zu entfernen, die AJAX verwenden? für Antworten speziell zu Scrapy.

  • Klingt so, als ob Sie etwas Schwereres brauchen könnten, versuchen Sie es mit Selenium oder Watir.

    – Wim

    8. November 2011 um 11:16 Uhr

  • Ich habe dies erfolgreich in Java gemacht (ich habe das Cobra-Toolkit verwendet lobobrowser.org/cobra.jsp) Da Sie in Python hacken möchten (immer eine gute Wahl), empfehle ich diese beiden Optionen: – packtpub.com/article/web-scraping-with-python-part-2blog.databigbang.com/web-scraping-ajax-and-javascript-sites

    – bpgergo

    8. November 2011 um 11:34 Uhr

  • Bitte beachten Sie, dass die am besten bewertete Antwort zuletzt im Jahr 2017 aktualisiert wurde und ab 2021 veraltet ist, da PhantomJS und Dryscrape veraltet sind. Ich empfehle, den gesamten Thread zu lesen, bevor Sie eine der empfohlenen Techniken ausprobieren.

    – ggorlen

    30. März 2021 um 21:46 Uhr

Benutzeravatar von avi
avi

EDIT September 2021: phantomjs wird auch nicht mehr gepflegt

BEARBEITEN 30. Dezember 2017: Diese Antwort erscheint in den Top-Ergebnissen der Google-Suche, daher habe ich beschlossen, sie zu aktualisieren. Die alte Antwort ist immer noch am Ende.

dryscape wird nicht mehr gepflegt und die von dryscape-Entwicklern empfohlene Bibliothek ist nur Python 2. Ich habe festgestellt, dass die Verwendung der Python-Bibliothek von Selenium mit Phantom JS als Webtreiber schnell genug und einfach ist, um die Arbeit zu erledigen.

Sobald Sie installiert haben Phantom JSStellen Sie sicher, dass phantomjs binär ist im aktuellen Pfad verfügbar:

phantomjs --version
# result:
2.1.1

#Example Um ein Beispiel zu geben, habe ich eine Beispielseite mit folgendem HTML-Code erstellt. (Verknüpfung):

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Javascript scraping test</title>
</head>
<body>
  <p id='intro-text'>No javascript support</p>
  <script>
     document.getElementById('intro-text').innerHTML = 'Yay! Supports javascript';
  </script> 
</body>
</html>

Ohne Javascript heißt es: No javascript support und mit Javascript: Yay! Supports javascript

#Scraping ohne JS-Unterstützung:

import requests
from bs4 import BeautifulSoup
response = requests.get(my_url)
soup = BeautifulSoup(response.text)
soup.find(id="intro-text")
# Result:
<p id="intro-text">No javascript support</p>

#Scraping mit JS-Unterstützung:

from selenium import webdriver
driver = webdriver.PhantomJS()
driver.get(my_url)
p_element = driver.find_element_by_id(id_='intro-text')
print(p_element.text)
# result:
'Yay! Supports javascript'

Sie können auch die Python-Bibliothek verwenden trockenkratzen Javascript-gesteuerte Websites zu schaben.

#Scraping mit JS-Unterstützung:

import dryscrape
from bs4 import BeautifulSoup
session = dryscrape.Session()
session.visit(my_url)
response = session.body()
soup = BeautifulSoup(response)
soup.find(id="intro-text")
# Result:
<p id="intro-text">Yay! Supports javascript</p>

  • Leider keine Windows-Unterstützung.

    – Auslagen

    17. April 2017 um 14:39 Uhr

  • @Expenzor Ich arbeite an Windows. PhantomJS funktioniert einwandfrei.

    – Aakash Choubey

    12. Januar 2018 um 10:43 Uhr


  • Erwähnenswert ist, dass PhantomJS eingestellt wurde und nicht mehr aktiv weiterentwickelt wird, da Chrome jetzt Headless unterstützt. Die Verwendung von Headless Chrome/Firefox wird empfohlen.

    – Sytech

    23. März 2018 um 20:42 Uhr

  • Ich bekomme folgende Warnung: Selenium support for PhantomJS has been deprecated, please use headless versions of Chrome or Firefox instead. Vielleicht hat @sytech von Selenium-Unterstützung gesprochen?

    – jpmc26

    30. April 2018 um 4:37 Uhr


  • Es ist sowohl die Selen-Unterstützung als auch PhantomJS selbst. github.com/ariya/phantomjs/issues/15344

    – Sytech

    30. April 2018 um 12:34 Uhr


Benutzeravatar von John Moutafis
John Moutafis

Wir erhalten nicht die richtigen Ergebnisse, da alle mit Javascript generierten Inhalte auf dem DOM gerendert werden müssen. Wenn wir eine HTML-Seite abrufen, rufen wir das anfängliche, nicht durch Javascript modifizierte DOM ab.

Daher müssen wir den Javascript-Inhalt rendern, bevor wir die Seite crawlen.

Da Selen in diesem Thread schon oft erwähnt wurde (und wie langsam es manchmal wird, wurde auch erwähnt), werde ich zwei andere mögliche Lösungen auflisten.


Lösung 1: Dies ist ein sehr schönes Tutorial auf wie man Scrapy verwendet, um mit Javascript generierte Inhalte zu crawlen und wir werden genau dem folgen.

Was wir brauchen:

  1. Docker in unserer Maschine installiert. Dies ist bis zu diesem Punkt ein Plus gegenüber anderen Lösungen, da es eine vom Betriebssystem unabhängige Plattform verwendet.

  2. Splash installieren Befolgen Sie die Anweisungen für unser entsprechendes Betriebssystem.
    Zitat aus Splash-Dokumentation:

    Splash ist ein Javascript-Rendering-Dienst. Es ist ein leichter Webbrowser mit einer HTTP-API, implementiert in Python 3 mit Twisted und QT5.

    Im Wesentlichen werden wir Splash verwenden, um mit Javascript generierte Inhalte zu rendern.

  3. Führen Sie den Splash-Server aus: sudo docker run -p 8050:8050 scrapinghub/splash.

  4. Installiere das kratziges Spritzen Plugin: pip install scrapy-splash

  5. Angenommen, wir haben bereits ein Scrapy-Projekt erstellt (falls nicht, lass uns einen machen), werden wir der Anleitung folgen und die aktualisieren settings.py:

    Dann gehen Sie zu Ihrem Scrapy-Projekt settings.py und legen Sie diese Middlewares fest:

    DOWNLOADER_MIDDLEWARES = {
          'scrapy_splash.SplashCookiesMiddleware': 723,
          'scrapy_splash.SplashMiddleware': 725,
          'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810,
    }
    

    Die URL des Splash-Servers (wenn Sie Win oder OSX verwenden, sollte dies die URL des Docker-Computers sein: How to get a Docker container’s IP address from the host?):

    SPLASH_URL = 'http://localhost:8050'
    

    Und schließlich müssen Sie auch diese Werte festlegen:

    DUPEFILTER_CLASS = 'scrapy_splash.SplashAwareDupeFilter'
    HTTPCACHE_STORAGE = 'scrapy_splash.SplashAwareFSCacheStorage'
    
  6. Schließlich können wir a verwenden SplashRequest:

    In einem normalen Spider haben Sie Request-Objekte, mit denen Sie URLs öffnen können. Wenn die Seite, die Sie öffnen möchten, JS-generierte Daten enthält, müssen Sie SplashRequest (oder SplashFormRequest) verwenden, um die Seite zu rendern. Hier ist ein einfaches Beispiel:

    class MySpider(scrapy.Spider):
        name = "jsscraper"
        start_urls = ["http://quotes.toscrape.com/js/"]
    
        def start_requests(self):
            for url in self.start_urls:
            yield SplashRequest(
                url=url, callback=self.parse, endpoint="render.html"
            )
    
        def parse(self, response):
            for q in response.css("div.quote"):
            quote = QuoteItem()
            quote["author"] = q.css(".author::text").extract_first()
            quote["quote"] = q.css(".text::text").extract_first()
            yield quote
    

    SplashRequest rendert die URL als HTML und gibt die Antwort zurück, die Sie in der callback(parse)-Methode verwenden können.


Lösung 2: Nennen wir das im Moment (Mai 2018) experimentell…
Diese Lösung ist für Pythons Version 3.6 nur (im Moment).

Kennst du Anfragen Modul (gut, wer nicht)?
Jetzt hat es ein kleines Geschwisterchen, das das Web durchsucht: Anfragen-HTML:

Diese Bibliothek soll das Parsen von HTML (zB das Scrapen des Webs) so einfach und intuitiv wie möglich machen.

  1. Requests-html installieren: pipenv install requests-html

  2. Stellen Sie eine Anfrage an die URL der Seite:

    from requests_html import HTMLSession
    
    session = HTMLSession()
    r = session.get(a_page_url)
    
  3. Rendern Sie die Antwort, um die von Javascript generierten Bits zu erhalten:

    r.html.render()
    

Endlich scheint sich das Modul zu bieten Schabefähigkeiten.
Alternativ können wir den gut dokumentierten Weg versuchen der Verwendung von BeautifulSoup mit dem r.html Objekt, das wir gerade gerendert haben.

  • Können Sie erläutern, wie Sie nach dem Aufruf von .render() den vollständigen HTML-Inhalt mit geladenen JS-Bits erhalten? Nach diesem Punkt stecke ich fest. Ich sehe nicht alle iFrames, die normalerweise von JavaScript in die Seite eingefügt werden r.html.html Objekt.

    – fIwJlxSzAPHEZIl

    13. Dezember 2018 um 20:24 Uhr

  • @anon58192932 Da dies im Moment eine experimentelle Lösung ist und ich nicht weiß, was genau Sie damit erreichen möchten, kann ich nicht wirklich etwas vorschlagen … Sie können hier auf SO eine neue Frage erstellen, wenn Sie dies nicht getan haben noch eine Lösung gefunden

    – John Moutafis

    2. Januar 2019 um 13:57 Uhr

  • Ich habe diesen Fehler erhalten: RuntimeError: HTMLSession kann nicht innerhalb einer vorhandenen Ereignisschleife verwendet werden. Verwenden Sie stattdessen AsyncHTMLSession.

    – Joshua Stafford

    23. April 2019 um 15:59 Uhr

  • @HuckIt das scheint ein bekanntes Problem zu sein: github.com/psf/requests-html/issues/140

    – John Moutafis

    15. Oktober 2019 um 12:22 Uhr

  • Ich habe die erste Methode ausprobiert, aber ich kann immer noch keine js-gerenderten Inhalte sehen? Können Sie mir bitte sagen, was mir fehlt.

    – AlixaProDev

    12. Juli 2022 um 16:41 Uhr

Vielleicht Selen kann es tun.

from selenium import webdriver
import time

driver = webdriver.Firefox()
driver.get(url)
time.sleep(5)
htmlSource = driver.page_source

  • Selenium ist für solche Dinge wirklich schwer, das wäre unnötig langsam und erfordert einen Browserkopf, wenn Sie PhantomJS nicht verwenden, aber das würde funktionieren.

    – Joshua Hedges

    28. Juli 2017 um 16:27 Uhr

  • @JoshuaHedges Sie können andere Standardbrowser im Headless-Modus ausführen.

    – reynoldsnlp

    9. Januar 2020 um 0:55 Uhr

  • options = webdriver.ChromeOptions() options.add_argument('--headless') driver = webdriver.Chrome(options=options)

    – fantastisch

    15. Oktober 2020 um 14:50 Uhr


Benutzeravatar von SShah
SSchah

Wenn Sie die jemals verwendet haben Requests module for python zuvor habe ich kürzlich herausgefunden, dass der Entwickler ein neues Modul namens erstellt hat Requests-HTML die jetzt auch die Fähigkeit hat, JavaScript zu rendern.

Sie können auch besuchen https://html.python-requests.org/ Um mehr über dieses Modul zu erfahren, oder wenn Sie nur am Rendern von JavaScript interessiert sind, können Sie besuchen https://html.python-requests.org/?#javascript-support um direkt zu lernen, wie man das Modul zum Rendern von JavaScript mit Python verwendet.

Im Wesentlichen, sobald Sie die Requests-HTML Modul, das folgende Beispiel, das ist auf dem obigen Link angezeigtzeigt, wie Sie dieses Modul verwenden können, um eine Website zu scrapen und in der Website enthaltenes JavaScript zu rendern:

from requests_html import HTMLSession
session = HTMLSession()

r = session.get('http://python-requests.org/')

r.html.render()

r.html.search('Python 2 will retire in only {months} months!')['months']

'<time>25</time>' #This is the result.

Das habe ich kürzlich durch ein YouTube-Video erfahren. Klicken Sie hier! um das YouTube-Video anzusehen, das die Funktionsweise des Moduls demonstriert.

Es hört sich so an, als ob auf die Daten, nach denen Sie wirklich suchen, über eine sekundäre URL zugegriffen werden kann, die von einem JavaScript auf der Primärseite aufgerufen wird.

Während Sie versuchen könnten, Javascript auf dem Server auszuführen, um dies zu handhaben, könnte ein einfacherer Ansatz darin bestehen, die Seite mit Firefox zu laden und ein Tool wie zu verwenden Karl oder Feuerwanze um genau zu identifizieren, was diese sekundäre URL ist. Dann können Sie diese URL einfach direkt nach den Daten abfragen, an denen Sie interessiert sind.

  • @Kris Nur für den Fall, dass jemand darüber stolpert und es anstelle von etwas so Schwerem wie Selen ausprobieren möchte, hier ist ein kurzes Beispiel. Das öffnet die Teiledetailseite für eine Sechskantmutter auf der McMaster-Carr-Website. Der Inhalt ihrer Website wird hauptsächlich mit Javascript abgerufen und enthält nur sehr wenige native Seiteninformationen. Wenn Sie die Entwicklertools Ihres Browsers öffnen, zur Registerkarte „Netzwerk“ navigieren und die Seite aktualisieren, können Sie alle von der Seite gestellten Anforderungen sehen und die relevanten Daten finden (in diesem Fall die Teildetail-HTML).

    – SweepingsDemon

    13. August 2018 um 18:02 Uhr


  • Das ist eine andere URL, die auf der Registerkarte Netzwerk des Firefox-Devtools zu finden ist, die, wenn sie befolgt wird, den HTML-Code für die meisten Teilinformationen enthält und einige der Parameter offenlegt, die erforderlich sind, um einfach zu anderen Teilinformationen zu navigieren, um das Scraping zu erleichtern. Dieses spezielle Beispiel ist nicht besonders nützlich, da der Preis von einer anderen Javascript-Funktion generiert wird, sollte aber als Einführung für alle dienen, die Stephens Rat befolgen möchten.

    – SweepingsDemon

    13. August 2018 um 18:10 Uhr


Robbies Benutzeravatar
Robbie

Dies scheint auch eine gute Lösung zu sein, entnommen aus a toller Blogbeitrag

import sys  
from PyQt4.QtGui import *  
from PyQt4.QtCore import *  
from PyQt4.QtWebKit import *  
from lxml import html 

#Take this class for granted.Just use result of rendering.
class Render(QWebPage):  
  def __init__(self, url):  
    self.app = QApplication(sys.argv)  
    QWebPage.__init__(self)  
    self.loadFinished.connect(self._loadFinished)  
    self.mainFrame().load(QUrl(url))  
    self.app.exec_()  

  def _loadFinished(self, result):  
    self.frame = self.mainFrame()  
    self.app.quit()  

url="http://pycoders.com/archive/"  
r = Render(url)  
result = r.frame.toHtml()
# This step is important.Converting QString to Ascii for lxml to process

# The following returns an lxml element tree
archive_links = html.fromstring(str(result.toAscii()))
print archive_links

# The following returns an array containing the URLs
raw_links = archive_links.xpath('//div[@class="campaign"]/a/@href')
print raw_links

  • @Kris Nur für den Fall, dass jemand darüber stolpert und es anstelle von etwas so Schwerem wie Selen ausprobieren möchte, hier ist ein kurzes Beispiel. Das öffnet die Teiledetailseite für eine Sechskantmutter auf der McMaster-Carr-Website. Der Inhalt ihrer Website wird hauptsächlich mit Javascript abgerufen und enthält nur sehr wenige native Seiteninformationen. Wenn Sie die Entwicklertools Ihres Browsers öffnen, zur Registerkarte „Netzwerk“ navigieren und die Seite aktualisieren, können Sie alle von der Seite gestellten Anforderungen sehen und die relevanten Daten finden (in diesem Fall die Teildetail-HTML).

    – SweepingsDemon

    13. August 2018 um 18:02 Uhr


  • Das ist eine andere URL, die auf der Registerkarte Netzwerk des Firefox-Devtools zu finden ist, die, wenn sie befolgt wird, den HTML-Code für die meisten Teilinformationen enthält und einige der Parameter offenlegt, die erforderlich sind, um einfach zu anderen Teilinformationen zu navigieren, um das Scraping zu erleichtern. Dieses spezielle Beispiel ist nicht besonders nützlich, da der Preis von einer anderen Javascript-Funktion generiert wird, sollte aber als Einführung für alle dienen, die Stephens Rat befolgen möchten.

    – SweepingsDemon

    13. August 2018 um 18:10 Uhr


Benutzeravatar von seco
seco

Selen eignet sich am besten zum Scrapen von JS- und Ajax-Inhalten.

Überprüfen Sie diesen Artikel auf Extrahieren von Daten aus dem Web mit Python

$ pip install selenium

Laden Sie dann den Chrome-Webtreiber herunter.

from selenium import webdriver

browser = webdriver.Chrome()

browser.get("https://www.python.org/")

nav = browser.find_element_by_id("mainnav")

print(nav.text)

Einfach richtig?

  • Selen ist am besten, aber einige Websites scheinen die Verwendung von Selen zu erkennen.

    – Jawad Ahmad Khan

    26. August 2020 um 5:21 Uhr

  • Ich denke die wirst du auch brauchen Chromtreiber auf Ihrem PATH, damit dies funktioniert.

    – wsams

    1. November 2022 um 16:08 Uhr


1448690cookie-checkWie kann ich eine Seite mit dynamischem Inhalt (erstellt durch JavaScript) in Python kratzen?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy