Python Web Scraping - Dynamische Websites

In diesem Kapitel erfahren Sie, wie Sie Web-Scraping auf dynamischen Websites durchführen und welche Konzepte im Detail verwendet werden.

Einführung

Web Scraping ist eine komplexe Aufgabe und die Komplexität vervielfacht sich, wenn die Website dynamisch ist. Laut dem Global Audit of Web Accessibility der Vereinten Nationen sind mehr als 70% der Websites dynamischer Natur und verlassen sich für ihre Funktionen auf JavaScript.

Beispiel für eine dynamische Website

Schauen wir uns ein Beispiel für eine dynamische Website an und wissen, warum es schwierig ist, zu kratzen. Hier nehmen wir ein Beispiel für die Suche auf einer Website mit dem Namenhttp://example.webscraping.com/places/default/search.Aber wie können wir sagen, dass diese Website dynamischer Natur ist? Es kann anhand der Ausgabe des folgenden Python-Skripts beurteilt werden, das versucht, Daten von der oben genannten Webseite zu kratzen -

import re
import urllib.request
response = urllib.request.urlopen('http://example.webscraping.com/places/default/search')
html = response.read()
text = html.decode()
re.findall('(.*?)',text)

Ausgabe

[ ]

Die obige Ausgabe zeigt, dass der Beispiel-Scraper keine Informationen extrahieren konnte, weil das <div> -Element, das wir suchen, leer ist.

Ansätze zum Scraping von Daten von dynamischen Websites

Wir haben gesehen, dass der Scraper die Informationen von einer dynamischen Website nicht kratzen kann, da die Daten dynamisch mit JavaScript geladen werden. In solchen Fällen können wir die folgenden zwei Techniken zum Scrapen von Daten von dynamischen JavaScript-abhängigen Websites verwenden:

  • Reverse Engineering JavaScript
  • JavaScript rendern

Reverse Engineering JavaScript

Der als Reverse Engineering bezeichnete Prozess wäre nützlich und lässt uns verstehen, wie Daten dynamisch von Webseiten geladen werden.

Dazu müssen wir auf das klicken inspect elementRegisterkarte für eine angegebene URL. Als nächstes werden wir klickenNETWORK Registerkarte, um alle für diese Webseite gestellten Anforderungen einschließlich search.json mit dem Pfad von zu finden /ajax. Anstatt über den Browser oder über die Registerkarte NETWORK auf AJAX-Daten zuzugreifen, können wir dies auch mithilfe des folgenden Python-Skripts tun -

import requests
url=requests.get('http://example.webscraping.com/ajax/search.json?page=0&page_size=10&search_term=a')
url.json()

Beispiel

Mit dem obigen Skript können wir mithilfe der Python-json-Methode auf die JSON-Antwort zugreifen. In ähnlicher Weise können wir die Antwort auf die Rohzeichenfolge herunterladen und mithilfe der json.loads-Methode von Python auch laden. Wir tun dies mit Hilfe des folgenden Python-Skripts. Grundsätzlich werden alle Länder durchsucht, indem der Buchstabe des Alphabets 'a' durchsucht und dann die resultierenden Seiten der JSON-Antworten wiederholt werden.

import requests
import string
PAGE_SIZE = 15
url = 'http://example.webscraping.com/ajax/' + 'search.json?page={}&page_size={}&search_term=a'
countries = set()
for letter in string.ascii_lowercase:
   print('Searching with %s' % letter)
   page = 0
   while True:
   response = requests.get(url.format(page, PAGE_SIZE, letter))
   data = response.json()
   print('adding %d records from the page %d' %(len(data.get('records')),page))
   for record in data.get('records'):countries.add(record['country'])
   page += 1
   if page >= data['num_pages']:
      break
   with open('countries.txt', 'w') as countries_file:
   countries_file.write('n'.join(sorted(countries)))

Nach dem Ausführen des obigen Skripts erhalten wir die folgende Ausgabe und die Datensätze werden in der Datei mit dem Namen country.txt gespeichert.

Ausgabe

Searching with a
adding 15 records from the page 0
adding 15 records from the page 1
...

JavaScript rendern

Im vorherigen Abschnitt haben wir auf der Webseite ein Reverse Engineering durchgeführt, in dem erläutert wurde, wie die API funktioniert und wie wir sie verwenden können, um die Ergebnisse in einer einzelnen Anforderung abzurufen. Beim Reverse Engineering können wir jedoch auf folgende Schwierigkeiten stoßen:

  • Manchmal können Websites sehr schwierig sein. Wenn die Website beispielsweise mit einem erweiterten Browser-Tool wie Google Web Toolkit (GWT) erstellt wird, wird der resultierende JS-Code maschinell generiert und ist schwer zu verstehen und zurückzuentwickeln.

  • Einige übergeordnete Frameworks mögen React.js kann das Reverse Engineering erschweren, indem bereits komplexe JavaScript-Logik abstrahiert wird.

Die Lösung für die oben genannten Schwierigkeiten besteht darin, eine Browser-Rendering-Engine zu verwenden, die HTML analysiert, die CSS-Formatierung anwendet und JavaScript zum Anzeigen einer Webseite ausführt.

Beispiel

In diesem Beispiel verwenden wir zum Rendern von Java Script ein bekanntes Python-Modul Selenium. Der folgende Python-Code rendert eine Webseite mit Hilfe von Selenium -

Zuerst müssen wir den Webdriver wie folgt aus Selen importieren:

from selenium import webdriver

Geben Sie nun den Pfad des Webtreibers an, den wir gemäß unserer Anforderung heruntergeladen haben.

path = r'C:\\Users\\gaurav\\Desktop\\Chromedriver'
driver = webdriver.Chrome(executable_path = path)

Geben Sie nun die URL an, die wir in diesem Webbrowser öffnen möchten, der jetzt von unserem Python-Skript gesteuert wird.

driver.get('http://example.webscraping.com/search')

Jetzt können wir die ID der Such-Toolbox verwenden, um das auszuwählende Element festzulegen.

driver.find_element_by_id('search_term').send_keys('.')

Als nächstes können wir das Java-Skript verwenden, um den Inhalt des Auswahlfelds wie folgt festzulegen:

js = "document.getElementById('page_size').options[1].text = '100';"
driver.execute_script(js)

Die folgende Codezeile zeigt, dass die Suche auf der Webseite angeklickt werden kann -

driver.find_element_by_id('search').click()

Die nächste Codezeile zeigt, dass 45 Sekunden auf das Abschließen der AJAX-Anforderung gewartet wird.

driver.implicitly_wait(45)

Für die Auswahl von Länderlinks können wir nun den CSS-Selektor wie folgt verwenden:

links = driver.find_elements_by_css_selector('#results a')

Jetzt kann der Text jedes Links extrahiert werden, um die Liste der Länder zu erstellen -

countries = [link.text for link in links]
print(countries)
driver.close()