用于查找 <a> 链接的“href”值的正则表达式

Posted

技术标签:

【中文标题】用于查找 <a> 链接的“href”值的正则表达式【英文标题】:regular expression for finding 'href' value of a <a> link 【发布时间】:2013-04-02 07:28:52 【问题描述】:

我需要一个用于在 html 中查找网页链接的正则表达式模式。

我首先使用@"(&lt;a.*?&gt;.*?&lt;/a&gt;)" 提取链接(&lt;a&gt;),但我无法从中获取href

我的字符串是:

    &lt;a href="www.example.com/page.php?id=xxxx&amp;name=yyyy" ....&gt;&lt;/a&gt; &lt;a href="http://www.example.com/page.php?id=xxxx&amp;name=yyyy" ....&gt;&lt;/a&gt; &lt;a href="https://www.example.com/page.php?id=xxxx&amp;name=yyyy" ....&gt;&lt;/a&gt; &lt;a href="www.example.com/page.php/404" ....&gt;&lt;/a&gt;

1、2 和 3 有效,我需要它们,但数字 4 对我无效 (?= 是必不可少的)


谢谢大家,但我不需要解析&lt;a&gt;。我有一个href="abcdef" 格式的链接列表。

我需要获取链接中的href 并对其进行过滤,我最喜欢的网址必须包含?=,例如page.php?id=5

谢谢!

【问题讨论】:

阅读:***.com/questions/1732348/… 我建议使用 HtmlAgility nuget 包。 您可能需要结帐CsQuery。类似于 jQuery,它允许您选择标签和提取属性等。正则表达式在应用于原始 html 时往往会变得棘手。 嗨,请检查一下:***.com/questions/2450985/… 不要对 HTML 使用正则表达式,如 ***.com/questions/1732348/… 中所述。 【参考方案1】:

我建议在正则表达式上使用 HTML 解析器,但这里仍然有一个正则表达式,它将在每个链接的 href 属性的值上创建一个捕获组。它将匹配使用双引号还是单引号。

<a\s+(?:[^>]*?\s+)?href=(["'])(.*?)\1

您可以在here查看此正则表达式的完整说明。

片段游乐场:

const linkRx = /<a\s+(?:[^>]*?\s+)?href=(["'])(.*?)\1/;
const textToMatchInput = document.querySelector('[name=textToMatch]');

document.querySelector('button').addEventListener('click', () => 
  console.log(textToMatchInput.value.match(linkRx));
);
<label>
  Text to match:
  <input type="text" name="textToMatch" value='<a href="google.com"'>
  
  <button>Match</button>
 </label>

【讨论】:

请注意,这也将匹配:&lt;area href="a.html"&gt; @MostyMostacho 已修复! 不错的一个。我对\s+)? 有点迷失了。也许这会更简单,或者我错过了什么? &lt;a\s+[^&gt;]*?href="([^"]*)" @MostyMostacho 附加的\s+ 是必需的,否则&lt;a somethinghref="test" 也会匹配。 @plalx 请注意,这与 href='//example.com'href=//example.com 不匹配,而仅匹配双引号之间的内容。不幸的是,有些人仍在使用这两个选项之一(浏览器接受这些选项)。如果这两个也包括在内,正则表达式会怎样?【参考方案2】:

不推荐使用regex解析html

regex 用于经常出现的模式。html 的格式不规则(xhtml 除外)。例如,html 文件是有效的,即使您有一个closing tag!这可能会破坏你的代码。

使用像htmlagilitypack这样的html解析器

您可以使用此代码使用HtmlAgilityPack 检索锚标记中的所有href's

HtmlDocument doc = new HtmlDocument();
doc.Load(yourStream);

var hrefList = doc.DocumentNode.SelectNodes("//a")
                  .Select(p => p.GetAttributeValue("href", "not found"))
                  .ToList();

hrefList 包含所有href`s

【讨论】:

在这种情况下,问题非常具体,使用正则表达式就足够安全了。我们可以安全地丢弃任何不是&lt;a[^&gt;]* href="([^"]*)" 形式的东西,除非你想处理单引号属性,但这是一个简单的解决方法。 @plalx 确实是..但不推荐。如果 html 很大并且在许多情况下它是巨大的,性能将成为瓶颈 你测试过性能吗?我很确定正则表达式会比使用必须生成整个 DOM 树的解析器更快。 也许你应该再读一遍对话? =P 你同意我的看法,然后提出了性能因素。现在你不同意并且你说表现并不重要,你自相矛盾。我跟不上嘿嘿;) 当搜索的模式很简单并且必须一次处理大量的HTML文档时,我用正则表达式解析HTML是合理的。即使这样,它也应该被视为一种积极的优化,并且只有在确定解析造成性能问题时才实施。【参考方案3】:

谢谢大家(特别是@plalx)

我发现用如此复杂和神秘的模式来强​​制 href 属性的有效性而使用诸如&lt;a\s+(?:[^&gt;]*?\s+)?href="([^"]*)"这样的简单表达式是非常过分的 足以捕获所有 URL。如果您想确保它们至少包含一个查询字符串,您可以使用&lt;a\s+(?:[^&gt;]*?\s+)?href="([^"]+\?[^"]+)"


我的最终正则表达式字符串:

首先使用其中一个:
st = @"((www\.|https?|ftp|gopher|telnet|file|notes|ms-help):((//)|(\\\\))+ \w\d:#@%/;$()~_?\+-=\\\.&]*)";
st = @"<a href[^>]*>(.*?)</a>";
st = @"((([A-Za-z]3,9:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)";
st = @"((?:(?:https?|ftp|gopher|telnet|file|notes|ms-help):(?://|\\\\)(?:www\.)?|www\.)[\w\d:#@%/;$()~_?\+,\-=\\.&]+)";
st = @"(?:(?:https?|ftp|gopher|telnet|file|notes|ms-help):(?://|\\\\)(?:www\.)?|www\.)";
st = @"(((https?|ftp|gopher|telnet|file|notes|ms-help):((//)|(\\\\))+)|(www\.)[\w\d:#@%/;$()~_?\+-=\\\.&]*)";
st = @"href=[""'](?<url>(http|https)://[^/]*?\.(com|org|net|gov))(/.*)?[""']";
st = @"(<a.*?>.*?</a>)";
st = @"(?:hrefs*=)(?:[s""']*)(?!#|mailto|location.|javascript|.*css|.*this.)(?.*?)(?:[s>""'])";
st = @"http://([\\w+?\\.\\w+])+([a-zA-Z0-9\\~\\!\\@\\#\\$\\%\\^\\&amp;\\*\\(\\)_\\-\\=\\+\\\\\\/\\?\\.\\:\\;\\'\\,]*)?";
st = @"http(s)?://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?";
st = @"(http|https)://([a-zA-Z0-9\\~\\!\\@\\#\\$\\%\\^\\&amp;\\*\\(\\)_\\-\\=\\+\\\\\\/\\?\\.\\:\\;\\'\\,]*)?";
st = @"((http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&amp;:/~\+#]*[\w\-\@?^=%&amp;/~\+#])?)";
st = @"http://([\\w+?\\.\\w+])+([a-zA-Z0-9\\~\\!\\@\\#\\$\\%\\^\\&amp;\\*\\(\\)_\\-\\=\\+\\\\\\/\\?\\.\\:\\;\\'\\,]*)?";
st = @"http(s?)\:\/\/[0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*(:(0-9)*)*(\/?)([a-zA-Z0-9\-\.\?\,\'\/\\\+&amp;%\$#_]*)?$";
st = @"(?<Protocol>\w+):\/\/(?<Domain>[\w.]+\/?)\S*";

我的选择是

@"(?<Protocol>\w+):\/\/(?<Domain>[\w.]+\/?)\S*"

第二次使用这个:

st = "(.*)?(.*)=(.*)";

问题已解决。谢谢大家:)

【讨论】:

你问的问题看起来有点过分了。 请考虑更改您选择的答案。没有人会或不应该使用如此复杂的正则表达式来完成这项简单的任务。 @plalx 为什么?不幸的是,我不再使用正则表达式 - 但去年正则表达式对我有用。如果您确定您有更好的选择,请说使其成为最佳答案。 tnx ;) 好吧,事实是,即使您拥有世界上最聪明的正则表达式,可以验证 href 内容实际上是一个 URL,但您不能断言它是一个有效的 URL,因为它可能不是根本存在。因此,我发现使用如此复杂和神秘的模式强制 href 属性的有效性是非常过分的,而像 &lt;a\s+(?:[^&gt;]*?\s+)?href="([^"]*)" 这样的简单表达式就足以捕获所有 URL。如果你想确保它们至少包含一个查询字符串,你可以使用&lt;a\s+(?:[^&gt;]*?\s+)?href="([^"]+\?[^"]+)" ...如果您认为它更好,为什么不直接标记 plalx 的答案被接受呢?您实际上是在复制内容,这不是我们想要鼓励的。【参考方案4】:

试试这个:

 public partial class Form1 : Form
    
        public Form1()
        
            InitializeComponent();
        

        private void Form1_Load(object sender, EventArgs e)
        
            var res = Find(html);
        

        public static List<LinkItem> Find(string file)
        
            List<LinkItem> list = new List<LinkItem>();

            // 1.
            // Find all matches in file.
            MatchCollection m1 = Regex.Matches(file, @"(<a.*?>.*?</a>)",
                RegexOptions.Singleline);

            // 2.
            // Loop over each match.
            foreach (Match m in m1)
            
                string value = m.Groups[1].Value;
                LinkItem i = new LinkItem();

                // 3.
                // Get href attribute.
                Match m2 = Regex.Match(value, @"href=\""(.*?)\""",
                RegexOptions.Singleline);
                if (m2.Success)
                
                    i.Href = m2.Groups[1].Value;
                

                // 4.
                // Remove inner tags from text.
                string t = Regex.Replace(value, @"\s*<.*?>\s*", "",
                RegexOptions.Singleline);
                i.Text = t;

                list.Add(i);
            
            return list;
        

        public struct LinkItem
        
            public string Href;
            public string Text;

            public override string ToString()
            
                return Href + "\n\t" + Text;
            
        

      

输入:

  string html = "<a href=\"www.aaa.xx/xx.zz?id=xxxx&name=xxxx\" ....></a> 2.<a href=\"http://www.aaa.xx/xx.zz?id=xxxx&name=xxxx\" ....></a> "; 

结果:

[0] = www.aaa.xx/xx.zz?id=xxxx&name=xxxx
[1] = http://www.aaa.xx/xx.zz?id=xxxx&name=xxxx

C# Scraping HTML Links

抓取 HTML 会提取重要的页面元素。它有许多合法用途 适用于网站管理员和 ASP.NET 开发人员。使用 Regex 类型和 WebClient,我们为 HTML 实现屏幕抓取。

已编辑

另一种简单的方法:您可以使用web browser 控件从标签a 中获取href,如下所示:(参见我的示例)

 public Form1()
        
            InitializeComponent();
            webBrowser1.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted);
        

        private void Form1_Load(object sender, EventArgs e)
        
            webBrowser1.DocumentText = "<a href=\"www.aaa.xx/xx.zz?id=xxxx&name=xxxx\" ....></a><a href=\"http://www.aaa.xx/xx.zz?id=xxxx&name=xxxx\" ....></a><a href=\"https://www.aaa.xx/xx.zz?id=xxxx&name=xxxx\" ....></a><a href=\"www.aaa.xx/xx.zz/xxx\" ....></a>";
        

        void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
        
            List<string> href = new List<string>();
            foreach (HtmlElement el in webBrowser1.Document.GetElementsByTagName("a"))
            
                href.Add(el.GetAttribute("href"));
            
        

【讨论】:

没有结束标签的锚标签是 valid..所以,在这种情况下,您的代码将 break 或不起作用...最好使用 html 解析器 @:The_Land_Of_Devils_SriLanka:html 解析器更适合动态内容。你是对的。 我使用了 2 次正则表达式,第一次是在这篇文章中,第二次是 this"(.*)?(.*)=(.*)"【参考方案5】:

试试这个正则表达式:

"href\\s*=\\s*(?:\"(?<1>[^\"]*)\"|(?<1>\\S+))"

您将从以下讨论中获得更多帮助:

Regular expression to extract URL from an HTML link

Regex to get the link in href. [asp.net]

希望对您有所帮助。

【讨论】:

【参考方案6】:
 HTMLDocument DOC = this.MySuperBrowser.Document as HTMLDocument;
 public IHTMLAnchorElement imageElementHref;
 imageElementHref = DOC.getElementById("idfirsticonhref") as IHTMLAnchorElement;

只需试试这段代码

【讨论】:

【参考方案7】:

我想出了这个,它支持锚和图像标签,并支持单引号和双引号。

<[a|img]+\\s+(?:[^>]*?\\s+)?[src|href]+=[\"']([^\"']*)['\"]

所以

<a href="/something.ext">click here</a>

将匹配:

 Match 1: /something.ext

<a href='/something.ext'>click here</a>

将匹配:

 Match 1: /something.ext

img src 属性也是如此

【讨论】:

【参考方案8】:

我采用了一种更简单的方法。这只是简单地查找 href 属性,并将值(在撇号之间)捕获到一个名为 url 的组中:

href=['"](?&lt;url&gt;.*?)['"]

【讨论】:

【参考方案9】:

我认为在这种情况下这是最简单的预赛之一

/<a\s*(.*?id[^"]*")/g

获取地址中带有变量id的链接

href 开始,包括它,获取所有字符/符号(. - 不包括换行符) 直到第一个 id 出现,包括它,然后所有符号到最近的下一个 " 符号 ([^"]*)

【讨论】:

以上是关于用于查找 <a> 链接的“href”值的正则表达式的主要内容,如果未能解决你的问题,请参考以下文章

python 字符串替换正则查找替换

xpath表达式从链接中选择href值

<a href=""> 在 PHP 中用于在源视图中隐藏链接

在 href (jQuery) 中查找带有图像扩展名的 <a>

在 selenium python 中通过 href 查找链接

<a>标签中href="javascript:;"的意思