【问题标题】:Novice Python/Regex: pull strings between <a> tags using regex新手 Python/Regex:使用 regex 在 <a> 标记之间拉取字符串
【发布时间】:2012-01-28 12:09:47
【问题描述】:

需要使用 re 模块在 Python 中的 href 属性标签之间拉取字符串。

我尝试了许多模式,例如:

patFinderLink = re.compile('\>"(CVE.*)"\<\/a>')

示例:我需要从以下位置提取标签之间的内容(在本例中为“CVE-2010-3718”):

<pre>
<a href="https://www.redhat.com/security/data/cve/CVE-2010-3718.html">CVE-2010-3718</a>
</pre>

我在这里做错了什么?任何意见是极大的赞赏。提前谢谢你。

太阳

【问题讨论】:

    标签: python regex beautifulsoup


    【解决方案1】:

    您需要使用正则表达式吗?我不认为你这样做,你不能用正则表达式解析 SGML,因为 SGML 本身不是正则的,请参阅这个著名的 stackoverflow 答案以了解原因:https://stackoverflow.com/a/1732454/88123

    无论如何。您应该使用 lxml Python 模块及其 xpath 实现。 xpath 支持选择以开头的文本。

    在这种情况下,XPath 将是//h1/text()

    或者,使用BeautifulSoup Python 模块。

    【讨论】:

    • lxml +1,我会再为著名的反reg-exp 答案 +1!
    • @Acorn - 我实际上查看了他链接的页面,并看到了 h1 中表示的 CVE 编号。
    • 正则表达式引起人们两个问题的原因正是这个。他们在不适用的地方使用它们。
    • @ikanobori 链接的答案以其文学品质而闻名,但这掩盖了他想要准确表达的内容。他是否使用“解析”来精确表示“提取文本树表示的过程”?在这种情况下,我可以相信他:正则表达式不能这样做,因为他解释的原因。但这绝不能导致地球上所有的人都虔诚地相信正则表达式永远不能用于分析文本。 “解析”这个词现在通常用作“分析”的意思,但在我看来,在计算机科学中它以前只意味着“提取一棵树”(?)这是一个可怜的混乱
    • 不使用正则表达式解析 HTML(特别是在这种情况下)的原因是 HTML 不是正则的。如果您正在使用(抓取)第三方维护的站点并且事情发生变化,那么如果您使用正则表达式(并且它们更难维护),那么您将在实际层面上做更多的工作。遗憾的是,HTML 不是常规的(它甚至没有定义要关闭哪些标签(自关闭等))。总而言之,一个简单的答案是:“不要使用正则表达式解析html”但答案的真正深度更多的是灰色地带。
    【解决方案2】:

    不要尝试使用正则表达式来解析 HTML 或 XML。使用解析器,例如lxml

    import lxml.html as lh
    
    tree = lh.fromstring(html)
    
    print tree.xpath("//pre/a[starts-with(., 'CVE')]/text()")
    

    结果:

    ['CVE-2010-3718']

    【讨论】:

    • lxml 至少比正则表达式慢 20 倍。事实上我一天测量了 100 次,但它可能不能代表 lxml 解决方案与正则表达式解决方案相比的中等超额时间,所以我更愿意说 20 .....
    【解决方案3】:

    使用

    re.compile('">(CVE.*?)</a>') 
    
    # instead of your re.compile('\>"(CVE.*)"\<\/a>')
    

    注意字符 / 不需要在正则表达式模式中转义

    请注意.* 之后的? 字符会停止量词* 的贪婪行为,以便在遇到第一个&lt;/a&gt; 时停止匹配。请参阅有关这一点的文档,这是基本的

    .

    使用re 分析 XML|GML 文本时有时会出现问题
    有一次,有人告诉我,一个可能的问题是一个标签可以写成几行,例如:

    ss = '''
    <pre>
        <a href="https://www.redhat.com/security/data/cve/CVE-2010-3718.html">CVE-20
        10-371
        8</a>
    </pre>'''
    

    在这种情况下,不会有任何匹配,因为在正则表达式模式中用作符号的点并不表示换行符“\n”。所以模式的.*? 部分不允许逐行运行。

    要纠正此问题,请使用re.DOTALL 规范,该规范赋予点符号表示任何和所有字符的能力。

    .

    请注意,普遍认为re 工具不得用于解析 SGML 或 XML 文本。但很少有人能够彻底解释原因。而我就是其中一个不知道确切原因的人。

    但我个人认为,正则表达式确实可以用来分析文本。我写的是“分析”而不是“解析”。

    据我了解,解析是分析文本并根据标签构建其树状表示的过程。
    虽然我将分析文本定义为......分析它而不是为了获得树表示。
    当不需要树表示从文本中提取数据时,请使用正则表达式,并且不要听那些对该主题有宗教考虑的人,例如在给出链接的有趣但具有欺骗性(在我看来)的帖子中

    【讨论】:

      【解决方案4】:

      我很惊讶没有人建议使用 BeautifulSoup:

      我会这样做:

      from BeautifulSoup import BeautifulSoup
      import re
      
      hello = """
      <pre>
      <a href="https://www.redhat.com/security/data/cve/CVE-2010-3718.html">CVE-2010-3718</a>
      <a href="https://www.redhat.com/security/data/cve/CVE-2010-3710.html">CVE-2010-3718</a>
      <a href="https://www.redhat.com/security/data/cve/CVE-2010-3700.html">CVE-2010-3718</a>
      </pre>
      """
      
      target = re.compile("CVE-\d+-\d+.html")
      commentSoup = BeautifulSoup(hello)
      atags = commentSoup.findAll(href=target)
      for a in atags:
          match = re.findall(target, a['href'])[0]
          print match
      

      结果:

      CVE-2010-3718.html
      CVE-2010-3710.html
      CVE-2010-3700.html
      

      【讨论】:

      • 虽然其他答案提出了可能更优雅的解决方案,但这个对我有用。谢谢。
      【解决方案5】:

      如果您仍想使用正则表达式进行 HTML 解析(虽然不推荐使用,但我不知道为什么)试试这个:

      a = re.compile('<a href=".*">(.*)</a>')
      result = a.match(string).group(0)
      

      结果将包含 CVE-2010-3718

      【讨论】:

        【解决方案6】:

        正如其他人已经建议的那样,正则表达式通常不是 HTML 解析的好工具。

        但是,如果您想使用正则表达式,这是我如何提取所有 URL 和 &lt;a&gt; &lt;/a&gt; 标签之间内容的元组的示例:

        import re
        
        #example html string with various hits
        html_string = """
            <pre>
            <a href="https://www.redhat.com/security/data/cve/CVE-2010-3718.html">CVE-2010-3718</a>
            <a href="https://www.redhat.com/security/data/cve/CVE-2010-3710.html">CVE-2010-3710</a>
            <a href="https://www.redhat.com/security/data/cve/CVE-2010-3700.html">CVE-2010-3700</a>
            </pre>
        """
        
        #regular expression:
        pattern = re.compile('<a href=([^>]*)>([^<]*)</a>')
        
        #find all matches in our html string:
        tuples = pattern.findall(html_string)
        
        for tuple in tuples:
            print "%s —> %s" % (tuple[1], tuple[0])
        

        正如其他人提到的,lxml 将是一个更合适的工具。

        如果你打算这样做,我建议你关注@Acorn 的回复。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-10-13
          • 2015-06-24
          • 2016-01-12
          • 2021-07-02
          • 1970-01-01
          • 1970-01-01
          • 2016-07-12
          • 2021-04-18
          相关资源
          最近更新 更多