Web爬虫 - 如何用Beautiful Soup检查<a>标签的href是否在li标签内?

1 投票
1 回答
2083 浏览
提问于 2025-04-18 02:36

我正在用Python和Beautiful Soup写一个网络爬虫,目的是抓取维基百科的内容。不过,维基百科上有很多我不想看的无用链接。

比如说:

那些在目标部分前面有#的链接

<li class="toclevel-1 tocsection-1">
  <a href="#Overview">
    <span class="tocnumber">1</span>
    <span class="toctext">Overview</span>
  </a>
</li>

讨论页面

<li class="nv-talk">
  <a href="/wiki/Template_talk:Data_structures" title="Template talk:Data structures">
    <span title="Discuss this template" style=";;background:none transparent;border:none;;">t</span>
  </a>
</li>

模板页面

<li class="nv-view">
  <a href="/wiki/Template:Data_structures" title="Template:Data structures">
    <span title="View this template" style=";;background:none transparent;border:none;;">v</span>
  </a>
</li>

等等...

现在,我把所有已经访问过的链接存储在一个字典里,这样就不会重复访问。为了避免那些目标链接,我只需要检查链接到#符号的部分是否已经在字典里。

不过,我在处理讨论、模板和其他类似页面时遇到了一些麻烦。

它们有一个独特的特点,就是总是出现在<li>标签里面,并且有一些类属性(比如"nv-talk""nv-view"等),但是我的爬虫主要是看<a>标签,所以我无法访问包含它们的<li>标签的属性。

而且,并不是页面上的所有链接都在<li>标签里,所以我也不能仅仅搜索<li>标签。

有没有什么好主意呢?

1 个回答

2

你可以使用find_parents()这个方法,它是BeautifulSoup库中的一个功能。这个方法可以告诉你某个标签是否在另一个具有特定属性的标签里面。在这个例子中,我们要找的是一个锚标签(也就是链接)是否在一个带有nv-talknv-view类属性的标签里面。

示例:

html = '''<li class="nv-talk"><a href="/wiki/Template_talk:Data_structures" title="Template talk:Data structures"><span title="Discuss this    template" style=";;background:none    transparent;border:none;;">t</span></a></li>    '''
soup = BeautifulSoup(html)
a_tag = soup.find('a')
a_tag.find_parents(attrs={'class':'nv-talk'})

这段代码会给你:

[<li class="nv-talk"><a href="/wiki/Template_talk:Data_structures" title="Template talk:Data    structures"><span style=";;background:none transparent;border:none;;"    title="Discuss this template">t</span></a></li>]

对于你网址列表中的每一个锚标签,你可以检查一下find_parents()是否返回一个空列表。如果返回的是空列表,那就说明这个链接不属于“讨论”或“谈话”页面,因此在抓取的时候是安全的。

解决这个问题的另一种方法是查看锚标签的href属性是否以'http'或'https'开头。但我不太确定这是否符合你代码的逻辑。我的意思是,href属性以#开头的锚标签是指向同一页面内的某个部分的链接。如果你想忽略这些链接,可以找那些不以#开头,而是以httphttps开头的锚标签。这就是我的意思:

html = '''
<li class="toclevel-1 tocsection-1"><a href="#Overview"><span class="tocnumber">1</span> <span class="toctext">Overview</span></a></li>
<li class="toclevel-1 tocsection-1"><a href="http://www.google.com"><span class="tocnumber">1</span> <span class="toctext">Overview</span></a></li>
<li class="toclevel-1 tocsection-1"><a href="#Overview"><span class="tocnumber">1</span> <span class="toctext">Overview</span></a></li>
'''
soup = BeautifulSoup(html)
a_tag = soup.find('a', attrs={'href': re.compile(r'^http.*')})

这样你就只会得到以http开头的链接。

撰写回答