Скрейпинг веб-сайтов на Python

09.07.21 в 10:10 Other 4366

С чего начать скрейпинг данных в Сети, используя Python? Такой вопрос возникает у многих начинающих специалистов. На начальном уровне этот процесс довольно простой и любой желающий может быстро начать реализовывать свой проект. Однако, для качественной работы над подобной задачей нужно помнить о большом количестве нюансов, в которых не так просто разобраться сразу

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

Что такое скрейпинг?

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

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


В качестве первого шага к созданию своего бота рекомендуем создать отдельный проект в одной из популярных IDE. Для работы с python это могут быть: VS Code, PyCharm, Jupyter, Spider или другие подобные решения. Для примеров, приведенных ниже используется интерпретатор Python версии 3.8. Если вы планируете постоянно вести работу над этим проектом, рекомендуем сразу создать под него git-репозиторий.

Когда проект создан, создайте и запустите виртуальное окружение. Оно понадобится, поскольку мы будет работать с целым списком дополнительных библиотек. Подробную инструкцию по работе с виртуальным окружением можно найти в документации python: https://docs.python.org/3/tutorial/venv.html

Установка дополнительных библиотек

Для работы базовых примеров из первой части статьи достаточно установить три дополнительные библиотеки. В запущенном виртуальном окружении производим установку с помощью pip:

    $ pip install BeautifulSoup4 pandas selenium

Selenium будет использоваться для автоматического управления браузером и отправки http-запросов. BeautifulSoup - мощнейшая библиотека для парсинга HTML-страниц, поможет выбрать нужные элементы. Pandas используем для записи данных в файл.

    beautifulsoup4==4.9.3
    blinker==1.4
    certifi==2020.12.5
    cffi==1.14.5
    chardet==4.0.0
    cryptography==3.4.7
    et-xmlfile==1.1.0
    gevent==21.1.2
    greenlet==1.1.0
    grequests==0.6.0
    h11==0.12.0
    h2==4.0.0
    hpack==4.0.0
    hyperframe==6.0.1
    idna==2.10
    kaitaistruct==0.9
    lxml==4.6.3
    MechanicalSoup==1.0.0
    numpy==1.20.3
    openpyxl==3.0.7
    pandas==1.2.4
    pyasn1==0.4.8
    pycparser==2.20
    pydivert==2.1.0
    pyOpenSSL==20.0.1
    pyparsing==2.4.7
    PySocks==1.7.1
    python-dateutil==2.8.1
    pytz==2021.1
    requests==2.25.1
    selenium==3.141.0
    selenium-wire==4.3.0
    six==1.16.0
    soupsieve==2.2.1
    urllib3==1.26.4
    wsproto==1.0.0
    zope.event==4.5.0zope.interface==5.4.0

Чтобы установить их вызовите команду:

    $ pip install -r requirements.txt

После установки можно начинать работу, все примеры кода будут работать корректно.

Webdriver для браузера


В этот раз для получения данных с веб-страниц мы будет использовать библиотеку selenium. Она позволяет запускать стандартный браузер и управлять им в автоматическом режиме. Несмотря на то, что для масштабных задач по скрейпингу данных применяются браузеры без графического интерфейса (headless browser), на первом этапе разработки более наглядно и удобно пользоваться обычным. В наших примерах мы будем работать с Chrome. Взаимодействие с Firefox при этом не имеет принципиальных отличий.

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

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

Python + Chrome: получаем данные с веб-сайта


Сейчас самое время воспользоваться недавно скачанным веб-драйвером и попробовать запустить браузер с помощью python. Начнем с импорта библиотеки selenium:

    from selenium import webdriver

Затем создадим объект драйвера для Chrome:

   browser = webdriver.Chrome(
     executable_path='c://path/to/your/chromedriver.exe'
   )

Браузеру нужно задать ссылку или набор ссылок на сайты, которые он будет открывать по команде из python-приложения. Объявим список, который будет содержать базу целевых URL:

    urls = [
      'https://rsocks.net/',
      'https://rsocks.net/server-proxy',
      'https://rsocks.net/mobile-proxy',
      ...
   ]

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

    from selenium import webdriver
    browser = webdriver.Chrome(
        executable_path='c://path/to/your/chromedriver.exe'
    )
    urls = [
        'https://rsocks.net/',
        'https://rsocks.net/server-proxy',
        'https://rsocks.net/mobile-proxy',
    ...
    ]
    for url in urls:
        browser.get(url)
    browser.quit()

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

Парсинг данных с BeautifulSoup

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

Начинаем с импорта модуля и создания пустых списков для хранения целевых данных:

    from bs4 import BeautifulSoup
    titles = []
    headers = []

Далее модифицируем процесс запроса страницы: сохраним ее содержание в переменную content и обработаем его встроенным HTML-парсером из BeautifulSoup:

    browser.get(url)
    content = browser.page_source
    soup = BeautifulSoup(content, features='html.parser'

Теперь сохраним отдельные элементы страницы в переменные и добавим в заготовленные списки, если подобного элемента еще нет в них:

    title = soup.find('title').text
    header = soup.find('h1').text
        if title not in titles:
    titles.append(str(title))
        if header not in headers:
    headers.append(str(header))

Чтобы убедиться в правильности извлечения данных можно просто вывести их в консоль:

    print(titles)
    print(headers)

Отлично! Страница запрашивается, нужные данные извлекаются, но при большом объеме информации ее нужно хранить в удобном формате.

Популярные модули в Python позволяют сохранять информацию в базы данных или файлы с разными форматами: txt, csv, xlsx, rtf и т.д. Мы воспользуемся одной из самых известных библиотек для работы с большими данными - Pandas.

Экспорт данных с Pandas

Библиотека Pandas предлагает специальные структуры данных для удобной и эффективной работы с большими объемами разнородной информации. В нашем случае воспользуемся типом данных DataFrame и сохраним в него получившиеся списки с заголовками.

В DataFrame можно сохранить массивы, списки, словари и другие подобные объекты. Импортируем модуль pandas и сохраним словарь с результатами парсинга страниц:

    import pandas as pd
     df = pd.DataFrame(
        {
            'Title': titles,
            'Headers': headers,
        }
     )

Для дальнейшей обработки данных можно использовать широкий функционал предоставляемый Pandas. Воспользуемся им для экспорта в файл Excel:

    df.to_excel('titles.xlsx', sheet_name="Sheet1")

Итоговый код будет выглядеть так:

    from selenium import webdriver
    from bs4 import BeautifulSoup
    import pandas as pd
    browser = webdriver.Chrome(
        executable_path='c://path/to/your/chromedriver.exe'
    )
    titles = []
    headers = []
    urls = [
        'https://rsocks.net/',
        'https://rsocks.net/server-proxy',
        'https://rsocks.net/mobile-proxy',
        ...
    ]
    for url in urls:
        browser.get(url)
        content = browser.page_source
        soup = BeautifulSoup(content, features='html.parser')
        title = soup.find('title').text
        header = soup.find('h1').text
        if title not in titles:
            titles.append(str(title))
        if header not in headers:
            headers.append(str(header))
    df = pd.DataFrame(
       {
           'Title': titles,
           'Headers': headers,
       }
    )
    df.to_excel('titles.xlsx', sheet_name="Sheet1")
    browser.quit()

В результате работы программы в рабочей директории появится готовый Excel-файл с записанными в него результатами скрейпинга. Поздравляем! Мы реализовали простейший веб-скрейпинг на Python!

Скрейпинг-бот на Python: продолжение

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

Запросы через прокси-сервер

При большом числе запросов на один и тот же ресурс может возникнуть проблема ограничения доступа. Многие сервисы стараются ограничить активность скрейп-ботов. Чаще всего отслеживание их активности производится по IP-адресу. Если все запросы на целевой сервис будут приходить с одного и того же IP, вам может быть временно отказано в доступе на определенные страницы или ограничена допустимая частота запросов.

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

Настроим запрос страницы в браузере через прокси в Selenium. Достаточно добавить несколько параметров к уже используемому веб-драйверу.

Для подключения к прокси понадобится его IP-адрес и номер порта. Сохраним их в отдельном словаре:

    proxy = {
        'address': 'IP:port',
        'username': 'proxy_login',
        'password': 'proxy_password',}

Возможности Selenium позволяют выполнять подключение через прокси, работающие по всем популярным http/socks протоколам и поддержкой разных типов авторизации. В примерах ниже мы используем подключение по протоколу socks5 при авторизации по IP-адресу и по http с доступом по логину/паролю.

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

Для работы браузера через прокси достаточно задать настройки в опциях браузера. Для этого в Selenium есть отдельный класс Options. Импортируем его и создадим объект для задания настроек запускаемого браузера:

    from selenium.webdriver.chrome.options import Options
    options = Options()

Конфигурировать отдельные настройки можно с помощью метода add_argument. Используем его для настройки прокси:

    options.add_argument('--proxy-server=socks5://IP:port')

Для проверки работы через прокси-сервер откроем в браузере страницу с индикацией IP-адреса посетителей. Исполнительный файл будет выглядеть так:

    from selenium import webdriver
    from selenium.webdriver.chrome.options import Options
    proxy = {
         'address': 'IP:port',
         'username': 'proxy_login',
         'password': 'proxy_password',
    }
    
    options = Options()
    options.add_argument(f'--proxy-server=socks5://{proxy["address"]}')
   
    chrome = webdriver.Chrome(
        executable_path='c://path/to/your/chromedriver.exe',
        options=options
    )

    chrome.get('http://ipinfo.io')

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

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

Расширение для браузера Chrome состоит из файл manifest.json, в котором описываются основные параметры конфигурации, и исполнительного файла на JavaScript, где содержится сам функционал расширения. Оба созданных файла добавляются в zip-архив. Эти операции можно проделать вручную, а можно автоматизировать этот процесс на Python.

Для создания файлов и их архивации в python воспользуемся встроенным модулем zipfile. Создадим отдельный исполнительный файл create_plugin.py внутри пропишем следующие инструкции:

    import zipfile

    manifest_json = """
    {
       "version": "1.0.0",
       "manifest_version": 2,
       "name": "Chrome Proxy",
       "permissions": [
           "proxy",
           "tabs",
           "unlimitedStorage",
           "storage",
           "<all_urls>",
           "webRequest",
           "webRequestBlocking"
       ],
       "background": {
           "scripts": ["background.js"]
       },
   "minimum_chrome_version":"22.0.0"
    }
    """

    background_js = """
    var config = {
        mode: "fixed_servers",
        rules: {
            singleProxy: {
                scheme: "http",
                host: "%s",
                port: parseInt(%s)
        },
        bypassList: ["localhost"]
       }
     };
    chrome.proxy.settings.set({value: config, scope: "regular"}, function() {});
    function callbackFn(details) {
        return {
            authCredentials: {
                username: "%s",
                password: "%s"
            }
        };
    }

    chrome.webRequest.onAuthRequired.addListener(
           callbackFn,
           {urls: ["<all_urls>"]},
           ['blocking']
    );
    """ % ('proxy_IP', 'proxy_port', 'username', 'password')

    plugin_file = 'proxy_auth_plugin.zip'

    with zipfile.ZipFile(plugin_file, 'w') as zp:
       zp.writestr("manifest.json", manifest_json)
       zp.writestr("background.js", background_js)

После выполнения этого файла в рабочей директории появится архив proxy_auth_plugin.zip с нужным расширением.

Для запуска браузера с использованием созданного расширения используется тот же метод: создание объекта Options и добавления к нему новых аргументов:

    from selenium import webdriver
    from selenium.webdriver.chrome.options import Options

    options = Options()
    options.add_argument(
        '--load-extension=c://path/to/your/proxy_auth_plugin'
    )

    chrome = webdriver.Chrome(
        executable_path='c://path/to/your/chromedriver.exe',
        options=options
    )
    chrome.get('http://ipinfo.io')

Данный метод позволяет использовать http-прокси с авторизацией по логину/паролю.

Как выбрать подходящие прокси для скрейпинга?

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

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

Мобильные прокси получают IP-адрес от реального мобильного оператора. Пользователи мобильных сетей пользуются высоким уровнем доверия даже со стороны таких требовательных сервисов как Amazon, Facebook, Instagram, Spotify и т.д. Эту особенность используется в работе с мобильными прокси, давая возможность работать с любым сервисом, без труда получая нужные данные.


У этого типа прокси есть и свои недостатки. Главный из которых - высокая стоимость мобильного трафика. По этой причине стоимость мобильных прокси превышает резидентские или серверные аналоги. Другим недостатком является невысокая скорость мобильного интернета по сравнению с проводным. Это сказывается и на мобильных прокси, они не являются рекордсменами по скорости передачи данных.

На RSocks (https://rsocks.net/mobile-proxy) вы можете найти огромный выбор мобильных прокси из 22 стран со всего мира. Большим преимуществом наших прокси является безлимитный трафик, что значительно упрощает работу, позволяя забыть об учете передаваемого объема данных.

Резидентские прокси работают на устройстве, подключенном к Сети через обычного провайдера домашнего интернета. Поэтому их IP не отличается от рядовых клиентов работающих на ПК. Это позволяет прокси поддерживать высокую производительность, поскольку скорость соединения домашнего Интернета во многих страна довольно высока.


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

Главным недостатком, осложняющим работу с резидентскими прокси, выступает сильная зависимость их характеристик от качества пакета. В случае использования бесплатных или бюджетных резидентских пакетов скорость соединения, пинг и uptime прокси внутри них иногда могут быть на очень невысоком уровне. В этом случае пакет подойдет только для небольшого объема данных одновременно передающихся через один прокси.

Хорошим решением при выборе резидентских прокси будет один из пакетов линейки World Mix (https://rsocks.net/socks-https-proxy). C ним вы получаете список из 9 000 - 27 000 резидентских SOCKS5/SOCKS4/HTTP прокси, которые обновляются до 30% каждые два часа. Геолокация IP-адресов смешанная, присутствуют страны со всех континентов.

Если потребностей в безлимитном трафике нет, то лучшим решением будет использование пакетов Exclusive (https://rsocks.net/exclusive). В нем вы найдете огромный пул самых качественных прокси-серверов с обновлением каждые 15 минут. Размер пакета 50 000 IP. Можно выбрать Wi-Fi или мобильный трафик.

Серверные прокси понимаются на серверах, предоставляемых сервисами хостинга. По этой причине IP таких прокси статичные, что ограничивает возможности их использования для скрейпинга. Но если целевой ресурс известен лояльностью ко всем посетителям и вы не планируете слишком большой объем запросов на него, то серверные прокси так же могут дать хорошие результаты.


Преимуществами, которые отличают серверные от других пакетов, являются их высокая скорость и стабильность соединения. Скорость соединения может достигать 100, а в очень редких случая и 1000 Mbit/s. В сочетании с безлимитным трафиком это дает отличные преимущества при аккуратном срейпинге с невысокой вероятностью блокировки по IP.

У нас (https://rsocks.net/server-proxy) вы можете найти более 25 000 серверных прокси из 14 стран. Минимальный размер пакета - 1000 IP. Для всех предложений мы гарантируем uptime до 99% и стабильную скорость соединения. Для прокси США, России и Германии вам доступен выбор IP определенного города. Цены за пакет начинаются от 9$.

Как сделать скрейпинг еще эффективнее?

Для полноценного сбора данных с целевых ресурсов представленные подходы могут использоваться только с дополнительными усовершенствованиями. Ниже приводятся еще несколько советов, способных помочь в движении к полноразмерному скрейпингу:

  • Собирайте однотипные данные, используя циклы, чтобы получить массивы одинаковой длины;
  • Запрашивайте сразу несколько страниц. Есть разный методы реализации этой возможности. Самое простое - собрать списки URL и отправляйте запросы, проходя по ним циклом;
  • Собирайте разнородные данные в разные массивы одинаковой длины. Так их будет легче сохранять в файлы. Скрейпинг данных разных форматов встречается довольно часто в коммерческих задачах;
  • После того, как вы убедились, что ваш скрейпинг-бот работает корректно, можно не использовать реальный браузер для каждого запроса. Гораздо эффективнее будет запускать браузер без графического интерфейса, что значительно сэкономит время;
  • Используйте для скрейпинга шаблоны, имитирующие действия реальных посетителей сайта. Для этого можно использовать дополнительные библиотеки. Например, для создания искусственных пауз между открытием страниц или реализации перемещения вниз по странице, имитируя скроллинг;
  • Подключите к боту систему мониторинга целевых страниц. Данные на некоторых сайтах могут меняться спустя время или в зависимости от статуса посетителя. Периодическая проверка страниц гарантирует получение актуальных данных;
  • Сделайте запросы на веб-страницы еще эффективнее с библиотекой Requests. Это один из самых популярных инструментов на Python для работы с сетевыми протоколами. Вы можете настраивать множество дополнительных параметров без значительного усложнения бота. Для работы в многопоточном режиме предусмотрена библиотека gRequests;
  • Используйте прокси той страны или города, которые лучше всего подходят для заданного целевого ресурса. Это позволит обойти ряд региональных ограничений, действующих в Сети.

Поздравляем! Работа над скрейпинг-ботом завершена! Продолжайте развивать собственные проекты и используйте качественные прокси!

Если формат видео будет полезен для резюмирования всей информации, то можно ознакомится с обучающим роликом здесь:

Остались вопросы? Поищите ответы здесь!

Как запустить работу скрейпинг-бота в многопоточном режиме?

Самый простой способ, который хорошо подходит для начинающих - библиотека grequests. Она позволяет выполнять простые операции в многопоточном режиме, не обращая внимание на многие технические нюансы, связанные с реализацией работы потоков.

Как работать с формами на целевой странице?

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

Какие еще инструменты в Python можно использовать для скрейпинга?

На Python разработано множество инструментов для эффективного скрейпинга. Интересными решениями являются полноценные фреймворки, позволяющие проводить весь цикл операции по сбору данных из Сети. Среди них можно выделить Scrapy и PySpider. Попробуйте воспользоваться руководствами по началу работы с ними здесь.

Как подобрать наилучшие прокси для моего проекта?

На RSocks вы можете запросить бесплатный тест любого интересующего пакета. Обратитесь в службу поддержки, наши специалисты помогут подобрать вам наилучшее предложение.

Сколько стоят прокси для скрейпинга?

Мы предлагаем широкий ассортимент пакетов отлично подходящих для сбора данных в Сети. Цены на пакеты резидентских прокси начинаются от 1$, мобильные от 3$, серверные - от 9$.

Комментарии

Войдите, чтобы оставить комментарий
Популярные

Вместе с широкими возможностями Интернет несет в себе и ряд опасностей. Решить данные проблемы можно с помощью технологии OpenVPN, которая предлагает несколько действенных способов скрыть трафик.

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

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

В далеком, по меркам темпов развития информационных технологий, 2015 году компания Google смогла создать искусственный интеллект, способный анализировать состояние вокруг него и делать выводы. Прозвали это чудо DQN, и оно тренировалось в аркадных игра (Пакман, Теннис, Спейс Инвейдерс, Боксинг и прочей классике). Результаты оказались таковы: DQN превзошло в 22 из 49 игр успехи лучших игроков мира!

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

Новые

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

Если вы ищете пакет резидентских или мобильных прокси с возможностью работы с определенной страной или ISP, лучшим решением станет пакет Exclusive mix. С ним вы можете скачать список, содержащий прокси только выбранных вами стран и операторов, гибко фильтруя его под свои нужды.

С чего начать скрейпинг данных в Сети, используя Python? Такой вопрос возникает у многих начинающих специалистов. На начальном уровне этот процесс довольно простой и любой желающий может быстро начать реализовывать свой проект. Однако, для качественной работы над подобной задачей нужно помнить о большом количестве нюансов, в которых не так просто разобраться сразу.

Знаете ли вы, что большая часть экспертов в области Интернет-маркетинга и электронной коммерции использует специализированные браузеры? Этот инструмент давно завоевал популярность при выполнении задач, требующих высокого уровня анонимности в Интернете.

Прокси сервер — что это такое. Основные преимущества работы через виртуального "посредника" — анонимность в сети, обход бана, защита от атак, охрана интеллектуальной собственности

Есть вопросы?

Нажмите сюда и мы с радостью на них ответим

Trustpilot 4.5