使用C#从Google Chrome获取当前标签的网址

Cod*_*cat 41 c# google-chrome

以前有一种方法可以通过FindWindowEx结合使用SendMessage调用获取当前在多功能框中的文本来从Google Chrome获取活动标签的URL .最近的(?)更新似乎打破了这种方法,因为Chrome现在似乎正在渲染所有内容.(您可以查看Spy ++,AHK Window Spy或Window Detective)

要在Firefox和Opera上获取当前URL,您可以使用DDE和WWW_GetWindowInfo.这在Chrome上似乎不可能(再也没有?).

这个问题有关于它如何用来工作,这是这段代码(正如我所解释的,不工作了-更多信息的回答hAddressBox0):

var hAddressBox = FindWindowEx(
    intPtr,
    IntPtr.Zero,
    "Chrome_OmniboxView",
    IntPtr.Zero);

var sb = new StringBuilder(256);
SendMessage(hAddressBox, 0x000D, (IntPtr)256, sb);
temp = sb.ToString();
Run Code Online (Sandbox Code Playgroud)

所以我的问题是:有没有方法来获取当前关注的标签的URL?(只是标题是不够的)

Cod*_*cat 35

编辑:似乎我的答案中的代码不再适用(虽然使用的想法AutomationElement仍然有用)适用于以后的Chrome版本,因此请查看不同版本的其他答案.例如,这是Chrome 54的一个:https://stackoverflow.com/a/40638519/377618

以下代码似乎有效(感谢icemanind的评论)但是资源密集.找到elmUrlBar需要大约350ms ......有点慢.

更不用说我们有chrome同时运行多个进程的问题.

// there are always multiple chrome processes, so we have to loop through all of them to find the
// process with a Window Handle and an automation element of name "Address and search bar"
Process[] procsChrome = Process.GetProcessesByName("chrome");
foreach (Process chrome in procsChrome) {
  // the chrome process must have a window
  if (chrome.MainWindowHandle == IntPtr.Zero) {
    continue;
  }

  // find the automation element
  AutomationElement elm = AutomationElement.FromHandle(chrome.MainWindowHandle);
  AutomationElement elmUrlBar = elm.FindFirst(TreeScope.Descendants,
    new PropertyCondition(AutomationElement.NameProperty, "Address and search bar"));

  // if it can be found, get the value from the URL bar
  if (elmUrlBar != null) {
    AutomationPattern[] patterns = elmUrlBar.GetSupportedPatterns();
    if (patterns.Length > 0) {
      ValuePattern val = (ValuePattern)elmUrlBar.GetCurrentPattern(patterns[0]);
      Console.WriteLine("Chrome URL found: " + val.Current.Value);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

编辑:我对上面的慢速方法感到不满意,所以我加快了速度(现在是50ms)并添加了一些URL验证,以确保我们获得了正确的URL而不是用户可能在网上搜索的内容,或者仍然忙于输入网址.这是代码:

// there are always multiple chrome processes, so we have to loop through all of them to find the
// process with a Window Handle and an automation element of name "Address and search bar"
Process[] procsChrome = Process.GetProcessesByName("chrome");
foreach (Process chrome in procsChrome) {
  // the chrome process must have a window
  if (chrome.MainWindowHandle == IntPtr.Zero) {
    continue;
  }

  // find the automation element
  AutomationElement elm = AutomationElement.FromHandle(chrome.MainWindowHandle);

  // manually walk through the tree, searching using TreeScope.Descendants is too slow (even if it's more reliable)
  AutomationElement elmUrlBar = null;
  try {
    // walking path found using inspect.exe (Windows SDK) for Chrome 31.0.1650.63 m (currently the latest stable)
    var elm1 = elm.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, "Google Chrome"));
    if (elm1 == null) { continue; } // not the right chrome.exe
    // here, you can optionally check if Incognito is enabled:
    //bool bIncognito = TreeWalker.RawViewWalker.GetFirstChild(TreeWalker.RawViewWalker.GetFirstChild(elm1)) != null;
    var elm2 = TreeWalker.RawViewWalker.GetLastChild(elm1); // I don't know a Condition for this for finding :(
    var elm3 = elm2.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, ""));
    var elm4 = elm3.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.ToolBar));
    elmUrlBar = elm4.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Custom));
  } catch {
    // Chrome has probably changed something, and above walking needs to be modified. :(
    // put an assertion here or something to make sure you don't miss it
    continue;
  }

  // make sure it's valid
  if (elmUrlBar == null) {
    // it's not..
    continue;
  }

  // elmUrlBar is now the URL bar element. we have to make sure that it's out of keyboard focus if we want to get a valid URL
  if ((bool)elmUrlBar.GetCurrentPropertyValue(AutomationElement.HasKeyboardFocusProperty)) {
    continue;
  }

  // there might not be a valid pattern to use, so we have to make sure we have one
  AutomationPattern[] patterns = elmUrlBar.GetSupportedPatterns();
  if (patterns.Length == 1) {
    string ret = "";
    try {
      ret = ((ValuePattern)elmUrlBar.GetCurrentPattern(patterns[0])).Current.Value;
    } catch { }
    if (ret != "") {
      // must match a domain name (and possibly "https://" in front)
      if (Regex.IsMatch(ret, @"^(https:\/\/)?[a-zA-Z0-9\-\.]+(\.[a-zA-Z]{2,4}).*$")) {
        // prepend http:// to the url, because Chrome hides it if it's not SSL
        if (!ret.StartsWith("http")) {
          ret = "http://" + ret;
        }
        Console.WriteLine("Open Chrome URL found: '" + ret + "'");
      }
    }
    continue;
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 将以下两个引用添加到您的解决方案1.UIAutomationClient,2.UIAutomationTypes.你不会得到任何错误.. (7认同)
  • 嗨,这对我来说效果很好,但最近,随着Chrome升级到版本34.0.1847.116m,它已经停止工作,因为谷歌改变了一些东西.有人可以告知任何可用于查找手柄和属性等的修复和/或工具,以便可以修复此问题吗? (3认同)
  • 添加`using System.Windows.Automation;` (2认同)

dot*_*NET 9

从Chrome 54开始,以下代码对我有用:

public static string GetActiveTabUrl()
{
  Process[] procsChrome = Process.GetProcessesByName("chrome");

  if (procsChrome.Length <= 0)
    return null;

  foreach (Process proc in procsChrome)
  {
    // the chrome process must have a window 
    if (proc.MainWindowHandle == IntPtr.Zero)
      continue;

    // to find the tabs we first need to locate something reliable - the 'New Tab' button 
    AutomationElement root = AutomationElement.FromHandle(proc.MainWindowHandle);
    var SearchBar = root.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.NameProperty, "Address and search bar"));
    if (SearchBar != null)
      return (string)SearchBar.GetCurrentPropertyValue(ValuePatternIdentifiers.ValueProperty);
  }

  return null;
}
Run Code Online (Sandbox Code Playgroud)


Ran*_*etz 8

使用Chrome V53及更高版本时,上述所有方法都失败了.

这是有效的:

Process[] procsChrome = Process.GetProcessesByName("chrome");
foreach (Process chrome in procsChrome)
{
    if (chrome.MainWindowHandle == IntPtr.Zero)
        continue;

    AutomationElement element = AutomationElement.FromHandle(chrome.MainWindowHandle);
    if (element == null)
        return null;
    Condition conditions = new AndCondition(
        new PropertyCondition(AutomationElement.ProcessIdProperty, chrome.Id),
        new PropertyCondition(AutomationElement.IsControlElementProperty, true),
        new PropertyCondition(AutomationElement.IsContentElementProperty, true),
        new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit));

    AutomationElement elementx = element.FindFirst(TreeScope.Descendants, conditions);
    return ((ValuePattern)elementx.GetCurrentPattern(ValuePattern.Pattern)).Current.Value as string;
}
Run Code Online (Sandbox Code Playgroud)

在这里找到它:

https://social.msdn.microsoft.com/Forums/vstudio/en-US/93001bf5-440b-4a3a-ad6c-478a4f618e32/how-can-i-get-urls-of-open-pages-from-chrome-和Firefox的?论坛= csharpgeneral


小智 7

我使用下一个代码获得了Chrome 38.0.2125.10的结果('try'块中的代码必须替换为此)

var elm1 = elm.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, "Google Chrome"));
if (elm1 == null) { continue; }  // not the right chrome.exe
var elm2 = TreeWalker.RawViewWalker.GetLastChild(elm1);
var elm3 = elm2.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.HelpTextProperty, "TopContainerView"));
var elm4 = elm3.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.ToolBar));
var elm5 = elm4.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.HelpTextProperty, "LocationBarView"));
elmUrlBar = elm5.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit));
Run Code Online (Sandbox Code Playgroud)


Mar*_*scu 5

我拿了安吉洛的解决方案并清理了一下……我对LINQ有兴趣:)

这是主要方法。它使用了两种扩展方法:

public IEnumerable<string> GetTabs()
{
  // there are always multiple chrome processes, so we have to loop through all of them to find the
  // process with a Window Handle and an automation element of name "Address and search bar"
  var processes = Process.GetProcessesByName("chrome");
  var automationElements = from chrome in processes
                           where chrome.MainWindowHandle != IntPtr.Zero
                           select AutomationElement.FromHandle(chrome.MainWindowHandle);

  return from element in automationElements
         select element.GetUrlBar()
         into elmUrlBar
         where elmUrlBar != null
         where !((bool) elmUrlBar.GetCurrentPropertyValue(AutomationElement.HasKeyboardFocusProperty))
         let patterns = elmUrlBar.GetSupportedPatterns()
         where patterns.Length == 1
         select elmUrlBar.TryGetValue(patterns)
         into ret
         where ret != ""
         where Regex.IsMatch(ret, @"^(https:\/\/)?[a-zA-Z0-9\-\.]+(\.[a-zA-Z]{2,4}).*$")
         select ret.StartsWith("http") ? ret : "http://" + ret;
}
Run Code Online (Sandbox Code Playgroud)

请注意,该注释具有误导性,因为注释往往会-它实际上并没有查看单个AutomationElement。我把它留在那里,因为安杰洛的代码有它。

这是扩展类:

public static class AutomationElementExtensions
{
  public static AutomationElement GetUrlBar(this AutomationElement element)
  {
    try
    {
      return InternalGetUrlBar(element);
    }
    catch
    {
      // Chrome has probably changed something, and above walking needs to be modified. :(
      // put an assertion here or something to make sure you don't miss it
      return null;
    }
  }

  public static string TryGetValue(this AutomationElement urlBar, AutomationPattern[] patterns)
  {
    try
    {
      return ((ValuePattern) urlBar.GetCurrentPattern(patterns[0])).Current.Value;
    }
    catch
    {
      return "";
    }
  }

  //

  private static AutomationElement InternalGetUrlBar(AutomationElement element)
  {
    // walking path found using inspect.exe (Windows SDK) for Chrome 29.0.1547.76 m (currently the latest stable)
    var elm1 = element.FindFirst(TreeScope.Children,
      new PropertyCondition(AutomationElement.NameProperty, "Google Chrome"));
    var elm2 = TreeWalker.RawViewWalker.GetLastChild(elm1); // I don't know a Condition for this for finding :(
    var elm3 = elm2.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, ""));
    var elm4 = elm3.FindFirst(TreeScope.Children,
      new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.ToolBar));
    var result = elm4.FindFirst(TreeScope.Children,
      new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Custom));

    return result;
  }
}
Run Code Online (Sandbox Code Playgroud)


小智 5

我发现了这篇文章,并且能够使用这些方法成功地从 C# 中的 chrome 中提取 URL,谢谢大家!

不幸的是,随着最近的Chrome 69更新,AutomationElement树遍历再次中断。

我找到了 Microsoft 的这篇文章:使用 TreeWalker 在 UI 自动化元素中导航

并使用它来创建一个简单的函数,该函数搜索AutomationElement具有"edit"我们正在寻找的控件类型的 ,而不是遍历始终在变化的树层次结构,并从中提取 url 值AutomationElement

我写了一个简单的类来包装这一切:Google-Chrome-URL-Check-C-Sharp

自述文件解释了如何使用它。

总而言之,它可能更可靠一点,希望你们中的一些人觉得它有用。