BeautifulSoup:查找类名称:AND + NOT

时间:2018-07-05 11:09:23

标签: python html beautifulsoup

我在HTML中有两组不同的div标签:

<div class="ABC BCD CDE123">

<div class="ABC BCD CDE234">

<div class="ABC BCD CDE345">

and 

<div class="ABC XYZ BCD">

我想选择所有带有ABC和BCD的标签,但不包含带有BeautifullSoup4的XYZ类。

我已经知道这种方法:

soup.find_all('div', class_=['ABC','BCD'])

,其搜索为OR(因此必须存在ABC或BCD)。

我在这里也知道这种方法:

def myfunction(theclass):
    return theclass is not None and len(theclass)=5
soup.find_all('div', class_=myfunction)

将返回所有类名长度为5的div

然后我尝试用以下方法解决我的问题:

soup.find_all('div', class_ = lambda x: x and 'ABC' and 'BCD' in x.split() and x and 'XYZ' not in x.split())

但是这没有用... 因此,我尝试在此处使用这种方法进行调试:

def myfunction(theclass):
    print theclass
    return True
soup.find_all('div', class_=myfunction)

问题似乎出在这样的标签上:

<div class="ABC BCD CDE123">

只有'ABC'移交给我的功能,因此class ='ABC' 而不是我所期望的class ='ABC BCD CDE123'... 这也是我猜测lambda函数失败的原因。

任何提示,如何根据我的要求过滤标签: 我想选择所有带有ABC和BCD的标签,但不包含带有BeautifullSoup4的XYZ类。

??

谢谢您的想法...

3 个答案:

答案 0 :(得分:1)

可以使用 SET 完成此操作。 使用ABC和BCD类获取所有结果的列表。将结果放入python SET中。将相同的内容应用于XYZ。现在,您将有两个SET,一个用于ABC和BCD,另一个用于XYZ。减去两个集

要在搜索列表中使用ABC和BCD,请使用 select 功能而不是 find_all

from bs4 import BeautifulSoup

data = '''
<div class="ABC BCD CDE123"></div>
<div class="ABC BCD CDE234"></div>
<div class="ABC BCD CDE345"></div>
<div class="ABC XYZ BCD"></div>
<div class="ABC XYZ AAC"></div>
<div class="ABC AAC"></div>
'''

soup = BeautifulSoup(data)
ABC_BCD = set(soup.select('div.ABC.BCD'))
XYZ     = set(soup.select('div.XYZ'))
result = ABC_BCD - XYZ
for element in result:
    print element

输出

<div class="ABC BCD CDE234"></div>
<div class="ABC BCD CDE123"></div>
<div class="ABC BCD CDE345"></div>

使用find_all使用相同的代码

ABC_BCD = set(soup.find_all('div', class_=['ABC','BCD']))
XYZ     = set(soup.find_all('div', class_=['XYZ']))
result = ABC-BCD
for element in result:
    print element

输出为

<div class="ABC BCD CDE234"></div>
<div class="ABC AAC"></div> #This is what we dont need
<div class="ABC BCD CDE123"></div>
<div class="ABC BCD CDE345"></div>

答案 1 :(得分:0)

我不知道一步解决方案,但是您可以使用CSS select,然后过滤掉不需要的元素。

from bs4 import BeautifulSoup

html = '''
<div class="ABC BCD CDE123"></div>
<div class="ABC BCD CDE234"></div>
<div class="ABC BCD CDE345"></div>
<div class="ABC XYZ BCD"></div>
<div class="ABC XYZ AAC"></div>
<div class="ABC AAC"></div>
'''

soup = BeautifulSoup(html, "html.parser")
divs = soup.select('div.ABC.BCD')
result = [div for div in divs if "XYZ" not in div['class']]

答案 2 :(得分:0)

您的方法是正确的,但是您错过了一件事。 BeautifulSoup会在列表中转换属性>>> soup.div['class'] ['ABC', 'BCD', 'CDE123'] 的值。

例如:

x.split()

因此,您不应使用html = ''' <div class="ABC BCD CDE123"></div> <div class="ABC BCD CDE234"></div> <div class="ABC BCD CDE345"></div> <div class="ABC XYZ BCD"></div>''' ,而应直接检查该值是否在列表中。

代码:

soup = BeautifulSoup(html, 'html.parser')
print(soup.find_all('div', class_=lambda c: 'ABC' in c and 'BCD' in c and 'XYZ' not in c))
[<div class="ABC BCD CDE123"></div>,
 <div class="ABC BCD CDE234"></div>,
 <div class="ABC BCD CDE345"></div>]

输出:

result Func(A a,B b,C c,D d,E e)
{
func f;
f.setA(a);
f.setB(b);
......
return f.execute();
}