使用BeautifulSoup查找包含AND NOT包含b的所有标签

时间:2016-07-21 00:54:21

标签: python regex python-2.7 beautifulsoup

我正在使用bs4从js-stream-item类中提取li标签,但不包含下面的scroll-bump-user-card。 (只有a,b)

<li class="js-stream-item stream-item ">a<li>
<li class="js-stream-item stream-item stream-item ">b<li>
<li class="js-stream-item stream-item scroll-bump-user-card ">c<li>

我想到的方法有两种。

  1. 使用soup.find_all('li', class_=re.compile('js-stream-item'))获取所有代码,然后使用scroll-bump-user-card删除代码。

  2. 首先使用[tag.extract() for tag in soup.find_all('li', class_=re.compile('scroll-bump-user-card'))]删除,然后查找所有内容。

  3. 问题是,如果通过在re.compile()中使用AND NOT语法编辑正则表达式来获得a,b是一种不错的方法。

    更新我将alecxe答案的第一个选项重新写入一条长行,如下所示:

    soup.find_all(lambda tag: re.compile('js-stream-item').search(str(tag))
                          and not re.compile('scroll-bump-user-card').search(str(tag))
                          and tag.name == 'li')
    

1 个答案:

答案 0 :(得分:1)

首先,class是一个特殊的multi-valued attribute,需要special handling

一种选择是使用searching function并检查是否存在js-stream-item班级并且缺少scroll-bump-user-card班级:

def search_function(tag):
    if tag.name == "li":
        class_ = tag.get("class", [])
        return "js-stream-item" in class_ and "scroll-bump-user-card" not in class_

for li in soup.find_all(search_function):
    print(li.get_text(strip=True))

另一种选择是查找所有lijs-stream-item类,然后跳过liscroll-bump-user-card类的元素:

for li in soup.select("li.js-stream-item"):
    if "scroll-bump-user-card" in li["class"]:
        continue
    print(li.get_text(strip=True))

另一个,检查class是否以stream-item CSS selector结尾(不要使用此内容):

for li in soup.select("li[class$=' stream-item ']"):
    print(li.get_text(strip=True))

请注意,此用例的更好的CSS选择器是:

li.js-stream-item:not(.scroll-bump-user-card)

但由于BeautifulSoup中的CSS选择器支持有限,它无法正常工作。