Пример #1
0
 def like_media(self, media_id, media_code, username):
     """
     Function is used to like user post using instagram public api
     (AJAX requests)
     :param media_id: id of the post
     :param media_code: code of the post
     :param username: username (of the followings)
     :return:
     """
     url_like = 'https://www.instagram.com/web/likes/{}/like/'.format(
         media_id)
     try:
         post_like = self.session.post(url_like)
         if post_like.status_code == 200:
             insta_logger.info('User {} post code #{} was liked'.format(
                 username, media_code))
             return 1
         else:
             insta_logger.error('Failed to like user {} post code #{},'
                                'status code: {}'.format(
                                    username, media_code,
                                    post_like.status_code))
     except Exception as e:
         insta_logger.error(
             'Exception raised while liking user {} post code #{}'
             'Exception: {}'.format(username, media_code, e))
Пример #2
0
def load_ignore_list():
    """
    Get names of users from file to be excluded from liking list
    :return: list of users to be ignored, empty list if file structure is
    modified or not found
    """
    dir_name = os.path.dirname(os.path.abspath(__file__))
    if os.path.exists(os.path.join(dir_name, 'ignore_list.txt')):
        with open('ignore_list.txt', 'r') as ignore_list_file:
            full_text = ignore_list_file.read()
            if full_text.find('Ignore list:') != -1:
                start_index = full_text.index('Ignore list:') + len(
                    'Ignore list:')
                list_raw = full_text[start_index:].split(',')
                insta_logger.info('Ignore list extracted')
                print('Ignore list extracted')
                return [account.strip() for account in list_raw]
            print('"Ignore list.txt" was edited incorrectly. '
                  'Can\'t create ignore list.'
                  ' Please see description.')
            insta_logger.error('Ignore list file incorrectly edited')
            return []
    print('No ignore list found')
    insta_logger.error('No ignore list found')
    return []
Пример #3
0
 def login(self, attempts=3):
     """
     Login to instagram account with 'requests'
     :param attempts: number of attempts to login, default is 3,
     shutting down if failed to login
     :return: 1 if login successful
     """
     print('-Trying to login to account to use public api')
     for attempt in range(attempts):
         try:
             print('-Login attempt {} of {}'.format(attempt + 1, attempts))
             self.session.get(self.login_url)
             csrf_token = self.session.cookies['csrftoken']
             self.session.headers.update({'X-CSRFToken': csrf_token})
             time.sleep(3)
             login_to_acc = self.session.post(self.login_url,
                                              data={
                                                  'username':
                                                  self.user_login,
                                                  'password':
                                                  self.user_password
                                              },
                                              allow_redirects=True)
             time.sleep(3)
             if login_to_acc.status_code == 200:
                 main_page = self.session.get(self.main_url)
                 if main_page.text.find(self.user_login) != -1:
                     print('--Successful login')
                     insta_logger.info('Requests: Successful login')
                     self.session.headers.update(
                         {'X-CSRFToken': login_to_acc.cookies['csrftoken']})
                     self.logged_in = True
                     return 1
                 print('--Login failed, wrong credentials')
                 insta_logger.error('Requests: Login failed (status code: '
                                    '{}), credentials: login: {} password:'******' {}, attempt: {}'.format(
                                        login_to_acc.status_code,
                                        self.user_login, self.user_password,
                                        attempt))
             else:
                 print('--Login failed, status code: {}'.format(
                     login_to_acc.status_code))
                 insta_logger.error('Requests: login failed (status code: '
                                    '{}), credentials: login: {} password: '******'{}, attempt: {}'.format(
                                        login_to_acc.status_code,
                                        self.user_login, self.user_password,
                                        attempt))
         except Exception as e:
             insta_logger.error(
                 'Requests: login error, Exception: {}, attempt {}'.format(
                     e, attempt + 1))
             print('--Failed. Exception raised.')
     insta_logger.critical('Requests: unable to login.' 'Shutting down')
     insta_logger.info('--------------STOP---------------')
     print('Unable to login. Refer to log file. ' 'Shutting down')
     sys.exit()
Пример #4
0
    def login(self, timeout=10, attempts=3):
        """
        Login to account using Selenium and PhantomJS headless browser
        :param timeout: Number of seconds before timing out
        :param attempts: number of attempts to login, default is 3,
        shutting down if failed to login
        :return:
        """
        for attempt in range(attempts):
            print('-Login with Selenium, attempt {} of {}'.format(
                attempt + 1, attempts))
            try:
                self.driver.get(self.login_page)
                WebDriverWait(
                    self.driver, timeout=timeout).until(
                    EC.presence_of_element_located((
                        By.XPATH,
                        '/html/body/span/section/main/div/article/div/'
                        'div[1]/div/form/div[1]/input')))
                login = self.driver.find_element(
                    By.XPATH,
                    '/html/body/span/section/main/div/article/'
                    'div/div[1]/div/form/div[1]/input')
                login.send_keys(self.user_login)
                password = self.driver.find_element(
                    By.XPATH,
                    '/html/body/span/section/main/div/article/div/'
                    'div[1]/div/form/div[2]/input')
                password.send_keys(self.user_password)
                btn = self.driver.find_element(
                    By.XPATH,
                    '/html/body/span/section/main/div/article'
                    '/div/div[1]/div/form/span/button')
                btn.click()
                time.sleep(5)
                if self.driver.current_url == self.main_url:
                    print('--Login successful')
                    insta_logger.info('Selenium: login successful')
                    return 1
                print('--Unable to login with given credentials, attempt {}'
                      ''.format(attempt + 1))
                insta_logger.error('Selenium: login fail, wrong credentials,'
                                   ' attempt #{}'.format(attempt + 1))

            except Exception as e:
                insta_logger.error(
                    'Selenium: login error, Exception: {}, attempt {}'.format(
                        e, attempt + 1))
                print('--Failed. Exception raised.')
        insta_logger.critical('Selenium: unable to login.'
                              'Shutting down')
        insta_logger.info('--------------STOP---------------')
        print('Unable to login. Refer to log file. '
              'Shutting down')
        sys.exit()
Пример #5
0
 def logout(self):
     """
     Logout from account with 'requests'
     :return:
     """
     try:
         logout_page = self.session.get(self.logout_url)
         time.sleep(3)
         if logout_page.status_code == 200:
             insta_logger.info('Successful logout')
         else:
             insta_logger.error('Failed logout, status code: {}'.format(
                 logout_page.status_code))
     except Exception as e:
         insta_logger.error('Failed logout, exception: {}'.format(e))
Пример #6
0
def write_likes(total_likes):
    """
    Write number of likes made by bot and current time stamp to json file:
     {"total_likes": "total likes", "timestamp": "timestamp"}
    :param total_likes: number of likes
    :return:
    """
    dir_name = os.path.dirname(os.path.abspath(__file__))
    with open(os.path.join(dir_name, 'likes_count.json'), 'w') as likes_file:
        try:
            likes = json.load(likes_file)
        except io.UnsupportedOperation:
            likes = {'total_likes': total_likes, 'timestamp': time()}
        likes['total_likes'] = total_likes
        likes['timestamp'] = time()
        json.dump(likes, likes_file)
        insta_logger.info('Likes made by bot is writen to file, '
                          'total posts liked: {}'.format(total_likes))
Пример #7
0
 def check_likes_limit(self, write_timestamp=True):
     """
     Checks if likes made by bot not exceeds limit (1000 likes)
     If likes made today equal limit - exit program.
     :return:
     """
     if not self.ignore_limit:
         if self.total_likes >= 1000:
             insta_logger.critical('Bot liked 1000 posts in recent '
                                   '24 hours,'
                                   'stopping bot to avoid ban')
             if write_timestamp:
                 write_likes(self.total_likes)
             insta_logger.info('--------------STOP---------------')
             print('Bot liked 1000 posts in recent 24 hours, '
                   'stopping bot to avoid ban')
             if self.public_api.logged_in:
                 self.public_api.logout()
             sys.exit()
Пример #8
0
 def liking_all_posts(self):
     """
     Liking followings posts using 'InstApi' 'like_media' method
     :return:
     """
     total_posts = self.calc_num_of_posts(self.posts_to_like)
     if total_posts == 0:
         insta_logger.critical('No posts to like, shutting down')
         insta_logger.info('--------------STOP---------------')
         print('No posts to like. Shutting down.')
         self.public_api.logout()
         sys.exit()
     print('-Liking followings posts')
     print('--Total posts to like: {}'.format(total_posts))
     start_time = current_time()
     completion = 0
     liked = 0
     for user, posts in self.posts_to_like.items():
         for post in posts:
             self.check_likes_limit()
             like_post = self.public_api.like_media(media_id=post[1],
                                                    media_code=post[0],
                                                    username=user)
             if like_post:
                 liked += 1
                 self.total_likes += 1
             else:
                 self.like_errors += 1
                 self.like_error_posts.setdefault(user, set()).add(post)
                 if self.like_errors == self.like_error_limit:
                     self.like_errors = 0
                     print('\n')
                     print('\n oops, something is wrong,'
                           'login again after 5 minutes\n'
                           'please wait')
                     self.public_api.logout()
                     time.sleep(60 * 5)
                     insta_logger.info('Relogin attempt')
                     self.public_api.login()
                     print('Resume liking')
             completion += 1
             progress_bar(completion=completion,
                          total=total_posts,
                          start_time=start_time)
             time.sleep(1 * random.random())
     session_failed = self.calc_num_of_posts(self.like_error_posts)
     print('--Successfully liked in session: {}'.format(liked))
     insta_logger.info('Successfully liked in session: {}'.format(liked))
     print('--Failed to like in session: {}'.format(session_failed))
     insta_logger.info('Failed to like in '
                       'session: {}'.format(session_failed))
     write_likes(self.total_likes)
Пример #9
0
 def excluding_liked_posts(self):
     """
     Exclude data from the set of posts that have already been liked using
     'InstApi' 'check_like' method
     :return:
     """
     print('-Excluding posts that have already been liked')
     start_time = current_time()
     total_posts = self.calc_num_of_posts(self.posts_to_like)
     completion = 0
     for user, posts in self.posts_to_like.items():
         liked_posts = set()
         for post in posts:
             liked = self.public_api.check_like(media_code=post[0],
                                                username=user)
             if liked:
                 liked_posts.add(post)
             completion += 1
             progress_bar(completion=completion,
                          total=total_posts,
                          start_time=start_time)
         insta_logger.info('User {} total liked posts excluded: {}'.format(
             user, len(liked_posts)))
         posts.difference_update(liked_posts)
Пример #10
0
 def populate_post_list(self):
     """
     Populate posts to like from list of followings using 'InstApi'
     'get_recent_media_feed' method
     :return:
     """
     print('-Extracting users media')
     start_time = current_time()
     total_links = len(self.followings)
     completion = 0
     for user_url in self.followings:
         media_data = self.public_api.get_recent_media_feed(user_url)
         if media_data:
             self.posts_to_like.update(media_data)
         completion += 1
         progress_bar(completion=completion,
                      total=total_links,
                      start_time=start_time)
     if not self.posts_to_like:
         insta_logger.critical('No posts media extracted, shutting down')
         insta_logger.info('--------------STOP---------------')
         print('No posts to like. Shutting down.')
         self.public_api.logout()
         sys.exit()
Пример #11
0
 def reliking_failed_posts(self):
     """
     Liking posts, that 'bot' failed to like during first session
     :return:
     """
     total_posts_to_relike = self.calc_num_of_posts(self.like_error_posts)
     if total_posts_to_relike != 0:
         print('-Logout and sleep for 2 minutes before "reliking" session')
         insta_logger.info('Logout and sleep for 2 minutes before'
                           ' "reliking" session')
         self.public_api.logout()
         time.sleep(2 * 60)
         print('-Trying to relogin to relike "failed posts"')
         insta_logger.info('Relogin to like "failed posts"')
         self.public_api.login()
         start_time = current_time()
         completion = 0
         liked = 0
         failed_to_like = 0
         for user, posts in self.like_error_posts.items():
             for post in posts:
                 self.check_likes_limit()
                 like_post = self.public_api.like_media(media_id=post[1],
                                                        media_code=post[0],
                                                        username=user)
                 if like_post:
                     liked += 1
                     self.total_likes += 1
                 else:
                     failed_to_like += 1
                 completion += 1
                 progress_bar(completion=completion,
                              total=total_posts_to_relike,
                              start_time=start_time)
                 time.sleep(1 * random.random())
         print('--Successfully liked in relike session: {}'.format(liked))
         insta_logger.info(
             'Successfully liked in relike session: {}'.format(liked))
         print('--Failed to like in relike session: {}'.format(
             failed_to_like))
         insta_logger.info(
             'Failed to like in relike session: {}'.format(failed_to_like))
         write_likes(self.total_likes)
Пример #12
0
 def get_recent_media_feed(self, url):
     """
     Function gather data about user recent posts: posts ids and posts codes
     To get json response with user media data query param '?__a=1' must be
     added to end of url. Response return max value of 12 posts, to get more
     posts query param &max_id='page_num' must be added.
     :param url: instagram user url
     :return: dictionary with user as key and set of tuples with posts media
     code and media id as value
     """
     main_url = urljoin(url, '?__a=1')
     step = 0
     end_cursor = None
     username = urlparse(url)[2].strip('/')
     media_data = {username: set()}
     try:
         while step != self.pagination + 1:
             if end_cursor:
                 query = '&max_id={}'.format(end_cursor)
                 feed_url = '{}{}'.format(main_url, query)
             else:
                 feed_url = main_url
             feed_page_raw = self.session.get(feed_url)
             json_data = feed_page_raw.json()
             if username in self.ignore_list:
                 insta_logger.info(
                     'User {} is in ignore list'.format(username))
                 return
             try:
                 feed_data = json_data['user']['media']['nodes']
                 if feed_data:
                     for media in feed_data:
                         media_data[username].add(
                             (media['code'], media['id']))
                         if len(media_data[username]
                                ) >= self.posts_to_check:
                             insta_logger.info(
                                 'User {} media data extracted,'
                                 ' total media {}'.format(
                                     username, len(media_data[username])))
                             return media_data
                     step += 1
                     if json_data['user']['media']['page_info'][
                             'has_next_page']:
                         end_cursor = json_data['user']['media'][
                             'page_info']['end_cursor']
                         time.sleep(1 * random.random())
                     else:
                         break
                 else:
                     insta_logger.info(
                         'User {} has no media data, ignored'.format(
                             username))
                     return
             except KeyError:
                 insta_logger.error(
                     'Key error while getting media feed, user {}'.format(
                         username))
                 return
         insta_logger.info(
             'User {} media data extracted, total media {}'.format(
                 username, len(media_data[username])))
         return media_data
     except Exception as e:
         insta_logger.error('Exception raised while getting feed data,'
                            'Exeption: {}'.format(e))
Пример #13
0
 def crawl_folowing_links(self, timeout=15, attempts=3):
     """
     Crawl links from web page using Selenium.
     Paginate hidden links with scroll down script.
     :param timeout: Number of seconds before timing out
     :param attempts: number of attempts to get followings links,
      default is 3, shutting down if failed to get links
     :return: 1 if links extracted from web page successfully
     """
     for attempt in range(attempts):
         print('-Trying to get followings, attempt {} of {}'.format(
             attempt + 1, attempts))
         try:
             self.driver.get(self.user_page)
             time.sleep(3)
             WebDriverWait(
                 self.driver, timeout=timeout).until(
                 EC.presence_of_element_located((
                     By.CLASS_NAME,
                     '_s53mj')))
             total_following_web_elem = self.driver.find_element(
                 By.CSS_SELECTOR,
                 'a[href*="following"] > span')
             total_following = int(total_following_web_elem.text)
             folowing_button = self.driver.find_element(By.CSS_SELECTOR,
                                                        'a[href*='
                                                        '"following"]')
             print('--Total following to extract: {}'.format(
                 total_following))
             folowing_button.click()
             time.sleep(3)
             current_total = len(
                 self.driver.find_elements(By.CLASS_NAME, '_cx1ua'))
             while current_total != total_following:
                 self.driver.execute_script('window.scrollTo(0, document'
                                            '.body.scrollHeight);')
                 time.sleep(2)
                 current_total = len(
                     self.driver.find_elements(By.CLASS_NAME, '_cx1ua'))
                 sys.stdout.write('\r--Total followings'
                                  ' extracted: {}'.format(current_total))
                 sys.stdout.flush()
             sys.stdout.write('\n')
             links_web_elem = self.driver.find_elements(By.CLASS_NAME,
                                                        '_cx1ua')
             links = [link.find_element_by_tag_name(
                 'a').get_attribute('href') for link in links_web_elem]
             if len(links) == total_following:
                 insta_logger.info(
                     'Selenium: Followings links extracted successfully')
                 print('--Followings extracted successfully')
                 self.followings_list = links
                 return 1
             insta_logger.info(
                 'Selenium: failed to extract '
                 'Followings links, attempt #{}'.format(attempt + 1))
             print('--Failed')
         except Exception as e:
             insta_logger.error('Selenium: crawl_following exception '
                                'raised. Exception: {}, attempt #{}'.format(
                 e, attempt + 1))
             print('--Failed')
     insta_logger.critical(
         'Selenium: unable to get followings. Shutting down')
     insta_logger.info(
         '--------------STOP---------------')
     print(
         '\nUnable to get followings. Refer to log file. Shutting'
         ' down')
     sys.exit()
Пример #14
0
def main():
    bot = None
    try:
        # Parsing args from command-line
        args = parse_credentials()
        login = args.login
        password = args.password
        posts_to_check = args.number_of_posts
        ignore_limit = args.ignore_limit
        insta_logger.info('--------------START---------------')
        draw_line_separator()
        draw_logo()
        draw_line_separator()
        print('instabot is working:')
        draw_worker_text('populating ignore list')
        ignore_list = load_ignore_list()
        bot = LikingBot(user_login=login,
                        user_password=password,
                        ignore_list=ignore_list,
                        followings=None,
                        posts_to_check=posts_to_check,
                        ignore_limit=ignore_limit)
        # Check if likes limit not exceeds
        bot.check_likes_limit(write_timestamp=False)
        draw_line_separator()
        draw_worker_text('getting list of followings')
        print('#This could take a while, be patient#')

        # Selenium part:
        # using PhantomJS headless web browser to login and
        # gather links of the accounts that user follows
        web_driver = CrawlFollowing(user_login=login, user_password=password)
        web_driver.login()
        web_driver.crawl_folowing_links()
        followings_list = web_driver.followings_list
        web_driver.close()
        # Public api part using requests library:
        bot.followings = followings_list
        draw_line_separator()
        draw_worker_text('Liking posts')
        # Login with 'requests' to use instagram public api
        bot.public_api.login()
        bot.populate_post_list()  # Populating users media data
        # Excluding posts that have already been liked
        bot.excluding_liked_posts()
        bot.liking_all_posts()  # Liking all remaining posts
        if bot.calc_num_of_posts(bot.like_error_posts) != 0:
            bot.reliking_failed_posts()
        draw_worker_text('Work is done, bot is tired and shutting down.')
        draw_worker_text('For more info refer to today log file')
        insta_logger.info('End of the program. Shutting down')
        insta_logger.info('--------------STOP---------------')
        bot.public_api.logout()
        sys.exit()

    except KeyboardInterrupt:
        print('\nBot was interrupted by user. Shutting down')
        insta_logger.info('Program is interrupted by user. Shutting down')
        if bot and bot.public_api.logged_in:
            bot.public_api.logout()
        insta_logger.info('--------------STOP---------------')
        sys.exit()