loblab / noip-renew

Auto renew (confirm) noip.com free hosts
Apache License 2.0
435 stars 138 forks source link

WebDriver' object has no attribute 'find_element_by_name #102

Open maykel535 opened 2 years ago

maykel535 commented 2 years ago

Thanks for share your script, but get these error:

[2022/09/30 10:23:32] - Debug level: 2 [2022/09/30 10:23:32] - Opening https://www.noip.com/login... [2022/09/30 10:23:35] - Logging in... [2022/09/30 10:23:35] - 'WebDriver' object has no attribute 'find_element_by_name'

juniorik commented 1 year ago

you should use webdriver.find_element("name", VALUE) instead

lclem commented 1 year ago

I have the same problem

Seagulls commented 1 year ago

I'm also having this problem, any way to fix it?

adithyapi4 commented 1 year ago

noip-renew.txt Copy the contents of the txt file and paste it in noip-renew.py. Copy the created file into /usr/local/bin/ and replace the existing file.

Modified the noip-renew.py as per @juniorik

TarkinMX commented 1 year ago

noip-renew.txt Copy the contents of the txt file and paste it in noip-renew.py. Copy the created file into /usr/local/bin/ and replace the existing file.

Modified the noip-renew.py as per @juniorik

I was having the same issue as maykel535 and tried the script you posted. It got further than before but still having errors. Pasted the output below minus the IP that it was showing.

[2023/07/02 15:25:44] - Debug level: 2 [2023/07/02 15:25:44] - Opening https://www.noip.com/login... [2023/07/02 15:25:47] - Logging in... [2023/07/02 15:25:48] - Message: element not interactable (Session info: headless chrome=...) Stacktrace:

0 0xaaaab33da088

1 0xaaaab3149690

2 0xaaaab317ff88

3 0xaaaab3176848

4 0xaaaab31761d4

5 0xaaaab31b21c4

6 0xaaaab3174aa8

7 0xaaaab3175a04

8 0xaaaab33a0aec

9 0xaaaab33a36b0

10 0xaaaab33a3c88

11 0xaaaab33ab6e4

12 0xaaaab33a42dc

13 0xaaaab337eda0

14 0xaaaab33c2e98

15 0xaaaab33c3028

16 0xaaaab33d26c4

17 0xffffb33dc648 start_thread

18 0xffffb2f07c1c

adithyapi4 commented 1 year ago

@TarkinMX I'm also facing the same issue.

ECLAYA4188 commented 1 year ago

I am have same issue as @TarkinMX

ECLAYA4188 commented 1 year ago

noip-renew.txt So it determined that the whole thing is pretty much bungled.

The initial script that @adithyapi4 issued fixed part of the problem. The xauth element grabs need to be updated as well, same format he used would apply. host.find_element_by_xpath(".//a[@class='link-info cursor-pointer']") would be host.find_element("xauth", ".//a[@class='link-info cursor-pointer']"). I used an imported library to be more intuitive, so my command looks like this host.find_element(By.XAUTH, ".//a[@class='link-info cursor-pointer']").

I also found the noip-renew-skd.sh script used to update cronjob will update the next cronjob to the past so I fixed that in the .py script. The line in question is Line 117, it uses current month to set the next cronjob which end up putting it in the past. I changed from month = str(today.month) to *** . I ended up updated noip-renew-skd.sh to also update the cronjob to properly dump the print statements as well as run the cronjob on my raspberry pi4. The cronjob was formatted to as "30 0 $1 $2 $USER $INSTEXE $LOGDIR", I ended up with "30 0 $1 $2 * $INSTEXE >> $LOGDIR 2>&1". Keep in mind the logs ownership needs to be rw for $USER.

I uploaded the noip-renew.py script I am currently using and is working for me in the .txt file, I also left some of my debug lines in there in case people might want to figure out there own new issues and have a starting point.

All in all, this script works great after the fixes. I assume some kind of update occurred with the Selenium webdriver or chrome because I setup roughly 1 month ago and it worked but 30 days later when noip needed a renewal it did not function. If anyone has question feel free to ask, I dumped 24 straight hours into these scripts and I am feeling proficient. HAHAHA

XVs32 commented 1 year ago

@ECLAYA4188 Thank you for the update, it works great here.

adithyapi4 commented 1 year ago

@ECLAYA4188 Can you post the working script

redespace commented 1 year ago

I tried the script on WSL, but it didn't detect any hosts :(

user@MyPC:/usr/local/bin$ bash noip-renew-user.sh
[2023/08/13 14:18:04] - Debug level: 2
[2023/08/13 14:18:04] - Opening https://www.noip.com/login...
[2023/08/13 14:18:07] - Logging in...
[2023/08/13 14:18:12] - Opening https://my.noip.com/dynamic-dns...
[2023/08/13 14:18:16] - No hosts or host table rows not found

I tried looking for the screenshots where selenium is supposed to be saving them, but couldn't find them.

    def get_hosts(self):
        host_tds = self.browser.find_elements(By.XPATH, "//td[@class=\"word-break-col\"]")
        self.browser.save_screenshot("end.png")
        if len(host_tds) == 0:
            raise Exception("No hosts or host table rows not found")
        return host_tds

@ECLAYA4188 As you are the expert one :D, do you have any idea why is not finding any hosts? I definitely have one under Dynamic DNS --> no-ip Hostnames

image

ECLAYA4188 commented 1 year ago

Sorry for the delay, I have been heavy in the proxy game these days MITM type garbage :P

@redespace I suspect you were tinkering with the xpath search strings and forgot to change some back... I also redirected the browser in parts of the code but after initial login the script depends on the webpage being "https://my.noip.com/dynamic-dns", maybe you redirected somewhere prior on accident. I did this when I was troubleshooting and got the same error. I can assure you all search strings function as intended. The major issue with the original script I believe to be that the selenium web-driver updated and deprecated some methods and syntax.

Another unrelated that I have had battles with in the past but no longer have this issue because all my pi's are hardwired is the webpage needs to fully load after each action. this is where the script delay comes in handy. after each page interaction ("click", "enter", etc) hard code a delay this might help if you are not hardwired.

@adithyapi4 Here is function script, github is doing some wierd formatting so I indicated beginning and end of script

beginning of functioning script

!/usr/bin/env python3

from selenium import webdriver from selenium.webdriver.common.keys import Keys from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.common.exceptions import TimeoutException from datetime import date from datetime import timedelta import time import sys import os import re import base64 import subprocess

class Logger: def init(self, level): self.level = 0 if level is None else level

def log(self, msg, level=None):
    self.time_string_formatter = time.strftime('%Y/%m/%d %H:%M:%S', time.localtime(time.time()))
    self.level = self.level if level is None else level
    if self.level > 0:
        print(f"[{self.time_string_formatter}] - {msg}")

class Robot:

USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:64.0) Gecko/20100101 Firefox/64.0"
LOGIN_URL = "https://www.noip.com/login"
HOST_URL = "https://my.noip.com/dynamic-dns"

def __init__(self, username, password, debug):
    self.debug = debug
    self.username = username
    self.password = password
    self.browser = self.init_browser()
    self.logger = Logger(debug)

@staticmethod
def init_browser():
    options = webdriver.ChromeOptions()
    #added for Raspbian Buster 4.0+ versions. Check https://www.raspberrypi.org/forums/viewtopic.php?t=258019 for reference.
    options.add_argument("disable-features=VizDisplayCompositor")
    options.add_argument("headless")
    options.add_argument("no-sandbox")  # need when run in docker
    options.add_argument("window-size=1200x800")
    options.add_argument(f"user-agent={Robot.USER_AGENT}")
    options.add_argument('disable-extensions')
    if 'https_proxy' in os.environ:
        options.add_argument("proxy-server=" + os.environ['https_proxy'])
    browser = webdriver.Chrome(options=options)
    browser.set_page_load_timeout(90000) # Extended timeout for Raspberry Pi.
    return browser

def login(self):
    self.logger.log(f"Opening {Robot.LOGIN_URL}...")
    self.browser.get(Robot.LOGIN_URL)
    time.sleep(1)
    #html = self.browser.page_source
    #print (html)
    if self.debug > 1:
        self.browser.save_screenshot("debug1.png")

    self.logger.log("Logging in...")
    ele_usr = self.browser.find_element("name","username")
    ele_pwd = self.browser.find_element("name","password")
    ele_usr.send_keys(self.username)
    ele_pwd.send_keys(self.password)
    self.browser.find_element(By.ID , "clogs-captcha-button").click()
    time.sleep(1)
    #html = self.browser.page_source
    #print (html)
    if self.debug > 1:
        time.sleep(1)
        self.browser.save_screenshot("debug2.png")

def update_hosts(self):
    count = 0
    self.open_hosts_page()
    time.sleep(1)
    iteration = 1
    next_renewal = []
    self.browser.save_screenshot("test.png")
    hosts = self.get_hosts()
    for host in hosts:
        host_link = self.get_host_link(host, iteration) # This is for if we wanted to modify our Host IP.
        host_button = self.get_host_button(host, iteration) # This is the button to confirm our free host
        host_name = host_link.text
        expiration_days = self.get_host_expiration_days(host, iteration)
        next_renewal.append(expiration_days)
        self.logger.log(f"{host_name} expires in {str(expiration_days)} days")
        if expiration_days < 7:
            self.update_host(host_button, host_name)
            count += 1
        iteration += 1
    self.browser.save_screenshot("results.png")
    self.logger.log(f"Confirmed hosts: {count}", 2)
    nr = min(next_renewal) - 6
    today = date.today() + timedelta(days=nr)
    day = str(today.day)
    month = str(today.month + 1)
    subprocess.call(['/usr/local/bin/noip-renew-skd.sh', day, month, "True"])
    return True

def open_hosts_page(self):
    self.logger.log(f"Opening {Robot.HOST_URL}...")
    try:
        self.browser.get(Robot.HOST_URL)
        time.sleep(2)
        #html = self.browser.page_source
        #print (html)
    except TimeoutException as e:
        self.browser.save_screenshot("timeout.png")
        self.logger.log(f"Timeout: {str(e)}")

def update_host(self, host_button, host_name):
    self.logger.log(f"Updating {host_name}")
    host_button.click()
    time.sleep(3)
    intervention = False
    try:
        if self.browser.find_elements(By.XPATH,"//h2[@class='big']")[0].text == "Upgrade Now":
            intervention = True
    except:
        pass

    if intervention:
        raise Exception("Manual intervention required. Upgrade text detected.")

    self.browser.save_screenshot(f"{host_name}_success.png")

@staticmethod
def get_host_expiration_days(host, iteration):
    try:
        host_remaining_days = host.find_element(By.XPATH,".//a[@class='no-link-style']").text
    except:
        host_remaining_days = "Expires in 0 days"
        pass
    regex_match = re.search("\\d+", host_remaining_days)
    if regex_match is None:
        raise Exception("Expiration days label does not match the expected pattern in iteration: {iteration}")
    expiration_days = int(regex_match.group(0))
    return expiration_days

@staticmethod
def get_host_link(host, iteration):
    return host.find_element(By.XPATH ,".//a[@class='link-info cursor-pointer']")

@staticmethod
def get_host_button(host, iteration):
    return host.find_element(By.XPATH ,".//following-sibling::td[4]/button[contains(@class, 'btn')]")

def get_hosts(self):
    host_tds = self.browser.find_elements(By.XPATH, "//td[@class=\"word-break-col\"]")
    self.browser.save_screenshot("end.png")
    if len(host_tds) == 0:
        raise Exception("No hosts or host table rows not found")
    return host_tds

def run(self):
    rc = 0
    self.logger.log(f"Debug level: {self.debug}")
    try:
        self.login()
        if not self.update_hosts():
            rc = 3
    except Exception as e:
        self.logger.log(str(e))
        self.browser.save_screenshot("exception.png")
        subprocess.call(['/usr/local/bin/noip-renew-skd.sh', "*", "*", "False"])
        rc = 2
    finally:
        self.browser.quit()
    return rc

def main(argv=None): noip_username, noip_password, debug, = get_args_values(argv) return (Robot(noip_username, noip_password, debug)).run()

def get_args_values(argv): if argv is None: argv = sys.argv if len(argv) < 3: print(f"Usage: {argv[0]} [] ") sys.exit(1)

noip_username = argv[1]
noip_password = argv[2]
debug = 1
if len(argv) > 3:
    debug = int(argv[3])
return noip_username, noip_password, debug

if name == "main": sys.exit(main())

end of functioning .py script

Shoot me any questions, I will try to be faster!