Python点击警告框上的按钮

3

我是Python的新手,但需要修改别人创建的代码。我无法发布完整代码,但以下是我发布的大部分内容:

from bs4 import BeautifulSoup
import datetime
import getpass
from gmail import Gmail
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException
from selenium.common.exceptions import ElementNotVisibleException
from time import sleep
from selenium.common.exceptions import NoAlertPresentException
from selenium.webdriver.support import expected_conditions as EC


def soupify(session, url):
    """
    Makes parse-able HTML from any given URL.
    :param session: requests.Session()
    :param url: str
    :return: BeautifulSoup object
    """
    while True:
        try:
            r = session.get(url)
            break
        except Exception as e:
            print(e)
    return BeautifulSoup(r.content, 'html.parser')


def create_http_session():
    """
    Quick little function for returning a requests.Session() instance
    with a properly set User-Agent header.
    :return: requests.Session()
    """
    session = requests.Session()
    session.headers.update({'User-Agent':
                            'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36'
                        })
    return session


def retrieve_hidden_input(soup, name):
    return soup.find('input', attrs={
        'type': 'hidden',
        'name': name
    }).get('value')

class AmericanHomesScraper:
    def __init__(self, username, password, testing):
        self.username = username
        self.password = password
        self.testing = testing
        self.chrome_session = webdriver.PhantomJS()
        self.chrome_session.maximize_window()
        self.g = Gmail()
        self.g.login(username, password)
        self.index = 0

    def check_for_new_emails_from_sender(self,
                                     sender='info@mailer.netflix.com'):
        self.index += 1
        if self.index % 1000 == 0:
            print('Checking emails - {0}.'.format(datetime.datetime.now()))
        elif self.index == 1:
            print('Checking emails - {0}.'.format(datetime.datetime.now()))
        else:
            pass
        for s in sender:
            messages = self.g.inbox().mail(sender=s,
                                       unread=True)
            for message in messages:
                message.read()
                print(
                'Email from {0}: {1}.'.format(s, datetime.datetime.now()))
                self.check_for_listings()
            self.g.logout()
            self.g = Gmail()
            self.g.login(self.username, self.password)

 def login(self, username, ahsPassword):
    self.ahsPassword = ahsPassword
    self.chrome_session.get('https://www.aaa.com/Login.aspx')
    self.chrome_session.find_element_by_xpath(
        '//*[@id="txtUsername"]'
    ).send_keys(username)
    self.chrome_session.find_element_by_xpath(
        '//*[@id="txtPassword"]'
    ).send_keys(ahsPassword)
    self.chrome_session.find_element_by_xpath(
        '//*[@id="btnSubmit"]'
    ).click()

 def check_for_listings(self):
    #code block
    links = self.chrome_session.find_elements_by_class_name('link-record')
    links = [(link.text, link.get_attribute('href').decode('utf-8'))
             for link in links]
    if len(links) == 0:
        print("No work orders available at {0}".format(
            datetime.datetime.now())
        )
    else:
        for link_text, link_url in links:
            print("Clicking work order {0} at {1}".format(link_text,datetime.datetime.now()))
            self.chrome_session.get(link_url)
            print("Attempting to accept at {0}".format(datetime.datetime.now()))
            try:
                self.chrome_session.find_element_by_xpath("//input[@value='Accept']").click()
                try:
                    WebDriverWait(self.chrome_session, 1).until(EC.alert_is_present)
                    self.chrome_session.switch_to().alert().accept()
                    print("Accepted work order {0} at {1}.".format(link_text,datetime.datetime.now()))
                except:
                    print "no alert"
            except ElementNotVisibleException:
                print("Accept input not found at {0}".format(datetime.datetime.now()))
            self.chrome_session.back()

def main():
    username = raw_input(
        'Please enter the username of the GMail account you want to monitor.\n>')
    password = getpass.getpass(
        'Please enter the password of the GMail account you want to monitor.\n>')
    ahsPassword = getpass.getpass('Please enter the password for ahs. \n>')
    ahs = AmericanHomesScraper(username, password, testing)
    ahs.login(username,ahsPassword)
    print("Starting script")
    while True:
        ahs.check_for_new_emails_from_sender([
            'crm@aaa.com',
            'ds@aaa.com',
        ])


if __name__ == '__main__':
    main()

这段代码可以正确地找到并点击“接受”输入按钮。点击后,会弹出一个JavaScript警告(确定/取消)以确认接受。但是,该脚本无法找到结果警报。或者至少不能接受它,因为会调用异常。
如您所见,我已经尝试了switch_to().alert(),但它没有起作用。
我做错了什么?非常感谢您的帮助,我已经花费了数小时时间在这上面。
更新
此代码在虚拟服务器上运行,不使用用户界面。我刚意识到驱动程序是PhantomJS,而不是Chrome。所以,这可能是失败的原因。我已经更新了问题以反映这一点。
我尝试了类似问题的建议,但它没有起作用。第三方网站需要警报确认才能完成流程,但我的脚本无法看到它,因为它是无头的。

请至少提供网址。 - Argus Malware
@Bahrom,从代码中可以看出,我已经尝试按照你的文章点击警报。但它没有起作用。 - davids
当点击接受按钮后,警报是否保证立即存在于.click()返回的时间? - user955340
我立刻看到这一点。但是,我不确定代码是否认为它是即时的。 - davids
driver.switch_to.alert - Corey Goldberg
显示剩余4条评论
3个回答

1
这里有几点需要注意:

  • switch_to_alert had been deprecated so we have to mandatory use switch_to().alert()
  • Seems to me a purely timing issue. Hence we need to induce ExplicitWait i.e. WebDriverWait with expected_conditions clause set to alert_is_present as follows :

    from selenium.webdriver.support import expected_conditions as EC
    #code block
    self.chrome_session.find_element_by_xpath("//input[@value='Accept']").click()
    WebDriverWait(self.chrome_session, 10).until(EC.alert_is_present)
    self.chrome_session.switch_to().alert().accept()
    print("Accepted work order {0} at {1}.".format(link_text, datetime.datetime.now()))
    

我已经尝试过了,但它只是卡住了。没有任何消息,也没有错误。 - davids
我现在已经发布了大部分代码,看看是否有帮助。 - davids
我刚才意识到它正在使用PhantomJS而不是Chrome。因此,当脚本运行时,警报实际上从未出现过。但是,我无法在没有点击接受的情况下达成我的目标。我该如何处理这个问题? - davids

0

我不知道下面的代码是否能帮到你,曾经我也遇到过同样的问题,最后等待警告并接受警告解决了我的问题。

from selenium.common.exceptions import NoAlertPresentException,

   def wait_for_alert(self):

        for i in range(50):
            try:
                alert = chrome_session.switch_to.alert
                if alert.text:
                   break
            except NoAlertPresentException:
              pass
            time.sleep(.25)
        else:
            raise NoAlertPresentException("Alert visibility timed out")
    return alert

wait_for_alert().accept()

这只是重新实现了 WebDriver 的显式等待的一部分。 - Corey Goldberg
你是对的,这就是我采取的方法,不是显式等待。话虽如此,在我的情况下,动作和警报显示之间存在延迟,但我的代码仍然有效。 - Satish
棒极了的代码,不过我建议使用Selenium WebDriver等待,无论是隐式还是显式。参考资料:http://selenium-python.readthedocs.io/waits.html# - innicoder
谢谢,我会研究一下。在我的情况下,我需要驱动程序告诉我元素是否存在于DOM中并且可见,而不是返回元素本身。这是一篇很好的文章,谢谢。 - Satish
Satish,你只需要使用一个方法WebdriverWait(arguments).until(presence_of_element_located),然后通过XPath或其他方式来定位它,虽然不是完全一样,但这应该可以帮助你找到它(希望如此)。 - innicoder

0

尝试以下代码! 对我来说很好用!

alert = driver.switch_to.alert #This .alert will work For Python
try:
   alert.accept() #If you want to Accept the Alert
except:
   alert.dismiss()  #If  You want to Dismiss the Alert.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接