Repository: InstaPy/InstaPy

Issue:
too few image, aborting
hello,

how to cope with system aborting because too few image?

can i add something so that when the first tag resluts too few image, instead of aborting, can continue to the second tag?


Discussion:

Resolving patch:
diff --git a/examples/example.py b/examples/example.py
--- a/examples/example.py
+++ b/examples/example.py
@@ -12,6 +12,9 @@
 #default enabled=False, ~ every 4th image will be commented on
 session.set_do_comment(enabled=True, percentage=25)
 session.set_comments(['Awesome', 'Really Cool', 'I like your stuff'])
+# you can also set comments for specific media types (Photo / Video)
+session.set_comments(['Nice shot!'], media='Photo')
+session.set_comments(['Great Video!'], media='Video')
 
 """Follow util"""
 #default enabled=False, follows ~ every 10th user from the images
@@ -56,9 +59,13 @@
 """Different tasks"""
 # you can put in as much tags as you want, likes 100 of each tag
 session.like_by_tags(['#test'], amount=100)
+# you can also set to like a specific media (Photo / Video)
+session.like_by_tags(['#test'], amount=10, media='Photo')
 
 #get's the tags from the description and likes 100 images of each tag
 session.like_from_image(url='www.instagram.com/image', amount=100)
+# media filtering works here as well
+session.like_by_tags(['#test'], amount=10, media='Video')
 
 session.unfollow_users(amount=10) #unfollows 10 of the accounts your following -> instagram will only unfollow 10 before you'll be 'blocked
 #  for 10 minutes' (if you enter a higher number than 10 it will unfollow 10, then wait 10 minutes and will continue then)
diff --git a/instapy/instapy.py b/instapy/instapy.py
--- a/instapy/instapy.py
+++ b/instapy/instapy.py
@@ -46,6 +46,8 @@ def __init__(self, username=None, password=None):
     self.do_comment = False
     self.comment_percentage = 0
     self.comments = ['Cool!', 'Nice!', 'Looks good!']
+    self.photo_comments = []
+    self.video_comments = []
 
     self.followed = 0
     self.follow_restrict = load_follow_restriction()
@@ -95,12 +97,23 @@ def set_do_comment(self, enabled=False, percentage=0):
 
     return self
 
-  def set_comments(self, comments=None):
+  def set_comments(self, comments=None, media=None):
     """Changes the possible comments"""
     if self.aborting:
       return self
 
+    if (media not in [None, 'Photo', 'Video']):
+      print('Unkown media type! Treating as "any".')
+      media = None
+
     self.comments = comments or []
+
+    if media is None:
+      self.comments = comments
+    else:
+      attr = '{}_comments'.format(media.lower())
+      setattr(self, attr, comments)
+
     return self
 
   def set_do_follow(self, enabled=False, percentage=0, times=1):
@@ -218,7 +231,8 @@ def set_lower_follower_count(self, limit=None):
     self.like_by_followers_lower_limit = limit or 0
     return self
 
-  def like_by_tags(self, tags=None, amount=50):
+  def like_by_tags(self, tags=None, amount=50, media=None):
+
     """Likes (default) 50 images per given tag"""
     if self.aborting:
       return self
@@ -238,7 +252,7 @@ def like_by_tags(self, tags=None, amount=50):
       self.logFile.write('--> {}\n'.format(tag.encode('utf-8')))
 
       try:
-        links = get_links_for_tag(self.browser, tag, amount)
+        links = get_links_for_tag(self.browser, tag, amount, media)
       except NoSuchElementException:
         print('Too few images, aborting')
         self.logFile.write('Too few images, aborting\n')
@@ -252,7 +266,7 @@ def like_by_tags(self, tags=None, amount=50):
         self.logFile.write(link)
 
         try:
-          inappropriate, user_name, reason = \
+          inappropriate, user_name, is_video, reason = \
             check_link(self.browser, link, self.dont_like, self.ignore_if_contains, self.ignore_users,
                        self.username, self.like_by_followers_upper_limit, self.like_by_followers_lower_limit)
 
@@ -279,9 +293,14 @@ def like_by_tags(self, tags=None, amount=50):
 
               if self.do_comment and user_name not in self.dont_include \
                   and checked_img and commenting:
-                commented += comment_image(self.browser,
-                                           temp_comments if temp_comments
-                                           else self.comments)
+                if temp_comments:
+                  # Use clarifai related comments only!
+                  comments = temp_comments
+                elif is_video:
+                  comments = self.comments + self.video_comments
+                else:
+                  comments = self.comments + self.photo_comments
+                commented += comment_image(self.browser, comments)
               else:
                 print('--> Not commented')
                 sleep(1)
@@ -321,7 +340,7 @@ def like_by_tags(self, tags=None, amount=50):
 
     return self
 
-  def like_from_image(self, url, amount=50):
+  def like_from_image(self, url, amount=50, media=None):
     """Gets the tags from an image and likes 50 images for each tag"""
     if self.aborting:
       return self
@@ -329,7 +348,7 @@ def like_from_image(self, url, amount=50):
     try:
       tags = get_tags(self.browser, url)
       print(tags)
-      self.like_by_tags(tags, amount)
+      self.like_by_tags(tags, amount, media)
     except TypeError as err:
       print('Sorry, an error occured: {}'.format(err))
       self.logFile.write('Sorry, an error occured: {}\n'.format(err))
diff --git a/instapy/like_util.py b/instapy/like_util.py
--- a/instapy/like_util.py
+++ b/instapy/like_util.py
@@ -6,41 +6,82 @@
 from .time_util import sleep
 
 
-def get_links_for_tag(browser, tag, amount):
+def get_links_for_tag(browser, tag, amount, media=None):
   """Fetches the number of links specified
   by amount and returns a list of links"""
+  if media is None:
+    # All known media types
+    media = ['', 'Post', 'Video']
+  elif media == 'Photo':
+    # Include posts with multiple images in it
+    media = ['', 'Post']
+  else:
+    # Make it an array to use it in the following part
+    media = [media]
+
   browser.get('https://www.instagram.com/explore/tags/'
               + (tag[1:] if tag[:1] == '#' else tag))
-
   sleep(2)
 
-  # clicking load more till there are 1000 posts
+  # clicking load more
   body_elem = browser.find_element_by_tag_name('body')
-
   sleep(2)
 
-  load_button = body_elem.find_element_by_xpath \
-    ('//a[contains(@class, "_8imhp _glz1g")]')
-  body_elem.send_keys(Keys.END)
-  sleep(2)
-
-  load_button.click()
+  abort = True
+  try:
+    load_button = body_elem.find_element_by_xpath \
+      ('//a[contains(@class, "_8imhp _glz1g")]')
+  except:
+    print('Load button not found, working with current images!')
+  else:
+    abort = False
+    body_elem.send_keys(Keys.END)
+    sleep(2)
+    load_button.click()
 
   body_elem.send_keys(Keys.HOME)
   sleep(1)
 
+  # Get links
   main_elem = browser.find_element_by_tag_name('main')
-
-  new_needed = int(ceil((amount - 33) / 12))
-
-  for _ in range(new_needed):  # add images x * 12
-    body_elem.send_keys(Keys.END)
-    sleep(1)
-    body_elem.send_keys(Keys.HOME)
-    sleep(1)
-
   link_elems = main_elem.find_elements_by_tag_name('a')
-  links = [link_elem.get_attribute('href') for link_elem in link_elems]
+  total_links = len(link_elems)
+  links = [link_elem.get_attribute('href') for link_elem in link_elems
+           if link_elem.text in media]
+  filtered_links = len(links)
+
+  while (filtered_links < amount) and not abort:
+    amount_left = amount - filtered_links
+    # Average items of the right media per page loaded
+    new_per_page = ceil(12 * filtered_links / total_links)
+    if new_per_page == 0:
+      # Avoid division by zero
+      new_per_page = 1. / 12.
+    # Number of page load needed
+    new_needed = int(ceil(amount_left / new_per_page))
+
+    if new_needed > 12:
+      # Don't go bananas trying to get all of instagram!
+      new_needed = 12
+
+    for i in range(new_needed):  # add images x * 12
+      # Keep the latest window active while loading more posts
+      before_load = total_links
+      browser.switch_to.window(browser.window_handles[-1])
+      body_elem.send_keys(Keys.END)
+      sleep(1)
+      browser.switch_to.window(browser.window_handles[-1])
+      body_elem.send_keys(Keys.HOME)
+      sleep(1)
+      link_elems = main_elem.find_elements_by_tag_name('a')
+      total_links = len(link_elems)
+      abort = (before_load == total_links)
+      if abort:
+        break
+
+    links = [link_elem.get_attribute('href') for link_elem in link_elems
+             if link_elem.text in media]
+    filtered_links = len(links)
 
   return links[:amount]
 
@@ -53,9 +94,10 @@ def check_link(browser, link, dont_like, ignore_if_contains, ignore_users,
   post_page = browser.execute_script("return window._sharedData.entry_data.PostPage")
   if post_page is None:
     print('Unavailable Page: {}'.format(link.encode('utf-8')))
-    return True, None, 'Unavailable Page'
+    return True, None, None, 'Unavailable Page'
 
   """Gets the description of the link and checks for the dont_like tags"""
+  is_video = browser.execute_script("return window._sharedData.entry_data.PostPage[0].media.is_video")
   user_name = browser.execute_script("return window._sharedData.entry_data.PostPage[0].media.owner.username")
   image_text = browser.execute_script("return window._sharedData.entry_data.PostPage[0].media.caption")
 
@@ -100,24 +142,25 @@ def check_link(browser, link, dont_like, ignore_if_contains, ignore_users,
     print('Number of Followers: {}'.format(num_followers))
 
     if like_by_followers_upper_limit and num_followers > like_by_followers_upper_limit:
-      return True, user_name, 'Number of followers exceeds limit'
+      return True, user_name, is_video, 'Number of followers exceeds limit'
     if like_by_followers_lower_limit and num_followers < like_by_followers_lower_limit:
-      return True, user_name, 'Number of followers does not reach minimum'
-
+      return True, user_name, is_video, 'Number of followers does not reach minimum'
+    
   print('Link: {}'.format(link.encode('utf-8')))
   print('Description: {}'.format(image_text.encode('utf-8')))
 
   """Check if the user_name is in the ignore_users list"""
   if (user_name in ignore_users) or (user_name == username):
-    return True, user_name, 'Username'
+    return True, user_name, is_video, 'Username'
 
   if any((word in image_text for word in ignore_if_contains)):
-      return False, user_name, 'None'
+      print('--> Ignoring content: ' + tag)
+      return False, user_name, is_video, 'None'
 
-  if any((tag in image_text for tag in dont_like)):
-      return True, user_name, 'Inappropriate'
+  image_text = image_text.lower()
+  if any((tag.lower() in image_text for tag in dont_like)):
+      return True, user_name, is_video, 'Inappropriate'
 
-  return False, user_name, 'None'
 
 def like_image(browser):
   """Likes the browser opened image"""
@@ -136,6 +179,7 @@ def like_image(browser):
     print('--> Invalid Like Element!')
     return False
 
+
 def get_tags(browser, url):
   """Gets all the tags of the given description in the url"""
   browser.get(url)


Test patch: