Учебники

Python Web Scraping — Динамические сайты

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

Вступление

Соскоб в Интернете — сложная задача, и сложность увеличивается, если сайт динамический. Согласно Глобальному аудиту доступности веб-сайтов Организации Объединенных Наций, более 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. Точно так же мы можем загрузить необработанный строковый ответ и, используя метод json.loads в python, также можем загрузить его. Мы делаем это с помощью следующего скрипта 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.

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

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

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

пример

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

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

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

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