Парсинг
Vladislav LaptevВариант 1. Масшабируем в лоб.
На VPS создаю простое приложение на рельсах, из-за того, чтобы было удобно работать с базой через ActiveRecord, миграции, смотреть статистику во вьюхах и так далее. База данных PostgreSQL, настроенная на удаленное подключение. На этом работа с базой заканчивается.
Далее пишу скрипт парсинга, в который дописываю.
require 'active_record'
и прописываю подключение к базе (в моем случае это был удаленный сервер, но можно писать и на локальный)
ActiveRecord::Base.establish_connection(adapter: 'postgresql', host:'127.0.0.1', database: 'parsing', username: 'myuser', password: 'mypassword', port:'5432')
Далее, для того, чтобы оперировать данными точно так-же легко как и в Rails я создаю класс. В моем случае я собирал данные по сайтам и имел модель, например такую
Site (url, ip)
class Sites < ActiveRecord::Base
self.table_name = "sites"
end
И теперь в скрипте, чтобы что-то записать в базу я пишу и результат сохраняется в базу. Ну что еще нужно то для парсинга небольшого количества данных.
result = Site.create(url: "microsoft.com", ip: "104.43.195.251")
result - в нашем случае возвращает true или false, в случае успешного или неуспешной записи в базу. Так как у нас на базе нет валидаций, то все запросы даже если оба параметра nil будут успешны.
Но так как слать каждую секунду по 1 запросу - неправильно я собираю в хэш некое количество напарсенных записей (например 50), групирую их в массив хэшей и через Site.create отправляю на удаленный сервер.
Далее для того, чтобы не платить за прокси сервера, которые еще не понятно как будут работать, я использую сервера на Vscale.io, у которых оплата за использование почасовая. Путем нехитрых манипуляций с API Vscale и Ansible я получаю скрипты, которые:
1) Создают новый сервер на Vscale самой дешевой конфигурации (0.29 рублей за час)
2) Через Ansible устанавливают все, необходимое для работы ruby
3) Заливают скрипт, устанавливают входные данные для парсинга и запускают скрипт как background процесс.
Вариант 2. Sidekiq
Создаю Rails приложение, создаю модели, в которые буду складывать напарсенные данные. Например тоже "Site". Устанавливаю sidekiq, добавляю sidekiq в Gemfile.
Далее пишу Job на ActiveJob для парсинга. Почему не Worker для Sidekiq? Потому что лень было нагуглить как дебажить через pry Worker'ы, сходу не нашел информации, видимо какой-то нюанс есть. А job спокойно дебажится через pry. После успешного написания создаю Worker с аналогичным кодом просто.
Теперь создаю модель Proxy (ip, port, username, password, available, last_used_at), куда загоняю десяток хороших прокси. И в скрипте парсинга указываю дергать из базы прокси. last_used_at обновляю в случае валидности прокси и успешного запроса.
Proxy.where(available: 1).where("last_used_at < ?", 1.seconds.ago).last
Ограничение на 1.seconds.ago стоит потому что парсил специфические данные, где есть ограничение на количество запросов с одного IP. В итоге все парсится, но руки не дошли собирать метрики по кол-ву запросов в минуту. Все приходит с опытом.
Этот вариант парсинга мне больше нравится, так как вариант с масштабированием на сервера подходит больше для других задач, нежели для парсинга. В итоге можно создавать тысячи worker'ов не боясь за то, что какие-то данные не спарсятся или потеряются. Плюс при наличии большого количества IP можно спокойно парсить все, что угодно. Однако при каких-то объемах не будет хватать ширины канала вашей машины или сервера. Поэтому придется шаманить с вариантов номер 1.