botinsta 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6aaa7af1d1799524017bfd68e099f63b940b8f99d7c5a39d1bf105c351419cdb
4
+ data.tar.gz: 8d38665b27b5a6aa1af0edfe34fc0f1129afe67682290ce8225e852c375f48ad
5
+ SHA512:
6
+ metadata.gz: 5876356f6bd056b4ed0e6ba5109ecd1cc70ac166186dc3be7bfaee94f9f50b2e214d256d2aafd9cdccd584ed9d1c47999b3fb0ca3a24abccbeb07476a7d034d0
7
+ data.tar.gz: 28fbf4d409672370fce4d796fcac09e0d45c0cfc024ff7318d13299599647c870c9a8f7c79987b824c2bd384fa833f87800373d8aee30218fdb9a7ccbb637596
data/.gitignore ADDED
@@ -0,0 +1,16 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ example/actions_db.db
10
+ example/test.rb
11
+ .idea/
12
+ Gemfile.lock
13
+ *.gem
14
+
15
+ # rspec failure tracking
16
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.5.1
7
+ before_install: gem install bundler -v 1.16.5
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 andreyuhai
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,117 @@
1
+ # Botinsta [![Build Status](https://travis-ci.com/andreyuhai/botinsta.svg?branch=master)](https://travis-ci.com/andreyuhai/botinsta) [![Gem Version](https://badge.fury.io/rb/botinsta.svg)](https://badge.fury.io/rb/botinsta)
2
+
3
+ ## Description
4
+
5
+ This is a **tag-based Instagram bot** I've created under the influence of other cool Instagram bots [instabot.py](https://github.com/instabot-py) and [instabot.rb](https://github.com/eVanilla/instabot.rb/) to improve my Ruby skills.
6
+
7
+ #### What do you mean tag-based?!
8
+
9
+ Well, tag-based means that the bot works based on solely the tags you specified. You specify the tags you want the bot to like medias and follow users from and it loops through all tags liking a number of medias specified by you and also following the owners of medias it liked. See [how it works](#usage--how-it-works)
10
+
11
+ ## Installation
12
+
13
+ Add this line to your application's Gemfile:
14
+
15
+ ```ruby
16
+ gem 'botinsta'
17
+ ```
18
+
19
+ And then execute:
20
+
21
+ $ bundle
22
+
23
+ Or install it yourself as:
24
+
25
+ $ gem install botinsta
26
+
27
+ ## Features
28
+
29
+ * Follow
30
+ * Like
31
+ * Unfollow people followed after a day. Creates a local database for that.
32
+ * Avoid liking blacklisted tags
33
+
34
+ ## Features to come
35
+
36
+ * Comments
37
+ * Unlike medias
38
+ * Avoid following blacklisted users
39
+
40
+ I am still not sure what else to add but if you have any idea don't hesitate to hit me up or send me a pull request!
41
+
42
+ ## Usage & How it works
43
+
44
+ You can use the bot simply like below. It already has default parameters so you could just input your `username` and `password` and let it use the defaults for the rest.
45
+
46
+ ```ruby
47
+ require 'botinsta'
48
+
49
+ bot = Botinsta.new ({ username: 'YOUR_USERNAME',
50
+ password: 'YOUR_PASSWORD',
51
+ tags: ['photography','vsco','fotografia'],
52
+ tag_blacklist: ['nsfw','sexy','hot'],
53
+ likes_per_tag: 20,
54
+ unfollows_per_run: 200,
55
+ follows_per_tag: 10
56
+ })
57
+
58
+ bot.start
59
+ ```
60
+
61
+ The bot loops through each tag liking as many images as `@likes_per_tag` and following as many users as `@follows_per_tag`.
62
+
63
+ Liking medias and following users from the tag's first page is easy because all you have to do is:
64
+
65
+ https://instagram.com/explore/tags/YOURTAG/?__a=1
66
+
67
+ to navigate to above link and get the JSON string then parse it accordingly
68
+ to extract necessary information (i.e. media ID, owner ID).
69
+
70
+ It gets complicated when you liked all the medias on the first page and need to get the next page—with next page I am referring to when you scroll down the page to load more content—to continue extracting data, liking medias & following users. So we can do the same with a `GET` request instead since we are using `Mechanize` for automation.
71
+
72
+ To get the next page you need two things:
73
+
74
+ * query\_id (query\_hash)
75
+ * end\_cursor
76
+
77
+ which will be used in GET requests to get the JSON string for the next page.
78
+
79
+ An example of the link:
80
+
81
+ https://www.instagram.com/graphql/query/?query_hash=1780c1b186e2c37de9f7da95ce41bb67&variables={"tag_name":"photography","first":4,"after":"AQAiksCP1Uzk5-bXZ3qnwUsA89YRn1LBia9_yDFeWm5S1KTfzyU8eH8EFjq8LPuFOemdkRjzWb8_5vmyQ8Gnj-sTCfVGwRHs8WoKhPtBncmLbg"}
82
+
83
+ As you can see we need to provide the query\_id (query\_hash) and end\_cursor (the same as `after`) in the link.
84
+
85
+ We get the above parameters with the help of methods in the module [Pages]() below:
86
+
87
+ ## Documentation
88
+
89
+ * [Documentation](https://www.rubydoc.info/github/andreyuhai/botinsta/master)
90
+
91
+ I will eventually complete all method descriptions and usages. You can help me if you would like to!
92
+
93
+ ## Development
94
+
95
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
96
+
97
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
98
+
99
+ ## Gems used
100
+
101
+ * Colorize
102
+ * Hashie
103
+ * Json
104
+ * Mechanize
105
+ * Nokogiri
106
+ * Sequel
107
+ * Sqlite3
108
+
109
+ ## Contributing
110
+
111
+ Bug reports and pull requests are welcome on GitHub at https://github.com/andreyuhai/botinsta.
112
+
113
+ If you like the bot and want to see the new features very soon, please do not forget to star the repo to let me now you are interested. Boost me! :rocket: :blush:
114
+
115
+ ## License
116
+
117
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'botinsta'
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/botinsta.gemspec ADDED
@@ -0,0 +1,33 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'botinsta/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'botinsta'
7
+ spec.version = Botinsta::VERSION
8
+ spec.authors = ['andreyuhai']
9
+ spec.email = ['yuhai.ndre@gmail.com']
10
+
11
+ spec.summary = 'Ruby Instagram bot'
12
+ spec.description = 'A tag-based Instagram bot which works without using any Instagram API.'
13
+ spec.homepage = 'https://github.com/andreyuhai/botinsta'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files`.split("\n")
17
+ spec.bindir = 'exe'
18
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_runtime_dependency 'colorize', ['~> 0.8.1']
22
+ spec.add_runtime_dependency 'hashie', ['~> 3.6']
23
+ spec.add_runtime_dependency 'mechanize', ['~> 2.7', '>= 2.7.6']
24
+ spec.add_runtime_dependency 'nokogiri', ['~> 1.8', '>= 1.8.4']
25
+ spec.add_runtime_dependency 'pry', ['~> 0.11.3']
26
+ spec.add_runtime_dependency 'rb-readline', ['~> 0.5.5']
27
+ spec.add_runtime_dependency 'sequel', ['~> 5.12']
28
+ spec.add_runtime_dependency 'sqlite3', ['~> 1.3', '>= 1.3.13']
29
+
30
+ spec.add_development_dependency 'bundler', '~> 1.16'
31
+ spec.add_development_dependency 'rake', '~> 10.0'
32
+ spec.add_development_dependency 'rspec', '~> 3.0'
33
+ end
@@ -0,0 +1,12 @@
1
+ require 'botinsta'
2
+
3
+ bot = Botinsta.new ({ username: 'YOUR_USERNAME',
4
+ password: 'YOUR_PASSWORD',
5
+ tags: ['photography','vsco','b&w'],
6
+ likes_per_tag: 60,
7
+ tag_blacklist: ['nsfw','sexy','hot'],
8
+ unfollows_per_run: 200,
9
+ follows_per_tag: 10
10
+ })
11
+
12
+ bot.start
data/lib/botinsta.rb ADDED
@@ -0,0 +1,56 @@
1
+ require 'colorize'
2
+ require 'hashie'
3
+ require 'json'
4
+ require 'mechanize'
5
+ require 'sequel'
6
+ require 'sqlite3'
7
+ require 'nokogiri'
8
+
9
+ require_relative 'botinsta/class_methods'
10
+
11
+ # This is our main class from which we will be
12
+ # instantiating our bot.
13
+ class Botinsta
14
+
15
+ include ClassMethods
16
+
17
+ DEFAULT_PARAMETERS = { tags: %w[photography fotografia vsco],
18
+ tag_blacklist: %w[nsfw hot sexy],
19
+ user_blacklist: [],
20
+ likes_per_tag: 10,
21
+ unfollows_per_run: 200,
22
+ follows_per_tag: 50
23
+ }.freeze
24
+
25
+ def initialize(**params)
26
+
27
+ params = DEFAULT_PARAMETERS.merge(params)
28
+
29
+ @username = params[:username]
30
+ @password = params[:password]
31
+ @tags = params[:tags]
32
+ @tag_blacklist = params[:tag_blacklist]
33
+ @user_blacklist = params[:user_blacklist]
34
+ @likes_per_tag = params[:likes_per_tag]
35
+ @follows_per_tag = params[:follows_per_tag]
36
+ @unfollows_per_run = params[:unfollows_per_run]
37
+
38
+ @total_likes = 0
39
+ @total_follows = 0
40
+ @total_unfollows = 0
41
+
42
+ @agent = Mechanize.new
43
+
44
+ handle_database_creation
45
+ return if @table_follows.empty?
46
+
47
+ @first_db_entry = @table_follows.first
48
+ @last_follow_time = @table_follows.first[:follow_time]
49
+ end
50
+
51
+ def start
52
+ login
53
+ tag_based_mode
54
+ logout
55
+ end
56
+ end
@@ -0,0 +1,108 @@
1
+ # Various actions you can do on Instagram
2
+ # and other related methods.
3
+ module Actions
4
+
5
+ # Likes media given by media id.
6
+ #
7
+ # @param media_id [String]
8
+ # @return [true, false] returns true on success, false otherwise.
9
+ def like_media(media_id)
10
+ url_like = "https://www.instagram.com/web/likes/#{media_id}/like/"
11
+ print_try_message(action: :like, data: media_id)
12
+ begin
13
+ set_request_params
14
+ response = @agent.post url_like, @params, @request_headers
15
+ rescue Mechanize::ResponseCodeError
16
+ return false
17
+ end
18
+ response_data = JSON.parse(response.body)
19
+ response.code == '200' && response_data['status'] == 'ok' ? true : false
20
+ end
21
+
22
+ # Unlikes media given by media id.
23
+ #
24
+ # @param media_id [String]
25
+ # @return (see #like_media)
26
+ def unlike_media(media_id)
27
+ url_unlike = "https://www.instagram.com/web/likes/#{media_id}/unlike/"
28
+ print_try_message(action: :unlike, data: media_id)
29
+ begin
30
+ set_request_params
31
+ response = @agent.post url_unlike, @params, @request_headers
32
+ rescue Mechanize::ResponseCodeError
33
+ return false
34
+ end
35
+ response_data = JSON.parse(response.body)
36
+ response.code == '200' && response_data['status'] == 'ok' ? true : false
37
+ end
38
+
39
+ # Follows user given by user_id.
40
+ #
41
+ # @param user_id [String]
42
+ # @return (see #like_media)
43
+ def follow_user(user_id)
44
+ url_follow = "https://www.instagram.com/web/friendships/#{user_id}/follow/"
45
+ print_try_message(action: :follow, data: user_id)
46
+ begin
47
+ set_request_params
48
+ response = @agent.post url_follow, @params, @request_headers
49
+ rescue Mechanize::ResponseCodeError
50
+ return false
51
+ end
52
+ response_data = JSON.parse(response.body)
53
+ response.code == '200' && response_data['result'] == 'following' ? true : false
54
+ end
55
+
56
+ # Unfollows user given by user_id.
57
+ #
58
+ # @param user_id [String]
59
+ # @return (see #like_media)
60
+ def unfollow_user(user_id)
61
+ url_unfollow = "https://www.instagram.com/web/friendships/#{user_id}/unfollow/"
62
+ print_try_message(action: :unfollow, data: user_id)
63
+ begin
64
+ set_request_params
65
+ response = @agent.post url_unfollow, @params, @request_headers
66
+ rescue Mechanize::ResponseCodeError
67
+ return false
68
+ end
69
+ response_data = JSON.parse(response.body)
70
+ response.code == '200' && response_data['status'] == 'ok' ? true : false
71
+ end
72
+
73
+ # Likes the media if it doesn't exist in the database.
74
+ #
75
+ # @param media [MediaData] a MediaData instance.
76
+ # @return (see #like_media)
77
+ def like_if_not_in_db(media)
78
+ return false if media.exists_in_db?(@table_likes)
79
+
80
+ if like_media(media.id)
81
+ @total_likes += 1
82
+ print_success_message(action: :like, number: @total_likes, data: @media.id)
83
+ media.insert_into_db(@table_likes)
84
+ sleep_rand(28, 36)
85
+ true
86
+ else
87
+ false
88
+ end
89
+ end
90
+
91
+ # Follows the user if it doesn't exist in the database.
92
+ #
93
+ # @param user [UserData] a UserData instance.
94
+ # @return (see #like_media)
95
+ def follow_if_not_in_db(user)
96
+ return false if user.exists_in_db?(@table_follows)
97
+
98
+ if follow_user(user.id)
99
+ @total_follows += 1
100
+ print_success_message(action: :follow, number: @total_follows, data: @user.username)
101
+ user.insert_into_db(@table_follows)
102
+ sleep_rand(28, 36)
103
+ true
104
+ else
105
+ false
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,21 @@
1
+ require_relative 'actions'
2
+ require_relative 'data/media_data'
3
+ require_relative 'data/user_data'
4
+ require_relative 'data/page_data'
5
+ require_relative 'helpers'
6
+ require_relative 'login'
7
+ require_relative 'modes'
8
+ require_relative 'pages'
9
+ require_relative 'requests'
10
+
11
+
12
+ module ClassMethods
13
+
14
+ include Actions
15
+ include Helpers
16
+ include Login
17
+ include Modes
18
+ include Pages
19
+ include Requests
20
+
21
+ end