【问题标题】:Close proxy authentication pop-up via Selenium通过 Selenium 关闭代理身份验证弹出窗口
【发布时间】:2015-01-29 15:11:44
【问题描述】:

我在一个屏蔽社交媒体网站的地方工作,并为那些(少数)有正当商业理由访问它们的人弹出代理登录。由于大多数网站都有 Facebook、Twitter 或类似的链接,因此代理提示出现了很多。当以正常的人工方式浏览时,我只需按 ESC 键即可摆脱代理登录对话框。我怎样才能通过 Selenium 做到这一点?我已经看到很多关于关闭 ALERT 消息或模式对话的帖子和解决方案,但我没有看到任何关于关闭代理登录的内容;只需提供凭据即可绕过它。

任何帮助/提示将不胜感激。谢谢!

规格: 我在 C# 中使用 Selenium 2.44 和 Firefox 驱动程序

编辑#2:有关此对话的更多信息)

此登录提示来自我们自己的内部代理服务器。我们的代理服务器基本上是在与远程站点进行任何通信之前询问用户是否有权访问请求的站点。只要元素在远程站点上,它就会弹出。因此,例如,如果一个站点有一个 Facebook 和 Twitter 按钮,该按钮从 Facebook 或 Twitter 本身提取按钮,用户将看到两个代理登录提示。虽然页面的其他元素会在等待时加载,但页面加载过程最终会等待任何被自动阻止的元素的响应。

我解决此问题的一种方法是将 Firefox 驱动程序与 NoScript 结合使用,并从白名单中删除所有社交网络链接。这是一种粗略的解决方法,并强制使用一个浏览器。我正在寻找的是一种让 Selenium 简单地通过代码关闭代理登录提示的方法(如果这样做的话)。

编辑:添加截图示例)

编辑:添加了 Inspect 的屏幕截图)

【问题讨论】:

  • 您好@Jim M,您能否发布“弹出窗口”的屏幕截图以及您希望关闭它的代码行,以便我为您提供更好的答案?
  • Hello @TidusJar - 根据要求添加了屏幕截图。我无法识别代码行 - 它发生在任何链接到我们的内部政策认为“与业务无关”的网站(按钮等)的页面上。

标签: c# selenium proxy automation


【解决方案1】:

不确定 selenium,但您可以改用 System.Windows.Automation 命名空间。

  1. 订阅顶级窗口打开
  2. 使用收到的AutomationElement 来检查它是否与您的 Firefox 窗口信息匹配(您可以使用像 Inspect 这样的工具来找出它们是什么)
  3. 使用上面的AutomationElement 订阅子窗口打开事件
  4. 在事件中,检查是否是代理弹出窗口
  5. 使用其上的close方法或SendKeys发送ESC

这是一个示例代码,您必须收集类名、自动化 ID 和窗口名称(请随意推荐,我将编辑答案):

using System.Linq;
using System.Text.RegularExpressions;
using System.Windows.Automation;

namespace FirefoxAutomation
{
    class FirefoxAutomation
    {
        private const string FF_CLASSNAME = "MozillaWindowClass"; //"Firefox ClassName taken from Inspect";
        private const string FF_AUTOMATIONID = null;//"Firefox AutomationId taken from Inspect";
        private static readonly Regex FF_NAME = new Regex("( - Mozilla Firefox)$"); //new Regex("Firefox Name regex based on name taken from Inspect");

        private const string PROXY_CLASSNAME = "MozillaDialogClass";//"Proxy window ClassName taken from Inspect";
        private const string PROXY_AUTOMATIONID = null;//"Proxy window AutomationId taken from Inspect";
        private static readonly Regex PROXY_NAME = new Regex("^(Authentication Required)$");//new Regex("Proxy window Name regex based on name taken from Inspect");

        public FirefoxAutomation()
        {
            SubscribeTopLevelWindowOpened();
        }

        private void SubscribeTopLevelWindowOpened()
        {
            Automation.AddAutomationEventHandler(WindowPattern.WindowOpenedEvent,
                AutomationElement.RootElement, TreeScope.Children, TopLevelWindowOpened);
        }

        private void TopLevelWindowOpened(object sender, AutomationEventArgs e)
        {
            var element = sender as AutomationElement;
            if (element == null) return;

            // Filter for FireFox window element
            if (!MatchWindow(element, FF_CLASSNAME, FF_AUTOMATIONID, FF_NAME)) return;

            // Subscribe for child window opened even
            Automation.AddAutomationEventHandler(WindowPattern.WindowOpenedEvent,
                element, TreeScope.Children, FireFoxChildWindowOpened);
        }

        private void FireFoxChildWindowOpened(object sender, AutomationEventArgs e)
        {
            var element = sender as AutomationElement;
            if (element == null) return;

            // Filter for a proxy message
            if (!MatchWindow(element, PROXY_CLASSNAME, PROXY_AUTOMATIONID, PROXY_NAME)) return;

            // Find the cancel button
            var controls = element.FindAll(TreeScope.Children, Condition.TrueCondition).Cast<AutomationElement>().ToList();
            var cancelButton = controls.FirstOrDefault(c => c.Current.ControlType == ControlType.Button && c.Current.Name == "Cancel");
            if (cancelButton == null) return;

            // Get the click pattern
            object clickPatternObj;
            if (!cancelButton.TryGetCurrentPattern(InvokePattern.Pattern, out clickPatternObj)) return;
            ((InvokePattern)clickPatternObj).Invoke(); // click the cancel button
        }

        private bool MatchWindow(AutomationElement element, string className, string automationId, Regex name)
        {
            var current = element.Current;
            if (current.ControlType != ControlType.Window) return false;
            if (className != null && current.ClassName != className) return false;
            if (automationId != null && current.AutomationId != automationId) return false;
            if (name != null && name.IsMatch(current.Name)) return false;
            return true;
        }
    }
}

【讨论】:

  • .@DoronG - 我会试一试并报告。
  • -@DoronG - 抱歉耽搁了。我出差了一段时间。我还没有尝试过上述解决方案,但是当我有机会时我会尝试。 NoScript 技巧(上面提到过)确实有效,但不是真正的解决方案——尤其是对于那些不能使用 FireFox 的人
  • -@DoronG - 实现有点麻烦 - System.Windows.Automation.AutomationElementCollection 不包含在线“ToList”的定义 [var controls = element.FindAll(TreeScope.Children, Condition.TrueCondition).ToList();] 我会继续努力的。
  • @JimM - 将using System.Linq; 声明添加到顶部
  • -@DoronG - 使用 System.Linq;已经存在于代码中。我还添加了对所有 UIAutomation 集合的引用。编译器仍然没有爱
【解决方案2】:

像这样导航到网站:

WebDriver.Navigate().GoToUrl("http://username:password@website.com");

website.com 将是通常的网站。

如果您不想登录,可以使用Action 向驱动程序发送 Escape 键:

var action = new Actions(WebDriver);
action.SendKeys(Keys.ESCAPE).Build().Perform();

【讨论】:

  • 身份验证请求实际上来自 我们的 公司的代理服务器,询问您(用户)是否具有访问此被阻止站点的特殊权限。我明天会报告 esc-key 选项并让你知道。谢谢!
  • 你好@TidusJar。 SendKeys() 策略不起作用。在网站的初始页面加载期间出现对话。对话实际上会阻止页面加载继续,直到它关闭(我目前手动执行)。
猜你喜欢
  • 2019-01-22
  • 2016-03-29
  • 1970-01-01
  • 2016-05-11
  • 1970-01-01
  • 1970-01-01
  • 2018-10-21
  • 2022-01-19
  • 1970-01-01
相关资源
最近更新 更多