11# -*- coding: utf-8 -*-
22""" Module which handles the commenting features """
3-
3+ # import built-in & third-party modules
44import random
55import emoji
66
7+ # import InstaPy modules
78from .time_util import sleep
89from .util import update_activity
910from .util import add_user_to_blacklist
1011from .util import click_element
1112from .util import get_action_delay
1213from .util import explicit_wait
13- from .util import extract_text_from_element
1414from .util import web_address_navigator
1515from .util import evaluate_mandatory_words
1616from .event import Event
1717from .quota_supervisor import quota_supervisor
1818from .xpath import read_xpath
1919
20+ # import exceptions
2021from selenium .common .exceptions import WebDriverException
2122from selenium .common .exceptions import InvalidElementStateException
2223from selenium .common .exceptions import NoSuchElementException
@@ -157,16 +158,14 @@ def verify_commenting(browser, maximum, minimum, logger):
157158 return False , disapproval_reason
158159
159160 if maximum is not None and comments_count > maximum :
160- disapproval_reason = (
161- "Not commented on this post! ~more comments exist"
162- " off maximum limit at {}" .format (comments_count )
161+ disapproval_reason = "Not commented on this post! ~more comments exist off maximum limit at {}" .format (
162+ comments_count
163163 )
164164 return False , disapproval_reason
165165
166166 elif minimum is not None and comments_count < minimum :
167- disapproval_reason = (
168- "Not commented on this post! ~less comments exist"
169- " off minumum limit at {}" .format (comments_count )
167+ disapproval_reason = "Not commented on this post! ~less comments exist off minumum limit at {}" .format (
168+ comments_count
170169 )
171170 return False , disapproval_reason
172171
@@ -238,106 +237,97 @@ def get_comments_on_post(
238237 browser , owner , poster , amount , post_link , ignore_users , randomize , logger
239238):
240239 """ Fetch comments data on posts """
241-
242240 web_address_navigator (browser , post_link )
243241
244- orig_amount = amount
242+ comments = []
243+ commenters = []
244+
245245 if randomize is True :
246246 amount = amount * 3
247247
248248 # check if commenting on the post is enabled
249- commenting_state , msg = is_commenting_enabled (browser , logger )
250- if commenting_state is not True :
251- logger .info (msg )
252- return None
253-
254- # check if there are any comments in the post
255- comments_count , msg = get_comments_count (browser , logger )
256- if not comments_count :
257- logger .info (msg )
249+ (commenting_approved , disapproval_reason ,) = verify_commenting (
250+ browser ,
251+ None ,
252+ None ,
253+ logger ,
254+ )
255+ if not commenting_approved :
256+ logger .info (disapproval_reason )
258257 return None
259258
260- # get comments & commenters information
261-
262- # efficient location
263- comments_block_XPath = read_xpath (get_comments_on_post .__name__ , "comments_block" )
264- # path
259+ # get comments & commenters information path
265260 like_button_full_XPath = read_xpath (
266261 get_comments_on_post .__name__ , "like_button_full_XPath"
267262 )
268263 unlike_button_full_XPath = read_xpath (
269264 get_comments_on_post .__name__ , "unlike_button_full_XPath"
270265 )
271266
272- comments = []
273- commenters = []
274267 # wait for page fully load [IMPORTANT!]
275268 explicit_wait (browser , "PFL" , [], logger , 10 )
276269
277270 try :
278271 all_comment_like_buttons = browser .find_elements_by_xpath (
279272 like_button_full_XPath
280273 )
274+
281275 if all_comment_like_buttons :
282- comments_block = browser .find_elements_by_xpath (comments_block_XPath )
283- for comment_line in comments_block :
284- commenter_elem = comment_line .find_element_by_xpath (
285- read_xpath (get_comments_on_post .__name__ , "commenter_elem" )
286- )
287- commenter = extract_text_from_element (commenter_elem )
276+ commenter = None
277+ comment = None
278+
279+ data = browser .execute_script (
280+ "return window.__additionalData[Object.keys(window.__additionalData)].data."
281+ "graphql.shortcode_media.edge_media_to_parent_comment"
282+ )
283+ for value in data ["edges" ]:
284+ commenter = value ["node" ]["owner" ]["username" ]
285+ comment = value ["node" ]["text" ]
286+
288287 if (
289288 commenter
290- and commenter not in [owner , poster , ignore_users ]
291289 and commenter not in commenters
290+ and commenter not in [owner , poster , ignore_users ]
291+ and comment
292292 ):
293293 commenters .append (commenter )
294- else :
295- continue
296-
297- comment_elem = comment_line .find_elements_by_tag_name ("span" )[0 ]
298- comment = extract_text_from_element (comment_elem )
299- if comment :
300294 comments .append (comment )
301295 else :
302- commenters .remove (commenters [- 1 ])
303- continue
296+ logger .info ("Could not grab any commenter from this post" )
304297
305298 else :
306299 comment_unlike_buttons = browser .find_elements_by_xpath (
307300 unlike_button_full_XPath
308301 )
302+
309303 if comment_unlike_buttons :
310304 logger .info (
311- "There are {} comments on this post and all "
312- "of them are already liked." .format (len (comment_unlike_buttons ))
305+ "Grabbed {} comment(s) on this post and already liked." .format (
306+ len (comment_unlike_buttons )
307+ )
313308 )
314309 else :
315310 logger .info ("There are no any comments available on this post." )
316311 return None
317312
318313 except NoSuchElementException :
319- logger .info ("Failed to get comments on this post." )
314+ logger .info ("Failed to grab comments on this post." )
320315 return None
321316
322317 if not comments :
323- logger .info ("Could not grab any usable comments from this post.." )
318+ logger .info ("Could not grab any usable comments from this post... " )
324319 return None
325320
326321 else :
327322 comment_data = list (zip (commenters , comments ))
328323 if randomize is True :
329324 random .shuffle (comment_data )
330325
331- if len (comment_data ) < orig_amount :
332- logger .info (
333- "Could grab only {} usable comments from this post.." .format (
334- len (comment_data )
335- )
336- )
337- else :
338- logger .info (
339- "Grabbed {} usable comments from this post.." .format (len (comment_data ))
326+ logger .info (
327+ "Grabbed only {} usable comment(s) from this post..." .format (
328+ len (comment_data )
340329 )
330+ )
341331
342332 return comment_data
343333
@@ -382,29 +372,52 @@ def get_comments_count(browser, logger):
382372 ".graphql.shortcode_media.edge_media_preview_comment.count"
383373 )
384374
385- # media_edge_string = get_media_edge_comment_string(media)
386- # comments_count = media[media_edge_string]["count"]
387-
388375 except Exception as e :
389- try :
390- comments_count = browser .execute_script (
391- "return window.__additionalData[Object.keys(window.__additionalData)[0]].data"
392- ".graphql.shortcode_media.edge_media_preview_comment.count"
393- )
376+ msg = "Failed to get comments' count!\n \t {}" .format (str (e ).encode ("utf-8" ))
377+ return None , msg
394378
395- except Exception as e :
396- msg = "Failed to get comments' count!\n \t {}" .format (str (e ).encode ("utf-8" ))
397- return None , msg
379+ return comments_count , "Success"
398380
399- # if not comments_count:
400- # if comments_count == 0:
401- # msg = "There are no any comments in the post."
402- # return 0, msg
403- # else:
404- # msg = "Couldn't get comments' count."
405- # return None, msg
406381
407- return comments_count , "Success"
382+ def verify_commented_image (browser , link , owner , logger ):
383+ """ Fetch comments data on posts to determine if already commented """
384+
385+ web_address_navigator (browser , link )
386+
387+ # wait for page fully load [IMPORTANT!]
388+ explicit_wait (browser , "PFL" , [], logger , 10 )
389+
390+ try :
391+ commenter = None
392+ comment = None
393+ data = browser .execute_script (
394+ "return window.__additionalData[Object.keys(window.__additionalData)].data."
395+ "graphql.shortcode_media.edge_media_to_parent_comment"
396+ )
397+ for value in data ["edges" ]:
398+ commenter = value ["node" ]["owner" ]["username" ]
399+ comment = value ["node" ]["text" ]
400+
401+ if commenter and commenter == owner :
402+ message = (
403+ "--> The post has already been commented on before: '{}'" .format (
404+ comment
405+ )
406+ )
407+ return True , message
408+
409+ except NoSuchElementException :
410+ # Cannot be determined if the post has been comment by InstaPy user,
411+ # and then it will not be commented until next loop, maybe comments
412+ # on the post have been limited. Return True, to emulate or assume the
413+ # post has been commented by user.
414+ message = (
415+ "--> Failed to get comments on this post, will not comment the post..."
416+ )
417+ return True , message
418+
419+ message = "--> Could not found owner's comment in this post, trying to comment..."
420+ return None , message
408421
409422
410423def process_comments (
@@ -414,9 +427,11 @@ def process_comments(
414427 max_comments ,
415428 min_comments ,
416429 comments_mandatory_words ,
430+ owner ,
417431 user_name ,
418432 blacklist ,
419433 browser ,
434+ link ,
420435 logger ,
421436 logfolder ,
422437 publish = True ,
@@ -444,6 +459,7 @@ def process_comments(
444459 browser ,
445460 logger ,
446461 )
462+
447463 if not commenting_approved :
448464 logger .info (disapproval_reason )
449465 return False
@@ -453,6 +469,21 @@ def process_comments(
453469
454470 # smart commenting
455471 if comments and publish :
472+ # Check if InstaPy already commented on this post, it could be the
473+ # case that the image has been liked (manually) but not commented, so
474+ # we want to comment the post like usually we do.
475+ commented_image , message = verify_commented_image (browser , link , owner , logger )
476+
477+ if commented_image :
478+ # The post has already been commented, either manually or InstaPy
479+ # Commenting twice by InstaPy user is not allowd by now or could
480+ # not get comments on this post to check if InstaPy user commented
481+ # before, so will not comment until next check
482+ logger .info (message )
483+ return False
484+ else :
485+ logger .info (message )
486+
456487 comment_state , _ = comment_image (
457488 browser ,
458489 user_name ,
@@ -462,4 +493,8 @@ def process_comments(
462493 logfolder ,
463494 )
464495
496+ # Return to the target uset page
497+ user_link = "https://www.instagram.com/{}/" .format (user_name )
498+ web_address_navigator (browser , user_link )
499+
465500 return comment_state
0 commit comments