Подчеркну, проект некоммерческий, никоим образом не предназначен для раскрутки огромного числа аккаунтов горе/сеошниками/директологами, заточен сугубо под решение задач оптимизации работы со своим твиттер-аккаунтом, одним или несколькими.
Помимо рефакторинга кода (который на момент публикации этого материала еще не вполне окончен), Twitter Toolkit on Rails теперь использует фреймворк Active Job для формирования и постановки в очередь асинхронных задач. Бэкенд очередей не определен; при желании и необходимости крайне несложно подключаются sidekiq и sidekiq-cron, например. Но основной целью автора была многопоточность выполняемых задач, также упрощение работы с long running processes; даже возможность остановки сервера попросту по Ctrl + C вместо
kill -INT $(cat tmp/pids/server.pid)
делает работу с титтер-инструментарием более комфортной, и даже для программиста.
Напомню, написанный на ruby Twitter Toolkit on Rails умеет на данный момент ответный фолловинг и анфоловинг в полностью автоматических режимах, парсер твитов и автопостинг, ретвиты по заданным ключам или тэгам; также способен формировать список для ответного фолловинга вручную и перечень фолловеров (в HTML и csv) произвольного твиттер-аккаунта.
Фолловинг через Twitter API искусственно затруднен сегодня для пользователей программистами Твиттера; как видно из скриншота, перманентно приходится делать паузы, реализованные посредством rescue. Как-то так:
class FollowJob < ApplicationJob
queue_as :default
def perform(*args)
client = twi_client(args[0])
list = follow(args[0])
begin
list.take(100).each do |user|
client.follow(user.id)
list.delete(user)
puts "follow: #{user.screen_name} #{Time.now}"
sleep rand(30..60)
end
rescue Twitter::Error::TooManyRequests,
Twitter::Error::Forbidden,
OpenSSL::SSL::SSLError,
Twitter::Error::ServiceUnavailable,
HTTP::Error
[]
puts "rescue Twitter::Error #{Time.now}"
sleep 905
retry
end
end
end
Ну, что же делать, Твиттеру виднее. Кстати, передавая массив аккаунтов для фолловинга (или анфолловинга) - не забываем сериализовать аргумент (или, вернее, его часть) при вызове метода подкласса ApplicationJob, т. к. Twitter::User он однозначно не поймет:
ActiveJob::SerializationError (Unsupported argument type: Twitter::User)
Впрочем, все несложно. Взгляните, вот и вся в данном случае сериализация (а десериализация не потребуется, см. предыдущий фрагмент кода):
follow = (followers - friends).as_json(only: %i[id screen_name])
FollowJob.perform_later(tweet, follow)
Для тех, кто захочет потестить.
Вам понадобятся ключи доступа к Twitter API, вот уже несколько лет запросы их проходят ручную модерацию (спецом за TOS Твиттера не слежу, но, судя по характеру работы API - там вряд ли что-то поменялось). Совет: если токены доступа у вас "при наличии отсутствия" и вы намерены их запросить - так или иначе пригодятся, весчь в хозяйстве нужная и полезная - ни в коем случае не указывайте причиной их запроса эту (или аналогичные) прогу. Исходя из опыта - последует немедленный и категорический отказ, который окажется еще более категоричен, если у вас российский ip. Увы, спасибо здесь следует сказать кремлеботам и иже с ними, обижаться не на кого, кроме как на самих себя; думаю, все помнят эту тупую историю про русских в Твиттере. Заслужили. For example, французский мой коллега, помнится, как-то однажды понтанулся мне, зараза, что он, дескать, получил ключи Twitter без труда и плясок с бубнами... завидую ему белой и черной, всех оттенков, завистью, и дело тут, блять, вовсе не в ключах.
От вас потребуют аргументировать ваш запрос, придумайте какую-нибудь нейтральную причину. Скажем, есть у вас личный форум на kunena, и там в настройках нужно указать токены API Twitter, чтобы у пользователей была возможность вставлять твиты в посты (это на самом деле так). Или любой иной резон; российское вранье всем осточертело, правда, но тут уж ничего не поделаешь.