通过 Selenium 关闭代理身份验证弹出窗口

Close proxy authentication pop-up via Selenium

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

任何 help/tips 将不胜感激。谢谢!

规格: 我在 C#

中将 Selenium 2.44 与 Firefox 驱动程序一起使用

编辑#2:关于这个对话的更多信息)

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

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

(编辑:添加了屏幕截图示例)

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

像这样导航到网站:

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

website.com 就是通常的网站。

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

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

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

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

这里是一个示例代码,你需要收集windows的类名、自动化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;
        }
    }
}