Wie kratzt man eine Javascript-Website in Python?

Sep 06 2020

Ich versuche eine Website zu kratzen. Ich habe versucht, zwei Methoden zu verwenden, aber beide liefern mir nicht den vollständigen Website-Quellcode, den ich suche. Ich versuche, die Nachrichtentitel von der unten angegebenen Website-URL zu entfernen.

URL: "https://www.todayonline.com/"

Dies sind die beiden Methoden, die ich ausprobiert habe, aber fehlgeschlagen bin.

Methode 1: Schöne Suppe

tdy_url = "https://www.todayonline.com/"
page = requests.get(tdy_url).text
soup = BeautifulSoup(page)
soup  # Returns me a HTML with javascript text
soup.find_all('h3')

### Returns me empty list []

Methode 2: Selen + BeautifulSoup

tdy_url = "https://www.todayonline.com/"

options = Options()
options.headless = True

driver = webdriver.Chrome("chromedriver",options=options)

driver.get(tdy_url)
time.sleep(10)
html = driver.page_source

soup = BeautifulSoup(html)
soup.find_all('h3')

### Returns me only less than 1/4 of the 'h3' tags found in the original page source 

Bitte helfen Sie. Ich habe versucht, andere Nachrichten-Websites zu kratzen, und es ist so viel einfacher. Vielen Dank.

Antworten

2 politicalscientist Sep 06 2020 at 15:38

Sie können über die API auf Daten zugreifen (siehe Registerkarte Netzwerk):


Zum Beispiel,

import requests
url = "https://www.todayonline.com/api/v3/news_feed/7"
data = requests.get(url).json()
2 Noname Sep 06 2020 at 15:39

Es gibt verschiedene Möglichkeiten, den Inhalt einer Webseite zu erfassen, die Javascript enthält.

  1. Verwendung seleniummit dem Firefox-Webtreiber
  2. Verwenden eines Headless-Browsers mit phantomJS
  3. Ausführen eines API-Aufrufs mithilfe eines REST-Clients oder einer Python- requestsBibliothek

Sie müssen zuerst Ihre Forschung tun

2 MananGajjar Sep 06 2020 at 16:04

Ich werde Ihnen den ziemlich einfachen Ansatz vorschlagen,

import requests
from bs4 import BeautifulSoup as bs

page = requests.get('https://www.todayonline.com/googlenews.xml').content
soup = bs(page)
news = [i.text for i in soup.find_all('news:title')]

print(news)

Ausgabe

['DBS named world’s best bank by New York-based financial publication',
 'Russia has very serious questions to answer on Navalny - UK',
 "Exclusive: 90% of China's Sinovac employees, families took coronavirus vaccine - CEO",
 'Three militants killed after fatal attack on policeman in Tunisia',
.....]

Bei Bedarf können Sie auch auf der XML-Seite nach weiteren Informationen suchen.

PS Überprüfen Sie immer die Konformität, bevor Sie eine Website verschrotten :)

2 DemianWolf Sep 06 2020 at 16:00

Die Nachrichtendaten auf der Website, die Sie kratzen möchten, werden mithilfe von JavaScript vom Server abgerufen (dies wird als XHR - XMLHttpRequest bezeichnet ). Dies geschieht dynamisch, während die Seite geladen oder gescrollt wird. Daher werden diese Daten nicht innerhalb der vom Server zurückgegebenen Seite zurückgegeben.

Im ersten Beispiel erhalten Sie nur die vom Server zurückgegebene Seite - ohne die Nachrichten, aber mit JS, das sie erhalten soll. Weder Anfragen noch BeautifulSoup können JS ausführen.

Sie können jedoch versuchen, Anforderungen, die Nachrichtentitel vom Server erhalten, mit Python-Anforderungen zu reproduzieren. Führen Sie die folgenden Schritte aus:

  1. Öffnen Sie DevTools Ihres Browsers (normalerweise müssen Sie dafür F12oder Ctrl+ Shit+ drücken I) und sehen Sie sich Anfragen an, die Nachrichtentitel vom Server erhalten. Manchmal ist es sogar einfacher als Web Scraping mit BeautifulSoup. Hier ist ein Screenshot (Firefox):
  1. Kopieren Sie den Anforderungslink (Rechtsklick -> Kopieren -> Link kopieren) und übergeben Sie ihn an requests.get(...).

  2. Holen Sie sich .json()von der Anfrage. Es wird ein Diktat zurückgegeben, mit dem man leicht arbeiten kann. Um die Struktur des Diktats besser zu verstehen, würde ich empfehlen, pprintanstelle des einfachen Drucks zu verwenden. Beachten Sie, dass Sie dies tun müssen, from pprint import pprintbevor Sie es verwenden.

Hier ist ein Beispiel für den Code, mit dem die Titel aus den Hauptnachrichten auf der Seite abgerufen werden:

import requests


nodes = requests.get("https://www.todayonline.com/api/v3/news_feed/7")\
        .json()["nodes"]
for node in nodes:
    print(node["node"]["title"])

Wenn Sie eine Gruppe von Nachrichten unter Beschriftung kratzen möchten, müssen Sie die Nummer nach news_feed/in der Anforderungs-URL ändern (um sie zu erhalten, müssen Sie nur die Anforderungen nach "news_feed" in den DevTools filtern und die Nachrichtenseite nach unten scrollen).

Manchmal sind Websites vor Bots geschützt (obwohl die Website, die Sie kratzen möchten, dies nicht tut). In solchen Fällen müssen Sie möglicherweise auch diese Schritte ausführen.