Scraping Web Python - Sites Web dynamiques

Dans ce chapitre, apprenons comment effectuer du web scraping sur des sites Web dynamiques et les concepts impliqués en détail.

introduction

Le scraping Web est une tâche complexe et la complexité se multiplie si le site Web est dynamique. Selon l'audit mondial de l'accessibilité du Web des Nations Unies, plus de 70% des sites Web sont de nature dynamique et s'appuient sur JavaScript pour leurs fonctionnalités.

Exemple de site Web dynamique

Prenons un exemple de site Web dynamique et voyons pourquoi il est difficile de le gratter. Ici, nous allons prendre un exemple de recherche à partir d'un site Web nomméhttp://example.webscraping.com/places/default/search.Mais comment dire que ce site Web est de nature dynamique? Il peut être jugé à partir de la sortie du script Python suivant qui tentera de récupérer les données de la page Web mentionnée ci-dessus -

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)

Production

[ ]

La sortie ci-dessus montre que l'exemple de racleur n'a pas réussi à extraire les informations car l'élément <div> que nous essayons de trouver est vide.

Approches pour la récupération des données à partir de sites Web dynamiques

Nous avons vu que le grattoir ne peut pas extraire les informations d'un site Web dynamique car les données sont chargées dynamiquement avec JavaScript. Dans de tels cas, nous pouvons utiliser les deux techniques suivantes pour récupérer des données à partir de sites Web dynamiques dépendants de JavaScript:

  • Ingénierie inverse JavaScript
  • Rendu JavaScript

Ingénierie inverse JavaScript

Le processus appelé ingénierie inverse serait utile et nous permet de comprendre comment les données sont chargées dynamiquement par les pages Web.

Pour ce faire, nous devons cliquer sur le inspect elementonglet pour une URL spécifiée. Ensuite, nous allons cliquerNETWORK onglet pour trouver toutes les demandes faites pour cette page Web, y compris search.json avec un chemin de /ajax. Au lieu d'accéder aux données AJAX à partir du navigateur ou via l'onglet RÉSEAU, nous pouvons le faire à l'aide du script Python suivant également -

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

Exemple

Le script ci-dessus nous permet d'accéder à la réponse JSON en utilisant la méthode Python json. De même, nous pouvons télécharger la réponse de chaîne brute et en utilisant la méthode json.loads de python, nous pouvons la charger également. Nous faisons cela avec l'aide du script Python suivant. Il parcourra essentiellement tous les pays en recherchant la lettre de l'alphabet `` a '', puis en itérant les pages résultantes des réponses JSON.

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)))

Après avoir exécuté le script ci-dessus, nous obtiendrons la sortie suivante et les enregistrements seront enregistrés dans le fichier nommé countries.txt.

Production

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

Rendu JavaScript

Dans la section précédente, nous avons effectué une ingénierie inverse sur une page Web expliquant comment l'API fonctionnait et comment nous pouvons l'utiliser pour récupérer les résultats en une seule requête. Cependant, nous pouvons faire face aux difficultés suivantes lors de la rétro-ingénierie -

  • Parfois, les sites Web peuvent être très difficiles. Par exemple, si le site Web est créé avec un outil de navigateur avancé tel que Google Web Toolkit (GWT), le code JS résultant serait généré par la machine et difficile à comprendre et à effectuer de l'ingénierie inverse.

  • Certains cadres de niveau supérieur comme React.js peut rendre l'ingénierie inverse difficile en faisant abstraction d'une logique JavaScript déjà complexe.

La solution aux difficultés ci-dessus consiste à utiliser un moteur de rendu de navigateur qui analyse le HTML, applique le formatage CSS et exécute JavaScript pour afficher une page Web.

Exemple

Dans cet exemple, pour le rendu de Java Script, nous allons utiliser un module Python familier Selenium. Le code Python suivant rendra une page Web à l'aide de Selenium -

Tout d'abord, nous devons importer le pilote Web à partir du sélénium comme suit -

from selenium import webdriver

Maintenant, fournissez le chemin du pilote Web que nous avons téléchargé selon nos besoins -

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

Maintenant, fournissez l'url que nous voulons ouvrir dans ce navigateur Web maintenant contrôlé par notre script Python.

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

Maintenant, nous pouvons utiliser l'ID de la boîte à outils de recherche pour définir l'élément à sélectionner.

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

Ensuite, nous pouvons utiliser le script java pour définir le contenu de la boîte de sélection comme suit -

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

La ligne de code suivante montre que la recherche est prête à être cliquée sur la page Web -

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

La ligne de code suivante montre qu'elle attendra 45 secondes pour terminer la requête AJAX.

driver.implicitly_wait(45)

Maintenant, pour sélectionner les liens de pays, nous pouvons utiliser le sélecteur CSS comme suit -

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

Maintenant, le texte de chaque lien peut être extrait pour créer la liste des pays -

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