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

MrR*_*ing 30 c# regex

我需要一个正则表达式模式来查找HTML中的网页链接.

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

我的字符串是:

  1. <a href="www.example.com/page.php?id=xxxx&name=yyyy" ....></a>
  2. <a href="http://www.example.com/page.php?id=xxxx&name=yyyy" ....></a>
  3. <a href="https://www.example.com/page.php?id=xxxx&name=yyyy" ....></a>
  4. <a href="www.example.com/page.php/404" ....></a>

1,2和3是有效的,我需要它们,但是4号对我来说无效(?并且=是必不可少的)


谢谢大家,但我不需要解析<a>.我有一个href="abcdef"格式的链接列表 .

我需要获取href链接并过滤它,我最喜欢的网址必须包含?=喜欢page.php?id=5

谢谢!

pla*_*alx 61

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

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

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

片段操场:

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

document.querySelector('button').addEventListener('click', function () {
  console.log(textToMatchInput.value.match(rx));
});
Run Code Online (Sandbox Code Playgroud)
<label>
  Text to match:
  <input type="text" name="textToMatch" value='<a href="google.com"'>
  
  <button>Match</button>
 </label>
Run Code Online (Sandbox Code Playgroud)

  • 注意这也将匹配:`<area href ="a.html">` (2认同)

Ani*_*dha 11

regex建议不要使用解析html

regex用于定期发生的模式.html是不是经常与它的格式(除xhtml).例如html文件,即使你有效closing tag!这可能会破坏你的代码.

使用像htmlagilitypack这样的html解析器

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

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

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

hrefList 包含所有href的

  • 在这种情况下,问题非常具体,因此使用正则表达式足够安全。我们可以安全地丢弃任何不是 `&lt;a[^&gt;]* href="([^"]*)"` 形式的内容,除非您想处理单引号属性,但这是一个简单的解决方案。 (2认同)
  • 你测试过性能吗?我很确定正则表达式会比使用必须生成整个 DOM 树的解析器更快。 (2认同)

KF2*_*KF2 7

试试这个 :

 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;
            }
        }

    }  
Run Code Online (Sandbox Code Playgroud)

输入:

  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> "; 
Run Code Online (Sandbox Code Playgroud)

结果:

[0] = {www.aaa.xx/xx.zz?id=xxxx&name=xxxx}
[1] = {http://www.aaa.xx/xx.zz?id=xxxx&name=xxxx}
Run Code Online (Sandbox Code Playgroud)

C#抓取HTML链接

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

编辑

另一个简单的方法:你可以使用一个web browser控件来获取href标记a,如下所示:(参见我的例子)

 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"));
            }
        }
Run Code Online (Sandbox Code Playgroud)


MrR*_*ing 5

谢谢大家(特别是@plalx)

我发现用这样一个复杂而隐秘的模式来强​​制href属性的有效性是很矫kill的,而一个简单的表达式 就足以捕获所有URL。如果要确保它们至少包含一个查询字符串,则可以使用
<a\s+(?:[^>]*?\s+)?href="([^"]*)"

<a\s+(?:[^>]*?\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*";
Run Code Online (Sandbox Code Playgroud)

我的选择是

@"(?<Protocol>\w+):\/\/(?<Domain>[\w.]+\/?)\S*"
Run Code Online (Sandbox Code Playgroud)

第二个使用这个:

st = "(.*)?(.*)=(.*)";
Run Code Online (Sandbox Code Playgroud)


问题解决了。感谢大家 :)

  • 对于您提出的问题,这似乎有些过头了。 (4认同)
  • 请考虑更改您选择的答案。没有人会也不应该使用如此复杂的正则表达式来完成这项简单的任务。 (2认同)
  • 事实上,即使您拥有世界上最智能的正则表达式来验证“href”内容实际上是一个 URL,您也不能断言它是一个有效的 URL,因为它可能根本不存在。因此,我发现它用如此复杂和神秘的模式来强​​制执行“href”属性的有效性,而使用诸如“&lt;a\s+(?:[^&gt;]*?\s+)?href=”这样的简单表达式是相当过分的。 ([^"]*)"` 足以捕获所有 URL。如果你想确保它们至少包含一个查询字符串,你可以使用 `&lt;a\s+(?:[^&gt;]*?\s+ )?href="([^"]+\?[^"]+)"` (2认同)
  • ...如果您认为更好,为什么不只是将plalx的答案标记为已接受?您实质上是在这里复制内容,这不是我们想要鼓励的。 (2认同)

Daa*_*rgh 5

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

href=['"](?<url>.*?)['"]