Instapy: Cannot focus element error

Created on 26 Oct 2017  Â·  32Comments  Â·  Source: timgrossmann/InstaPy

I'm running the script on mac and after some time i get this error:

Message: unknown error: cannot focus element
(Session info: chrome=61.0.3163.100)
(Driver info: chromedriver=2.32.498537 (cb2f855cbc7b82e20387eaf9a43f6b99b6105061),platform=Mac OS X 10.12.3 x86_64)

Now I'm trying to update chromedriver with all of the packages to check whether they are the reason, but does anybody else get this error?

bug help wanted

Most helpful comment

@timgrossmann Here's the PR including @katieywu's fix. #831 😄

All 32 comments

Im getting this same issue. Im failing on comments with the following stack trace and error:

File "/Users/alexmattson/Desktop/InstaPy/instapy/instapy.py", line 614, in like_by_tags
    self.browser, comments)
  File "/Users/alexmattson/Desktop/InstaPy/instapy/comment_util.py", line 25, in comment_image
    comment_input[0].send_keys("\b")
  File "/Library/Python/2.7/site-packages/selenium/webdriver/remote/webelement.py", line 349, in send_keys
    'value': keys_to_typing(value)})
  File "/Library/Python/2.7/site-packages/selenium/webdriver/remote/webelement.py", line 493, in _execute
    return self._parent.execute(command, params)
  File "/Library/Python/2.7/site-packages/selenium/webdriver/remote/webdriver.py", line 252, in execute
    self.error_handler.check_response(response)
  File "/Library/Python/2.7/site-packages/selenium/webdriver/remote/errorhandler.py", line 194, in check_response
    raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.WebDriverException: Message: unknown error: cannot focus element
  (Session info: chrome=61.0.3163.100)
  (Driver info: chromedriver=2.31.488774 (7e15618d1bf16df8bf0ecf2914ed1964a387ba0b),platform=Mac OS X 10.12.2 x86_64)

@diveu were you able to find a solution?

I'm getting the same error on Windows 10 with chromedriver 2.33.506120

upgraded to 2.33.506106 and still getting error on mac

I still get the failure when I run on the firefox webdriver but a different error:

  File "/Users/alexmattson/Desktop/InstaPy/instapy/instapy.py", line 614, in like_by_tags
    self.browser, comments)
  File "/Users/alexmattson/Desktop/InstaPy/instapy/comment_util.py", line 26, in comment_image
    comment_input[0].submit()
  File "/Library/Python/2.7/site-packages/selenium/webdriver/remote/webelement.py", line 82, in submit
    form = self.find_element(By.XPATH, "./ancestor-or-self::form")
  File "/Library/Python/2.7/site-packages/selenium/webdriver/remote/webelement.py", line 510, in find_element
    {"using": by, "value": value})['value']
  File "/Library/Python/2.7/site-packages/selenium/webdriver/remote/webelement.py", line 493, in _execute
    return self._parent.execute(command, params)
  File "/Library/Python/2.7/site-packages/selenium/webdriver/remote/webdriver.py", line 252, in execute
    self.error_handler.check_response(response)
  File "/Library/Python/2.7/site-packages/selenium/webdriver/remote/errorhandler.py", line 194, in check_response
    raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.StaleElementReferenceException: Message: The element reference of <textarea class="_bilrf"> stale: either the element is no longer attached to the DOM or the page has been refreshed

@alexmattson I haven't found anything yet. But I'll look into it later today, and if I find smth I'll write it here.

I managed to fix this issue on Chrome by changing instapy/comment_util.py

I moved the find element code from comment_image into its own function

def get_comment_input(browser):
    comment_input = browser.find_elements_by_xpath(
        '//textarea[@placeholder = "Add a comment…"]')
    if len(comment_input) <= 0:
        comment_input = browser.find_elements_by_xpath(
            '//input[@placeholder = "Add a comment…"]')
    return comment_input

And changed the beginning of the comment_image function to the following

def comment_image(browser, comments):
    """Checks if it should comment on the image"""
    rand_comment = (choice(comments))
    rand_comment = emoji.demojize(rand_comment)
    rand_comment = emoji.emojize(rand_comment, use_aliases=True)

    comment_input = get_comment_input(browser)
    comment_input[0].clear()
    comment_input = get_comment_input(browser)

    if len(comment_input) > 0:
        browser.execute_script(
            "arguments[0].value = '" + rand_comment + " ';", comment_input[0])

It seems that clearing the comment textarea (comment_input[0].clear()) and finding the element again fixes the issue.

@ateich thx, it worked!

@ateich You forgot small part which produces error sometimes

Instead

def comment_image(browser, comments):
    """Checks if it should comment on the image"""
    rand_comment = (choice(comments))
    rand_comment = emoji.demojize(rand_comment)
    rand_comment = emoji.emojize(rand_comment, use_aliases=True)

    comment_input = get_comment_input(browser)
    comment_input[0].clear()
    comment_input = get_comment_input(browser)

    if len(comment_input) > 0:
        browser.execute_script(
            "arguments[0].value = '" + rand_comment + " ';", comment_input[0])

use

def comment_image(browser, comments):
    """Checks if it should comment on the image"""
    rand_comment = (choice(comments))
    rand_comment = emoji.demojize(rand_comment)
    rand_comment = emoji.emojize(rand_comment, use_aliases=True)

    comment_input = get_comment_input(browser)
    comment_input[0].clear()
    comment_input = get_comment_input(browser)

    if len(comment_input) > 0:
        browser.execute_script(
            "arguments[0].value = '" + rand_comment + " ';", comment_input[0])
    else:
        print('--> Warning: Comment Action Likely Failed:'
              ' Comment Element not found')

    print("--> Commented: {}".format(rand_comment.encode('utf-8')))
    sleep(2)

    return 1

@HammerSpb Sorry if I wasn't clear. I didn't intend for my comment_image function to be a full replacement for the existing one. Instead, I was suggesting changing the first part of the function to the code I posted.

Thanks for posting the entire function. It should go a long way to alleviate any confusion for anyone else with the issue.

@HammerSpb Also, I noticed your comment_image function is missing the following lines from the original. Are you able to post comments without them?

# An extra space is added here and then deleted.
# This forces the input box to update the reactJS core
comment_input[0].send_keys("\b")
comment_input[0].submit()

Here is what my entire comment_util.py looks like

# -*- coding: utf-8 -*-
"""Module which handles the commenting features"""
from random import choice
from .time_util import sleep
import emoji

def get_comment_input(browser):
    comment_input = browser.find_elements_by_xpath(
        '//textarea[@placeholder = "Add a comment…"]')
    if len(comment_input) <= 0:
        comment_input = browser.find_elements_by_xpath(
            '//input[@placeholder = "Add a comment…"]')
    return comment_input

def comment_image(browser, comments):
    """Checks if it should comment on the image"""
    rand_comment = (choice(comments))
    rand_comment = emoji.demojize(rand_comment)
    rand_comment = emoji.emojize(rand_comment, use_aliases=True)

    comment_input = get_comment_input(browser)
    comment_input[0].clear()
    comment_input = get_comment_input(browser)

    if len(comment_input) > 0:
        browser.execute_script(
            "arguments[0].value = '" + rand_comment + " ';", comment_input[0])
        # An extra space is added here and then deleted.
        # This forces the input box to update the reactJS core
        comment_input[0].send_keys("\b")
        comment_input[0].submit()
    else:
        print('--> Warning: Comment Action Likely Failed:'
              ' Comment Element not found')

    print("--> Commented: {}".format(rand_comment.encode('utf-8')))
    sleep(2)

    return 1

@ateich You are absolutely right
But sometimes it doesn't work
I found a better solution and tested it few times.

comment_input[0].submit()
comment_input[0].send_keys("\b")
comment_input[0].submit()

Sometimes send_keys("\b") overwrite comment! But if you add submit() before calling send_keys("\b") everything works fine. Atleast for now

def comment_image(browser, comments):
    """Checks if it should comment on the image"""
    rand_comment = (choice(comments))
    rand_comment = emoji.demojize(rand_comment)
    rand_comment = emoji.emojize(rand_comment, use_aliases=True)

    comment_input = get_comment_input(browser)
    if len(comment_input) > 0:
        comment_input[0].clear()
    else:
        print('--> Warning: Comment Action Likely Failed:'
              ' Comment Element not found')
        return False

    comment_input = get_comment_input(browser)
    if len(comment_input) > 0:
        browser.execute_script(
            "arguments[0].value = '" + rand_comment + " ';", comment_input[0])
        comment_input[0].submit()
        comment_input[0].send_keys("\b")
        comment_input[0].submit()

    else:
        print('--> Warning: Comment Action Likely Failed:'
              ' Comment Element not found')
        return False

    print("--> Commented: {}".format(rand_comment.encode('utf-8')))
    sleep(2)

    return True

@HammerSpb send_keys("\b") is the equivalent of pressing the BACKSPACE key. It is there to delete an extra space at the end of the following line of code and force reactJS to update

browser.execute_script(
            "arguments[0].value = '" + rand_comment + " ';", comment_input[0])

Note that there is a space between the " and the ' before the semicolon
+ " ';"

The send_keys("\b") forces the input box to update the reactJS core of the Instagram website. The extra space at the end is there to make sure that the blank space is the deleted character. Maybe the reactJS core update is no longer necessary since we cleared the textarea earlier?

I haven't had a comment overwritten yet, but I'm glad to hear that you found a solution that is working for you 😃

@ateich Thanks for the help debugging! But I keep getting a new error with your revised code.

Now an IndexError: list index out of range

Also any idea on the /instapy.py, line 614, in like_by_tags? I was looking at issue #700 but seems slightly different.

image

comment_util.py
image

@HammerSpb @Xander8 HammerSpb, i copied your comment code and it seems to be working fine. I did run into 1 error ( the original one) but i think thats because i moved the window as it was trying to go to another post.

@Xander8 copy, Hammerspb's code exactly and your code should work - its a good fix for now.

@Xander8 It looks like comment_input contains no items, which means that the Add a comment... textarea/input is not visible on screen. This is most likely the result of the browser window not being wide enough. (Instagram hides the Add a comment... element on smaller width screens)

Changing comment_image to the following will stop the list index out of range exception from being thrown, but you will then get Warning: Comment Action Likely Failed: Comment Element not found

def comment_image(browser, comments):
    """Checks if it should comment on the image"""
    rand_comment = (choice(comments))
    rand_comment = emoji.demojize(rand_comment)
    rand_comment = emoji.emojize(rand_comment, use_aliases=True)

    comment_input = get_comment_input(browser)

    if len(comment_input) > 0:
        comment_input[0].clear()
        comment_input = get_comment_input(browser)

        browser.execute_script(
            "arguments[0].value = '" + rand_comment + " ';", comment_input[0])
        # An extra space is added here and then deleted.
        # This forces the input box to update the reactJS core
        comment_input[0].send_keys("\b")
        comment_input[0].submit()
    else:
        print('--> Warning: Comment Action Likely Failed:'
              ' Comment Element not found')

    print("--> Commented: {}".format(rand_comment.encode('utf-8')))
    sleep(2)

    return 1

To actually get the element back on the screen, you need to open chrome in a wider window. You can make chrome enter fullscreen on launch by adding chrome_options.add_argument("--start-fullscreen"); to instapy/instapy.py after line 129

instapy/instapy.py lines 128 to 133 would now look like

chromedriver_location = './assets/chromedriver'
chrome_options = Options()
chrome_options.add_argument("--start-fullscreen");
chrome_options.add_argument('--dns-prefetch-disable')
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--lang=en-US')

I'm not sure if this will work in VirtualBox, but I think it is your best bet. Let me know how it goes

@Xander8 After some more thought, here is a better solution that doesn't require Chrome to be fullscreen. (No need to change instapy/instapy.py)

I added the function open_comment_section, which will press the on screen comment (message bubble) button. This causes the comment_input textarea/input to appear regardless of window size.

So all we need to do now is call open_comment_section before get_comment_input, as is done in the code below

instapy/comment_utl.py

# -*- coding: utf-8 -*-
"""Module which handles the commenting features"""
from random import choice
from .time_util import sleep
import emoji

def get_comment_input(browser):
    comment_input = browser.find_elements_by_xpath(
        '//textarea[@placeholder = "Add a comment…"]')
    if len(comment_input) <= 0:
        comment_input = browser.find_elements_by_xpath(
            '//input[@placeholder = "Add a comment…"]')
    return comment_input

def open_comment_section(browser):
    comment_elem = browser.find_elements_by_xpath(
        "//a[@role='button']/span[text()='Comment']/..")
    if len(comment_elem) > 0:
        comment_elem[0].click()
    else:
        print('--> Warning: Comment Button Not Found:'
              ' May cause issues with browser windows of smaller widths')

def comment_image(browser, comments):
    """Checks if it should comment on the image"""
    rand_comment = (choice(comments))
    rand_comment = emoji.demojize(rand_comment)
    rand_comment = emoji.emojize(rand_comment, use_aliases=True)

    open_comment_section(browser)
    comment_input = get_comment_input(browser)

    if len(comment_input) > 0:
        comment_input[0].clear()
        comment_input = get_comment_input(browser)

        browser.execute_script(
            "arguments[0].value = '" + rand_comment + " ';", comment_input[0])
        # An extra space is added here and then deleted.
        # This forces the input box to update the reactJS core
        comment_input[0].send_keys("\b")
        comment_input[0].submit()
    else:
        print('--> Warning: Comment Action Likely Failed:'
              ' Comment Element not found')

    print("--> Commented: {}".format(rand_comment.encode('utf-8')))
    sleep(2)

    return 1

Changed the comment_util.py to the last @ateich suggestion, but still getting the same freaking error..any idea?

@AlessioBucaioni Could you post the error log you are receiving?

@ateich

Have been running your latest revision on my local MacBook Pro and so far the fix seems fairly stable. So far it's made it through 2 tags without failing so I'll report back later on today if it's completely acceptable.

This might even be the fix for my follow/unfollow issue. I'll report back on that one as well.

@RomeoJuliett I'm not sure if this is related to your unfollow issue, but I ran into a problem unfollowing users when the browser window is smaller. Specifically, at smaller window widths the "following" link tag moves outside of the header and breaks unfollow_util.py line 125

Replacing lines 125 to 127 fixed this issue for me

before

following_link = browser.find_elements_by_xpath(
                '//header/div[2]//li[3]')
following_link[0].click()

after

following_link = browser.find_elements_by_xpath(
                '//a[@href="/' + username + '/followers/"]')
following_link[0].send_keys("\n")

@ateich I've tried your code that you posted above, the one where you added open_comment_section but I sometimes get this error:

Traceback (most recent call last):
File "/Users/katieywu/Katie/Code/InstaPy/examples/katwu.py", line 91, in <module>
    amount=10)
File "/Users/katieywu/Katie/Code/InstaPy/instapy/instapy.py", line 531, in like_by_tags
    commented += comment_image(self.browser, comments)
File "/Users/katieywu/Katie/Code/InstaPy/instapy/comment_util.py", line 50, in comment_image
    open_comment_section(browser)
File "/Users/katieywu/Katie/Code/InstaPy/instapy/comment_util.py", line 26, in open_comment_section
    comment_elem[0].click()
File "/usr/local/lib/python2.7/site-packages/selenium/webdriver/remote/webelement.py", line 72, in click
    self._execute(Command.CLICK_ELEMENT)
File "/usr/local/lib/python2.7/site-packages/selenium/webdriver/remote/webelement.py", line 461, in _execute
    return self._parent.execute(command, params)
File "/usr/local/lib/python2.7/site-packages/selenium/webdriver/remote/webdriver.py", line 236, in execute
    self.error_handler.check_response(response)
File "/usr/local/lib/python2.7/site-packages/selenium/webdriver/remote/errorhandler.py", line 192, in check_response
    raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.WebDriverException: Message: unknown error: Element is not clickable at point (732, 593)
  (Session info: chrome=61.0.3163.100)
  (Driver info: chromedriver=2.31.488774 (7e15618d1bf16df8bf0ecf2914ed1964a387ba0b),platform=Mac OS X 10.11.5 x86_64)

@ateich @HammerSpb Thank god for the duo debug team! Appreciate it guys!

@ateich

It unfollows just fine actually, it's when it tries to follow someone that it breaks. I reported back in the other thread as well.

@katieywu Based on the error log, it looks like the comment button is sometimes either not visible or off screen when we call comment_elem[0].click() in open_comment_section

Try replacing the open_comment_section function with the following

def open_comment_section(browser):
    missing_comment_elem_warning = (
        '--> Warning: Comment Button Not Found:'
        ' May cause issues with browser windows of smaller widths')
    comment_elem = browser.find_elements_by_xpath(
        "//a[@role='button']/span[text()='Comment']/..")
    if len(comment_elem) > 0:
        try:
            browser.execute_script(
                "arguments[0].click();", comment_elem[0])
        except WebDriverException:
            print(missing_comment_elem_warning)
    else:
        print(missing_comment_elem_warning)

Instead of comment_elem[0].click() the above uses

try:
     browser.execute_script(
          "arguments[0].click();", comment_elem[0])
except WebDriverException:
     print(missing_comment_elem_warning)

which should work even if the comment_button is not visible and, if all else fails, will catch the WebDriverException you are getting so the script won't crash

@ateich thanks that's fixed it for me

@ateich Would you be interested in proposing a fix via PR? :smile:

@ateich got another one for ya. ~On line \~68, the line is comment_input[0].submit() but I get this exception when it attempts to comment: selenium.common.exceptions.StaleElementReferenceException: Message: stale element reference: element is not attached to the page document ...very odd. A cursory google search says the reference to the element (comment_input) is not valid if the DOM refreshes, and it seems to be happening between the the comment_input[0].send_keys("\b") line and the submit line. If that line is removed it obviously doesn't actually comment, but it also doesn't throw the StaleElementReferenceException anymore...

Update: I ended up fixing it with a one liner. If you get the StaleElementException it seems the easy thing to do is just to re-fetch the reference. Here is the updated code:

    if len(comment_input) > 0:
        comment_input[0].clear()
        comment_input = get_comment_input(browser)

        browser.execute_script(
            "arguments[0].value = '" + rand_comment + " ';", comment_input[0])
        # An extra space is added here and then deleted.
        # This forces the input box to update the reactJS core
        comment_input[0].send_keys("\b")
        comment_input = get_comment_input(browser) #added this line to avoid StaleElementException
        comment_input[0].submit()
    else:
        print('--> Warning: Comment Action Likely Failed:'
              ' Comment Element not found')

still getting the error @ateich

File "quickstart.py", line 19, in
session.like_by_tags(['jokes', 'funny', 'lmao', 'jokes', 'lol' ,'laugh' ,'crazy','joking','silly','laughing','epic','lmfao','haha','humor','wacky','hilarious'], amount=50)
File "/root/InstaPy/instapy/instapy.py", line 571, in like_by_tags
self.like_by_followers_lower_limit)
File "/root/InstaPy/instapy/like_util.py", line 413, in check_link
"return window._sharedData.entry_data."
File "/usr/local/lib/python3.4/dist-packages/selenium/webdriver/remote/webdriver.py", line 465, in execute_script
'args': converted_args})['value']
File "/usr/local/lib/python3.4/dist-packages/selenium/webdriver/remote/webdriver.py", line 236, in execute
self.error_handler.check_response(response)
File "/usr/local/lib/python3.4/dist-packages/selenium/webdriver/remote/errorhandler.py", line 192, in check_response
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.WebDriverException: Message: unknown error: Cannot read property 'entry_data' of undefined
(Session info: chrome=62.0.3202.62)
(Driver info: chromedriver=2.32.498513 (2c63aa53b2c658de596ed550eb5267ec5967b351),platform=Linux 2.6.32-042stab125.3 x86_64)

Changed the file with this and the comments are working now in my case:

# -*- coding: utf-8 -*-
"""Module which handles the commenting features"""
from random import choice
from .time_util import sleep
import emoji

def get_comment_input(browser):
    comment_input = browser.find_elements_by_xpath(
        '//textarea[@placeholder = "Add a comment…"]')
    if len(comment_input) <= 0:
        comment_input = browser.find_elements_by_xpath(
            '//input[@placeholder = "Add a comment…"]')
    return comment_input

def open_comment_section(browser):
    missing_comment_elem_warning = (
        '--> Warning: Comment Button Not Found:'
        ' May cause issues with browser windows of smaller widths')
    comment_elem = browser.find_elements_by_xpath(
        "//a[@role='button']/span[text()='Comment']/..")
    if len(comment_elem) > 0:
        try:
            browser.execute_script(
                "arguments[0].click();", comment_elem[0])
        except WebDriverException:
            print(missing_comment_elem_warning)
    else:
        print(missing_comment_elem_warning)

def comment_image(browser, comments):
    """Checks if it should comment on the image"""
    rand_comment = (choice(comments))
    rand_comment = emoji.demojize(rand_comment)
    rand_comment = emoji.emojize(rand_comment, use_aliases=True)

    open_comment_section(browser)
    comment_input = get_comment_input(browser)

    if len(comment_input) > 0:
        comment_input[0].clear()
        comment_input = get_comment_input(browser)

        browser.execute_script(
            "arguments[0].value = '" + rand_comment + " ';", comment_input[0])
        # An extra space is added here and then deleted.
        # This forces the input box to update the reactJS core
        comment_input[0].send_keys("\b")
        comment_input[0].submit()
    else:
        print('--> Warning: Comment Action Likely Failed:'
              ' Comment Element not found')

    print("--> Commented: {}".format(rand_comment.encode('utf-8')))
    sleep(2)

    return 1

@timgrossmann Here's the PR including @katieywu's fix. #831 😄

@wizarduk It looks like your issue may stem from Instagram temporarily limiting liking from your account.

From #657: "I faced this problem and it was the sign that liking was limited for an account. Did you check the liking ability on your phone?"

@ateich ill check my cron job doesn't start i haven't a clue why not...

Was this page helpful?
0 / 5 - 0 ratings