Веб-парсинг Python - динамические веб-сайты

В этой главе давайте узнаем, как выполнять парсинг на динамических веб-сайтах, и подробно изучим используемые концепции.

Введение

Парсинг веб-страниц - сложная задача, и сложность возрастает, если веб-сайт является динамическим. Согласно Глобальному аудиту веб-доступности Организации Объединенных Наций, более 70% веб-сайтов являются динамическими по своей природе, и для их функций используется JavaScript.

Пример динамического веб-сайта

Давайте посмотрим на пример динамического веб-сайта и узнаем, почему его сложно очистить. Здесь мы собираемся взять пример поиска с веб-сайта с именемhttp://example.webscraping.com/places/default/search.Но как мы можем сказать, что этот сайт носит динамический характер? Об этом можно судить по выводам следующего скрипта Python, который попытается очистить данные с вышеупомянутой веб-страницы -

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)

Вывод

[ ]

Приведенный выше вывод показывает, что пример скребка не смог извлечь информацию, потому что элемент <div>, который мы пытаемся найти, пуст.

Подходы к извлечению данных с динамических веб-сайтов

Мы видели, что парсер не может очистить информацию с динамического веб-сайта, потому что данные загружаются динамически с помощью JavaScript. В таких случаях мы можем использовать следующие два метода для извлечения данных с динамических сайтов, зависящих от JavaScript:

  • Обратный инжиниринг JavaScript
  • Рендеринг JavaScript

Обратный инжиниринг JavaScript

Был бы полезен процесс, называемый обратным проектированием, который позволяет нам понять, как данные динамически загружаются веб-страницами.

Для этого нам нужно щелкнуть inspect elementвкладка для указанного URL. Далее мы нажмемNETWORK вкладка, чтобы найти все запросы, сделанные для этой веб-страницы, включая search.json с путем /ajax. Вместо доступа к данным AJAX из браузера или через вкладку NETWORK, мы можем сделать это также с помощью следующего скрипта Python -

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

пример

Приведенный выше скрипт позволяет нам получить доступ к ответу JSON с помощью метода Python json. Точно так же мы можем загрузить необработанный строковый ответ и, используя метод python json.loads, мы также можем загрузить его. Мы делаем это с помощью следующего скрипта Python. Он будет в основном очищать все страны, выполняя поиск по букве алфавита «а», а затем повторяя полученные страницы ответов 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)))

После запуска приведенного выше сценария мы получим следующий результат, и записи будут сохранены в файле с именем country.txt.

Вывод

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

Рендеринг JavaScript

В предыдущем разделе мы провели обратный инжиниринг на веб-странице, чтобы узнать, как работает API и как мы можем использовать его для получения результатов в одном запросе. Однако при выполнении обратного проектирования мы можем столкнуться со следующими трудностями:

  • Иногда веб-сайты могут быть очень сложными. Например, если веб-сайт создан с помощью расширенного инструмента браузера, такого как Google Web Toolkit (GWT), то полученный JS-код будет сгенерирован машиной, его будет сложно понять и перепроектировать.

  • Некоторые структуры более высокого уровня, такие как React.js может затруднить обратное проектирование, абстрагируя уже сложную логику JavaScript.

Решением вышеупомянутых трудностей является использование механизма визуализации браузера, который анализирует HTML, применяет форматирование CSS и выполняет JavaScript для отображения веб-страницы.

пример

В этом примере для рендеринга Java Script мы будем использовать знакомый Python-модуль Selenium. Следующий код Python будет отображать веб-страницу с помощью Selenium -

Во-первых, нам нужно импортировать webdriver из селена следующим образом:

from selenium import webdriver

Теперь укажите путь к веб-драйверу, который мы загрузили в соответствии с нашим требованием -

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

Теперь укажите URL-адрес, который мы хотим открыть в этом веб-браузере, который теперь контролируется нашим скриптом Python.

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

Теперь мы можем использовать идентификатор панели инструментов поиска для установки элемента для выбора.

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

Затем мы можем использовать java-скрипт, чтобы установить содержимое поля выбора следующим образом:

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

Следующая строка кода показывает, что поиск готов для нажатия на веб-странице -

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

Следующая строка кода показывает, что он будет ждать 45 секунд для завершения запроса AJAX.

driver.implicitly_wait(45)

Теперь для выбора ссылок на страны мы можем использовать селектор CSS следующим образом:

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

Теперь текст каждой ссылки можно извлечь для создания списка стран -

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