【问题标题】:Getting the value of href attributes in all <a> tags on a html file with Python使用 Python 获取 html 文件中所有 <a> 标记中的 href 属性值
【发布时间】:2010-10-14 20:29:15
【问题描述】:

我正在用 python 构建一个应用程序,我需要获取一个网页中所有链接的 URL。我已经有一个函数,它使用 urllib 从网上下载 html 文件,并使用 readlines() 将其转换为字符串列表。

目前我有这段代码使用正则表达式(我不太擅长)来搜索每一行的链接:

for line in lines:
    result = re.match ('/href="(.*)"/iU', line)
    print result

这不起作用,因为它只为文件中的每一行打印“无”,但我确信我正在打开的文件上至少有 3 个链接。

有人可以给我一个提示吗?

提前致谢

【问题讨论】:

  • Sigh,另一个试图用正则表达式解析 HTML/XML 的问题。仅供参考,不推荐使用解析器,正如 eduffy 所建议的那样。
  • 为什么需要使用正则表达式?为什么 htmllib 不是一个选项?
  • 嗯,主要是因为我想学习一些正则表达式:)

标签: python html regex parsing


【解决方案1】:

Python 中有一个标准的 HTML 解析器。结帐htmllib

【讨论】:

  • htmllib 在 python 3.0 中已被弃用,所以为了以后的兼容性,我想避免它。
【解决方案2】:

Beautiful Soup 几乎可以轻松做到这一点:

from BeautifulSoup import BeautifulSoup as soup

html = soup('<body><a href="123">qwe</a><a href="456">asd</a></body>')
print [tag.attrMap['href'] for tag in html.findAll('a', {'href': True})]

【讨论】:

  • 完美地做到了。谢谢
【解决方案3】:

不要将 html 内容分成几行,因为一行中可能有多个匹配项。也不要假设 url 周围总是有引号。

做这样的事情:

links = re.finditer(' href="?([^\s^"]+)', content)

for link in links:
  print link

【讨论】:

    【解决方案4】:

    BeautifulSoup 的另一种替代方法是 lxml (http://lxml.de/);

    import lxml.html
    links = lxml.html.parse("http://stackoverflow.com/").xpath("//a/@href")
    for link in links:
        print link
    

    【讨论】:

      【解决方案5】:

      其他人没有告诉你的是,为此使用正则表达式不是一个可靠的解决方案。
      在许多情况下使用正则表达式会给你错误的结果:如果有 标签被注释掉,或者页面中有包含字符串“href=”的文本,或者如果有

      为此您需要XPath,它是一种用于 DOM 树的查询语言,即它允许您检索满足您指定条件的任何节点集(HTML 属性是 DOM 中的节点)。
      XPath 现在是一种很好的标准化语言 (W3C),并且得到所有主要语言的良好支持。我强烈建议您为此使用 XPath 而不是正则表达式。
      adw 的回答显示了一个针对您的特定情况使用 XPath 的示例。

      【讨论】:

        【解决方案6】:

        如前所述:正则表达式没有解析 HTML 的能力。不要使用正则表达式来解析 HTML。不要通过围棋。不要收取 200 英镑。

        使用 HTML 解析器。

        但为了完整性,主要问题是:

        re.match ('/href="(.*)"/iU', line)
        

        您不会使用“/.../flags”语法来装饰 Python 中的正则表达式。而是将标志放在单独的参数中:

        re.match('href="(.*)"', line, re.I|re.U)
        

        另一个问题是贪婪的“.*”模式。如果一行中有两个href,它会很乐意吸收第一场比赛的开头“和第二场比赛的结尾”之间的所有内容。您可以使用非贪婪的‘.*?’或更简单的‘[^"]*’来匹配第一个结束引号。

        但不要使用正则表达式来解析 HTML。真的。

        【讨论】:

          【解决方案7】:

          好吧,为了完整起见,我将在这里添加我发现的最佳答案,我在 Mark Pilgrim 的 Dive Into Python 一书中找到了它。

          下面是列出网页中所有 URL 的代码:

          from sgmllib import SGMLParser
          
          class URLLister(SGMLParser):
              def reset(self):                              
                  SGMLParser.reset(self)
                  self.urls = []
          
              def start_a(self, attrs):                     
                  href = [v for k, v in attrs if k=='href']  
                  if href:
                      self.urls.extend(href)
          
          import urllib, urllister
          usock = urllib.urlopen("http://diveintopython.net/")
          parser = urllister.URLLister()
          parser.feed(usock.read())         
          usock.close()      
          parser.close()                    
          for url in parser.urls: print url
          

          感谢所有回复。

          【讨论】:

            猜你喜欢
            • 2010-11-18
            • 2013-09-05
            • 2023-04-01
            • 1970-01-01
            • 2012-05-17
            • 2019-06-13
            • 2013-11-22
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多