Python模块BeautifulSoup提取锚点href

7
我正在使用BeautifulSoup模块按以下方式选择HTML中的所有href链接:
def extract_links(html):
  soup = BeautifulSoup(html)
  anchors = soup.findAll('a')
  print anchors
  links = []
  for a in anchors:
    links.append(a['href'])
  return links

但有时会出现以下错误信息导致失败:

Traceback (most recent call last):
File "C:\py\main.py", line 33, in <module>
urls = extract_links(page)
File "C:\py\main.py", line 11, in extract_links
links.append(a['href'])
File "C:\py\BeautifulSoup.py", line 601, in __getitem__
return self._getAttrMap()[key]
KeyError: 'href'
6个回答

8

并非所有锚点标签都会有href属性。在尝试访问该属性之前,您应该检查该锚点是否具有href。

if a.has_key('href')
  links.append(a['href'])

在查看了一些评论后,我认为这是处理此情况的最pythonic方式。


谢谢,但现在出现以下错误消息:Traceback (most recent call last): File "C:\py\main.py", line 34, in <module> urls = extract_links(page) File "C:\py\main.py", line 11, in extract_links if 'href' in a.keys(): TypeError: 'NoneType' object is not callable - Michal
@micheal,你在字典中放置了没有href属性的a标签。与其要求字典提供可能具有href属性的标签,不如在将数据放入字典之前先询问数据是否具有该属性。 - yurisich
我认为新的错误是因为BeautifulSoup节点不是字典,所以keys不是你期望的。 - Thomas K

2

试试这个。

links = [a['href'] for a in anchors if a.has_key('href')]

或者,如果你更愿意改变一个已存在的列表
links = []
#...
links.extend(a['href'] for a in anchors if a.has_key('href'))

@Gabriel,文档可能更喜欢这样,但请考虑一下。 s = BeautifulSoup('<html><body><a>href</a></body></html>'); 'href' in s.findAll('a')[0] 的结果是 Truehas_key 不会泄漏信息。 - Matt Luongo

2

soup.findAll()返回一个包含属性字典的“标签”列表。因此,您需要提取它们的属性并对其进行操作。

以您的示例为基础进行修改,这是可行的代码:

def extract_links(html):
  soup = BeautifulSoup(html)
  anchors = soup.findAll('a')
  print anchors
  links = []
  for a in anchors:
    if a.attrs.has_key('href'):
      links.append(a['href'])
return links

0

Pythonic 的方式可能是这样的:

for a in anchors:
    try:
        links.append(a['href'])
    except KeyError:
        pass

这将简单地跳过任何没有 href 属性的 <a> 标签。


1
我认为has_key()比使用错误来进行逻辑判断更符合Pythonic的风格,但是社区中似乎有人对此持不同意见。 - Matt Luongo
@MattLuongo:这取决于你在做什么。我觉得最好表达为“获取每个链接的地址,如果没有链接就算了”,而不是“检查每个链接是否有地址,如果有,再获取它”。问题在于 has_key 在字典中已被弃用,但 in 对 BS 节点的作用不同。 - Thomas K
我猜这就是为什么Tag不是dict的子类。无论如何,由于这个原因,这个弃用并不太相关。 - Matt Luongo
我同意 @MattLuongo 的看法。我曾经试图在文档中找到这个,但我忘记了 Python 文档有多么糟糕。 - tjarratt
@tjarratt:Python的文档还好,但是BeautifulSoup不是Python的一部分。 - Thomas K

0
你需要先将 a.attrs 转换为 dict,然后再访问该元素。
links.append(dict(a.attrs)['href'])

额,我想你的意思是 links.append(dict(a.attrs)['href'])..? 但这并不能处理那些带有 href 属性的标签。 - Matt Luongo
你的意思是没有 href 吗?那么你是正确的。我的个人经验表明我需要进行强制转换。 - Sufian Latif
哈,不用了,谢谢。我只是想说上面的代码没有将a.attrs转换为dict,而是将a.attrs['href']转换为dict,这会引发一个TypeError错误。 - Matt Luongo
糟糕,我的错...应该更加小心。 - Sufian Latif

0
  1. 我使用了上面的注释,但是出现了警告,所以我将其更改为 has_attr 并通过

    if i.has_attr("href"):
        print(i.string, i['href'])
    

    用户警告:has_key 已弃用。请改用 has_attr("href")。

2.Pass——OK

if i.has_attr("href"):
    print(i.string, i['href'])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接