【问题标题】:Extract part of a regex match提取正则表达式匹配的一部分
【发布时间】:2010-11-22 13:53:10
【问题描述】:

我想要一个正则表达式来从 HTML 页面中提取标题。目前我有这个:

title = re.search('<title>.*</title>', html, re.IGNORECASE).group()
if title:
    title = title.replace('<title>', '').replace('</title>', '') 

是否有正则表达式可以只提取

的内容,这样我就不必删除标签?

【问题讨论】:

  • 哇,我不敢相信所有调用解析整个 HTML 页面的响应只是为了提取一个简单的标题。多么矫枉过正!
  • 问题标题说明了一切 - 给出的示例 happens 是 HTML,但一般问题是......一般。

标签: python html regex html-content-extraction


【解决方案1】:

在正则表达式中使用(),在python中使用group(1)来检索捕获的字符串(re.search如果没有找到结果将返回None,所以不要使用@ 987654328@直接):

title_search = re.search('<title>(.*)</title>', html, re.IGNORECASE)

if title_search:
    title = title_search.group(1)

【讨论】:

  • 如果没有找到标题,你什么都不做,为什么直接使用 group() 会是一件坏事? (无论如何你都可以捕捉到异常)
  • 是的,但是大多数人忘记了异常,当他们在运行时看到它们时真的很惊讶:)
  • 别忘了运行import re,否则你会得到NameError: name 're' is not defined
【解决方案2】:

请注意,从Python 3.8 开始,并引入assignment expressions (PEP 572):= 运算符),可以通过将 if 条件中的匹配结果直接捕获为变量并重新对Krzysztof Krasoń's solution 进行一些改进在条件体中使用它:

# pattern = '<title>(.*)</title>'
# text = '<title>hello</title>'
if match := re.search(pattern, text, re.IGNORECASE):
  title = match.group(1)
# hello

【讨论】:

    【解决方案3】:

    尝试使用捕获组:

    title = re.search('<title>(.*)</title>', html, re.IGNORECASE).group(1)
    

    【讨论】:

      【解决方案4】:

      我可以推荐你去美丽的汤。 Soup 是一个非常好的库,可以解析所有的 html 文档。

      soup = BeatifulSoup(html_doc)
      titleName = soup.title.name
      

      【讨论】:

      • 我想补充一下,beautifulsoup 还可以解析不完整的 html,真的很好。
      【解决方案5】:
      re.search('<title>(.*)</title>', s, re.IGNORECASE).group(1)
      

      【讨论】:

        【解决方案6】:

        试试:

        title = re.search('<title>(.*)</title>', html, re.IGNORECASE).group(1)
        

        【讨论】:

        • 如果你真的想使用 REGEX 进行 HTML 解析,请不要在匹配时直接运行 .group(),因为它可能返回 None。
        • 您应该使用.*?,以防文档中有多个&lt;/title&gt;(不太可能,但您永远不知道)。
        • @iElectric:如果你真的想的话,你可以把它放在 try except 块中,对吧?
        【解决方案7】:

        所提供的代码片段不适用于Exceptions 我可以建议吗

        getattr(re.search(r"<title>(.*)</title>", s, re.IGNORECASE), 'groups', lambda:[u""])()[0]
        

        如果没有找到模式,或者第一个匹配,默认返回一个空字符串。

        【讨论】:

          【解决方案8】:

          Krzysztof Krasoń 目前投票最多的答案以&lt;title&gt;a&lt;/title&gt;&lt;title&gt;b&lt;/title&gt; 失败。此外,它会忽略跨越行边界的标题标签,例如,出于行长的原因。最后,它以&lt;title &gt;a&lt;/title&gt; 失败(这是有效的HTML:White space inside XML/HTML tags)。

          因此我提出以下改进:

          import re
          
          def search_title(html):
              m = re.search(r"<title\s*>(.*?)</title\s*>", html, re.IGNORECASE | re.DOTALL)
              return m.group(1) if m else None
          

          测试用例:

          print(search_title("<title   >with spaces in tags</title >"))
          print(search_title("<title\n>with newline in tags</title\n>"))
          print(search_title("<title>first of two titles</title><title>second title</title>"))
          print(search_title("<title>with newline\n in title</title\n>"))
          

          输出:

          with spaces in tags
          with newline in tags
          first of two titles
          with newline
            in title
          

          最终,我和其他人一起推荐了一个 HTML 解析器——不仅是为了处理 HTML 标记的非标准使用。

          【讨论】:

            【解决方案9】:

            我认为这就足够了:

            #!python
            import re
            pattern = re.compile(r'<title>([^<]*)</title>', re.MULTILINE|re.IGNORECASE)
            pattern.search(text)
            

            ...假设您的文本 (HTML) 位于名为“text”的变量中。

            这还假设没有其他 HTML 标记可以合法地嵌入到 HTML TITLE 标记中,并且没有任何方法可以合法地将任何其他

            然而 ...

            不要在 Python 中使用正则表达式进行 HTML 解析。使用 HTML 解析器! (除非您要编写一个完整的解析器,当各种 HTML、SGML 和 XML 解析器已经在标准库中时,这将是一项额外的、多余的工作)。

            如果您正在处理“现实世界”标签汤 HTML(通常不符合任何 SGML/XML 验证器),请使用 BeautifulSoup 包。它不在标准库中(目前),但广泛推荐用于此目的。

            另一个选项是:lxml ... 这是为结构正确(符合标准)的 HTML 编写的。但它可以选择使用 BeautifulSoup 作为解析器:ElementSoup

            【讨论】:

            • re.MULTILINE 应该在这里做什么?它改变了行首^ 和行尾$,这两个你都不使用。
            【解决方案10】:

            没有人建议使用lookahead 和lookbehind 是否有特殊原因?我来到这里试图做同样的事情,(?&lt;=&lt;title&gt;).+(?=&lt;\/title&gt;) 效果很好。它只会匹配括号之间的内容,因此您不必执行整个组的操作。

            【讨论】:

              【解决方案11】:

              我需要匹配 package-0.0.1(名称、版本)的内容,但想拒绝无效版本,例如 0.0.010

              参见regex101 示例。

              import re
              
              RE_IDENTIFIER = re.compile(r'^([a-z]+)-((?:(?:0|[1-9](?:[0-9]+)?)\.){2}(?:0|[1-9](?:[0-9]+)?))$')
              
              example = 'hello-0.0.1'
              
              if match := RE_IDENTIFIER.search(example):
                  name, version = match.groups()
                  print(f'Name:     {name}')
                  print(f'Version:  {version}')
              else:
                  raise ValueError(f'Invalid identifier {example}')
              
              

              输出:

              Name:     hello
              Version:  0.0.1
              

              【讨论】:

                猜你喜欢
                • 2011-06-13
                • 1970-01-01
                • 2011-01-12
                • 1970-01-01
                • 2017-11-29
                • 2017-06-23
                相关资源
                最近更新 更多