Рубрики
Без рубрики

Как очистить сайт AJAX с помощью Python

Этот учебник научит вас ловить вызовы AJAX и воспроизводить их с помощью библиотеки запросов и браузера Google Chrome.

Автор оригинала: Codementor Team.

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

Проблема большинства этих инструментов заключается в том, что они извлекают только статический HTML-код, поступающий с сервера, а не динамическую часть, которая визуализируется с помощью JavaScript.

Вот несколько вариантов преодоления этой проблемы:

  1. Автоматизированные браузеры

    Автоматизированные веб-браузеры, такие как Selenium или Splash , являются полными браузерами, которые работают “без головы”.” Настройка этого немного сложна. Существуют решения для смягчения этой проблемы, такие как docker . Их настройка выходит за рамки данного документа, и поэтому мы сосредоточим наше решение на втором варианте ниже.

  2. Перехват вызовов AJAX

    Попробуйте перехватить AJAX-вызовы со страницы и воспроизвести/воспроизвести их.

Область применения этого учебника

Этот учебник научит вас ловить вызовы AJAX и воспроизводить их с помощью библиотеки requests и браузера Google Chrome. В то время как фреймворки типа scrapy обеспечивают более надежное решение для веб-скребка, это не обязательно для всех случаев. Вызовы AJAX в основном выполняются против API, который возвращает объект JSON, который может быть легко обработан библиотекой requests . Этот учебник можно сделать с любым другим браузером, таким как Firefox — процесс тот же самый, единственное, что меняется, – это пользовательский интерфейс dev tools.

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

Давайте начнем

Первое, что вам нужно знать, это то, что попытка воспроизвести вызов AJAX похожа на использование недокументированного API, поэтому вы должны посмотреть на вызов, который делают страницы. Зайдите на сайт и поиграйте с ним, перейдите по некоторым страницам и посмотрите, как отображается некоторая информация без необходимости перехода на другой URL. После того, как вы закончите играть, вернитесь сюда, чтобы начать выскабливание.

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

Во-первых, давайте перейдем к разделу найти магазин сайта:

скрести сайт ajax

Давайте ограничим наш скребок магазинами, расположенными в США по штатам:

напугать сайт ajax

Теперь мы видим магазины по штату США. Выберите любое состояние, и страница отобразит информацию о магазине, находящемся там. Попробуй, а потом возвращайся. Существует также возможность просмотра историй постранично, это тот вариант, который мы будем использовать для удаления страницы.

Как вы можете видеть, каждый раз, когда вы выбираете состояние или страницу, веб-сайт отображает новые магазины, заменяя старые. Это делается с помощью AJAX-вызова сервера с запросом новых магазинов. Теперь наша задача-поймать этот зов и воспроизвести его. Для этого откройте консоль Chrome DevTools и перейдите в раздел network и подраздел XHR:

скрести сайт ajax

XHR (XMLHttpRequest) – это интерфейс для выполнения HTTP-и HTTPS-запросов, поэтому, скорее всего, здесь будет показан ajax-запрос.

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

скрести сайт ajax

Если вы дважды щелкнете по вызову AJAX, то увидите, что там много информации о магазинах. Вы также можете просмотреть запросы. Давайте сделаем это, чтобы увидеть, есть ли там информация, которая нам нужна. Вызов AJAX не всегда имеет имя “AJAX”, он может иметь любое имя, поэтому вы должны посмотреть, какие данные поступают в каждый вызов подраздела XHR.

скрести сайт ajax

Ответ приходит в формате JSON. Он имеет 3 элемента, и информация, которая нам нужна, находится в последнем. Этот элемент содержит ключ данных, содержащий HTML-код, вставляемый на страницу при выборе страницы. Как вы заметите, HTML находится в очень длинной строке текста. Вы можете использовать что-то вроде Code Beautify , чтобы “приукрасить” его. Блок кода, соответствующий каждому хранилищу, находится в этом gist . В этом блоке есть все, что нам нужно.

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

Почтовый запрос

Здесь мы видим URL-адрес запроса и то, что метод запроса-post. Давайте теперь посмотрим на данные формы, которые отправляются на сервер.

скрести сайт ajax

Как видите, на сервер отправляется очень много данных, но не волнуйтесь — не все они нужны. Чтобы увидеть, какие данные действительно нужны, вы можете открыть консоль и сделать различные post-запросы к URL-адресу запроса с помощью библиотеки запросов, я уже сделал это для нас и выделил необходимые данные.

Написание собственного скребка для сайта

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

Мы будем использовать xml CSS selector для извлечения нужной нам информации. Мы извлекем следующее:

  • Название магазина
  • Полный адрес
  • Номер телефона
  • Часы работы

Давайте сначала создадим проект и компакт-диск к нему.

$ mrkdir wholefoods-scraper
$ cd wholefoods-scraper

Мы должны создать virtualenv.

$ virtualenv venv
$ source venv/bin/activate

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

$ pip install requests
$ pip install lxml
$ pip install cssselect
$ touch scraper.py

Теперь откройте файл Python с помощью вашего любимого редактора . Давайте начнем создавать ваш скребок с класса и делать функцию для репликации вызова AJAX:

# Importing the dependencies
# This is needed to create a lxml object that uses the css selector
 from lxml.etree import fromstring
  
# The requests library
import requests
  
class WholeFoodsScraper:
  
  API_url = 'http://www.wholefoodsmarket.com/views/ajax'
    scraped_stores = []

    def get_stores_info(self, page):
     
        # This is the only data required by the api 
        # To send back the stores info
        data = {
        'view_name': 'store_locations_by_state',
        'view_display_id': 'state',
        'page': page
        }
        # Making the post request
        response = requests.post(self.API_url, data=data)

        # The data that we are looking is in the second
        # Element of the response and has the key 'data', 
        # so that is what's returned
        return response.json()[1]['data']

Теперь, когда у нас есть функция, которая извлекает данные из хранилищ, давайте сделаем ее для анализа этих данных с помощью CSS-селектора, посмотрите на gist , если вы заблудились.

import ....

class WholeFoodsScraper:
  # Same ...
  # Array to store the scraped stores
  scraped_stores = []
    
  # get_store_info function
  
  def parse_stores(self, data):
    # Creating an lxml Element instance
        element = fromstring(data)

        for store in element.cssselect('.views-row'):
            store_info = {}
            
            # The lxml etree css selector always returns a list, so we get
            # just the first item
            store_name = store.cssselect('.views-field-title a')[0].text
            street_address = store.cssselect('.street-block div')[0].text
            address_locality = store.cssselect('.locality')[0].text
            address_state = store.cssselect('.state')[0].text
            address_postal_code = store.cssselect('.postal-code')[0].text
            phone_number = store.cssselect('.views-field-field-phone-number div')[0].text
            
            try:
                opening_hours = store.cssselect('.views-field-field-store-hours div')[0].text
            except IndexError:
                # Stores that doesn't have opening hours are closed and should not be saved.
                # This is found while debugging, so don't worry if you get errors when you
                # run a scraper
                opening_hours = 'STORE CLOSED'
                continue
            
            full_address = "{}, {}, {} {}".format(street_address,
                                                  address_locality,
                                                  address_state,
                                                  address_postal_code)
            
            # now we add all the info to a dict
            store_info = {
                        'name': store_name,
                        'full_address': full_address,
                        'phone': phone_number,
                        'hours': opening_hours
                        }
            
            # We add the store to the scraped stores list
            self.scraped_stores.append(store_info)

Теперь нам просто нужна функция для вызова get_stores_info для каждой из 22 страниц, на которых есть Wholefoods stores by US state site, а затем разбора данных с помощью parse_stores . Мы также сделаем небольшую функцию для сохранения всех очищенных данных в файл JSON.

import json
import ... All stays the same
  
class WholeFoodsScraper:
  # Same ...
    
  def run(self):
        for page in range(22):
            # Retrieving the data
            data = self.get_stores_info(page)
            # Parsing it
            self.parse_stores(data)
            print('scraped the page' + str(page))

        self.save_data()

    def save_data(self):
        with open('wholefoods_stores.json', 'w') as json_file:
            json.dump(self.scraped_stores, json_file, indent=4)

Теперь наш скребок готов! Нам просто нужно запустить его. Добавьте это в конец файла python:

if __name__ == '__main__':
  scraper = WholeFoodsScraper()
  scraper.run()

Вы можете увидеть результаты в whole foods_stores.json файл.

Вывод

Теперь вы, должно быть, спрашиваете: ” Когда я должен использовать автоматический браузер и, ну, должен ли я попытаться воспроизвести вызовы AJAX? ” Ответ прост: всегда старайтесь воспроизвести вызовы AJAX, прежде чем пытаться сделать что — то более сложное или тяжелое, например, использовать автоматический браузер-попробуйте этот более простой и легкий подход!

Точно так же вы также можете попробовать создать свой собственный веб-скребок с помощью Node.js .

Биография автора

Хулио Алехандро-внештатный разработчик программного обеспечения и инженер-химик из Венесуэлы с растущими навыками. Он любит заниматься веб-разработкой, веб-скребком и автоматизацией! Он работает в основном на серверном программировании с Python/Django/Flask. Он также занимается front-end разработкой с помощью JavaScript-фреймворков, таких как Vue или React.