查找元素的直接子元素

时间:2017-03-31 23:08:57

标签: python html dom web-scraping beautifulsoup

我正在编写一个在Python中测试this现象的解决方案。我已经完成了大部分逻辑,但是在维基百科文章中关注链接时会出现许多边缘情况。

我遇到的问题出现在this之类的网页上,其中第一个<p>具有多个级别的子元素,第一组括号需要后的第一个<a>标记被提取。在这种情况下,(要提取this link),您必须跳过括号,然后转到下一个锚标记/ href。在大多数文章中,我的算法可以跳过括号,但是通过它在括号前面查找链接的方式(或者如果它们不存在),它会在错误的位置找到锚标记。具体来说,这里:<span style="font-size: small;"><span id="coordinates"><a href="/wiki/Geographic_coordinate_system" title="Geographic coordinate system">Coordinates</a>

算法通过迭代第一段标记中的元素(在文章的主体中),迭代地对每个元素进行字符串化,并首先检查它是否包含'('或''

是否有任何直接的方法可以避免使用嵌入式锚标记,并且只接受第一个<p>的直接子级链接?

以下是此代码的功能供参考:

**def getValidLink(self, currResponse):
        currRoot = BeautifulSoup(currResponse.text,"lxml")
        temp = currRoot.body.findAll('p')[0]
        parenOpened = False
        parenCompleted = False
        openCount = 0
        foundParen = False
        while temp.next:
            temp = temp.next
            curr = str(temp)
            if '(' in curr and str(type(temp)) == "<class 'bs4.element.NavigableString'>":
                foundParen = True
                break
            if '<a' in curr and str(type(temp)) == "<class 'bs4.element.Tag'>":
                link = temp
                break

        temp = currRoot.body.findAll('p')[0]
        if foundParen:
            while temp.next and not parenCompleted:
                temp = temp.next
                curr = str(temp)
                if '(' in curr:
                    openCount += 1
                    if parenOpened is False:
                        parenOpened = True
                if ')' in curr and parenOpened and openCount > 1:
                    openCount -= 1
                elif ')' in curr and parenOpened and openCount == 1:
                    parenCompleted = True
            try:
                return temp.findNext('a').attrs['href']
            except KeyError:
                print "\nReached article with no main body!\n"
                return None
        try:
            return str(link.attrs['href'])
        except KeyError:
            print "\nReached article with no main body\n"
            return None**

1 个答案:

答案 0 :(得分:1)

我认为你严重过分复杂了这个问题。

有多种方法可以在BeautifulSoup中使用元素之间的直接父子关系。一种方法是> CSS selector

In [1]: import requests  

In [2]: from bs4 import BeautifulSoup   

In [3]: url = "https://en.wikipedia.org/wiki/Sierra_Leone"    

In [4]: response = requests.get(url)    

In [5]: soup = BeautifulSoup(response.content, "html.parser")

In [6]: [a.get_text() for a in soup.select("#mw-content-text > p > a")]
Out[6]: 
['West Africa',
 'Guinea',
 'Liberia',
 ...
 'Allen Iverson',
 'Magic Johnson',
 'Victor Oladipo',
 'Frances Tiafoe']

在这里,我们发现了a元素直接位于p元素正下方元素的正下方{ - 1}} - 据我所知,这是维基百科的主要文章位于。

如果您需要单个元素,请使用id="mw-content-text"代替select_one()

此外,如果您想通过select()解决此问题,请传递recursive=False参数。