Sign in

Зарегистрируйтесь, чтобы стать полноправным участником сообщества Masterpro.ws.

Twitter-инструментарий на Ruby on Rails

Показанный далее class представляет из себя не более чем концепт идеи, задумку набора инструментов для работы в Twitter, написанный аффтором - или, лучше сказать, набросанный - как приложение Ruby on Rails на основе gem 'twitter'.

 

 

 

Рабочий пример описанного в статье кода, в числе других Rails Examples - всегда возможно найти в тестовом блоге автора на herokuapp.com, welcome.

 

Класс полностью работоспособен, вы можете попробовать самостоятельно, клонировав rails-app с GitHub автора; ну или же попросту примите на веру показанный выше скринкаст. Если идея вас заинтересовала - вы можете попробовать это форкнуть, заодно причесать и сделать логику несколько более аккуратной. Увы, после очередного закручивания гаек своего API зловредным Твиттером не вижу особого смысла в продолжении работы над данным проектом. По секрету скажу, что бдительные модераторы Twitter, испросив ссылки на демки (да, теперь вот так), моментально отказали мне в девелоперском доступе даже к одному-единственному тви-аккаунту, токены которого я запрашивал; что заведомо вселяет немалые сомнения в рентабельности дальнейшей разработки. Жаль, конечно, проект обещал быть интересным и востребованным... ну, что же; в свете текущих событий, политических и не очень... нелепо было бы обижаться на сотрудников Twitter, бегущих сегодня как огня не только ботов, но и вообще любых попыток автоматизации действий пользователя в своей соц. сети. Повторюсь, их право.

Когда приложение в режиме твиттер-бота начинает ретвитить найденные по заданным хештегам твиты, довольно быстро приходим к:

ActionDispatch::Cookies::CookieOverflow in TweetsController#index

, в качестве же решения проблемы использован - и, по-видимому, вполне успешно - gem 'activerecord-session_store'; не забывайте однако, при необходимости (или время от времени):

db:sessions:trim

подробнее - на страничке Active Record Session Store на гитхабе.

 

Примечание. Приложение оптимизировано для работы (функции фолловинг и анфолловинг) с популярными твиттер-аккаунтами, насчитывающими большое количество читателей: тестировал, в частности, на собственных тви-акках, 15 - 18 тыс. фолловеров в каждом. В этом случае все значительно медленнее, чем показывает скринкаст; кроме того, вступают в действие лимиты Твиттера, о которых подробнее в этом материале.

 

controller

def index
		@tweets = current_user.tweet
		tweet = @tweets.detect {
			|t| params[:select] == t.name
		}

		config = {
			consumer_key: tweet&.key,
			consumer_secret: tweet&.secret,
			access_token: tweet&.token,
			access_token_secret: tweet&.token_secret
		}

		if (params[:select_action] == 'follow') || (params[:select_action] == 'unfollow')
			client = Twitter::REST::Client.new config
			followers_total = Twi.get_followers(client, config)
			friends_total = Twi.get_friends(client, config)
		end

		case
		when params[:select_action] == 'follow'
			follow = followers_total - friends_total
			Twi.follow(client, follow)
		when params[:select_action] == 'unfollow'
			unfollow = friends_total - followers_total
			Twi.unfollow(client, unfollow)
		when params[:select_action] == 'retweet'
			topics = params['tag'].split(/,/)
			Twi.retweet(config, topics)
		when params[:select_action] == 'post'
			array_posts = params[:tag].split(/[\r\n]+/)
			Twi.post(config, array_posts)
		end

	end

class

class Twi
    def self.get_followers(client, user_id)
		follower_ids = []
		next_cursor = -1
		while next_cursor != 0
			cursor = client.follower_ids(user_id, :cursor => next_cursor)
			follower_ids.concat cursor.attrs[:ids]
			next_cursor = cursor.send(:next_cursor)
		end

		followers = []
		follower_ids.each_slice(100) do |ids|
			followers.concat client.users(ids)
		end
		begin
			followers_total = []
			followers.each_with_index do |user, _index|
				followers_total << user.id
				puts "adding follower to an array: #{user.screen_name}"
			end
		rescue Twitter::Error::TooManyRequests
			[]
			puts "rescue Twitter::Error #{Time.now}"
			sleep 905
			retry
		end
	end
    
    def self.get_friends(client, user_id)
		friend_ids = []
		next_cursor = -1
		begin
			while next_cursor != 0
				cursor = client.friend_ids(user_id, :cursor => next_cursor)
				friend_ids.concat cursor.attrs[:ids]
				next_cursor = cursor.send(:next_cursor)
			end
		rescue Twitter::Error::Unauthorized
			[]
		end
		friends = []
		friend_ids.each_slice(100) do |ids|
			friends.concat client.users(ids)
		end
		begin
			friends_total = []
			friends.each_with_index do |user, _index|
				friends_total << user.id
				puts "adding friend to an array: #{user.screen_name}"
			end
		rescue Twitter::Error::TooManyRequests
			[]
			puts "rescue Twitter::Error #{Time.now}"
			sleep 905
			retry
		end
	end
	
    def self.follow(client, follow)
        counter = 0
		begin
			follow.take(100).reverse_each do |user| if counter <= 2
				client.follow(user)
				follow.delete(user)
				puts "follow: #{user.screen_name} #{Time.now}"
				sleep rand(1..5)
			end
    end
		rescue Twitter::Error::TooManyRequests, Twitter::Error::Forbidden, OpenSSL::SSL::SSLError, Twitter::Error::ServiceUnavailable, HTTP::ConnectionError
			[]
			puts "rescue Twitter::Error #{Time.now}"
            counter += 1
			sleep 905
			retry
		end
	end
    
	def self.unfollow(client, unfollow)
		begin
			unfollow.take(1000).reverse_each do |user|
				client.unfollow(user)
				unfollow.delete(user)
				puts "unfollow: #{user.screen_name} #{Time.now}"
				sleep rand(1..5)
			end
		rescue Twitter::Error::TooManyRequests, Twitter::Error::Forbidden, OpenSSL::SSL::SSLError, Twitter::Error::ServiceUnavailable, HTTP::ConnectionError
			[]
			puts "rescue Twitter::Error #{Time.now}"
			sleep 905
			retry
		end
	end

	def self.retweet(config, topics)    
		counter = 0
		while counter <= 15
			begin
				rClient = Twitter::REST::Client.new config
				sClient = Twitter::Streaming::Client.new(config)
				sClient.filter(track: topics.join(',')) do |tweet|
					if tweet.is_a?(Twitter::Tweet)
						puts tweet.text
						rClient.retweet tweet
						counter += 1
						sleep rand(1..15)
					end
				end
			rescue StandardError
				puts 'error occurred, waiting for 5 seconds'
				counter += 1
				sleep 5
			end
		end
	end

	def self.post(config, array_posts)
		client = Twitter::REST::Client.new config
		array_posts.each do |i|
			client.update(i)
			sleep rand(1..10)
		end
	end

end

 

Тем не менее, в качестве "домашнего" (open source и полностью бесплатно) "средства ухода" за своим тви-акком - приложение вполне имеет право на существование: как видите, в полностью автоматическом режиме вычисляются идентификаторы аккаунтов, которые далее фолловятся и анфолловятся, также приложение умеет искать твиты по заданным хеш-тегам - одному или нескольким - и ретвитить; также реализован постинг твитов (каждый твит с новой строчки) через рандомные промежутки времени. Разумеется, приложение способно не только хранить любое число аккаунтов для входа и токены доступа для любого количества твиттер-аккаунтов, но и легко переключаться между ними; что на данный момент представляется мне уже, к сожалению, избыточностью.

 

Оставить комментарий

Добавьте ваш комментарий