BeautifulSoup: найти имена классов: И + НЕ - PullRequest
0 голосов
/ 05 июля 2018

У меня есть два разных набора тегов div в HTML:

<div class="ABC BCD CDE123">

<div class="ABC BCD CDE234">

<div class="ABC BCD CDE345">

and 

<div class="ABC XYZ BCD">

Я хочу выбрать все теги с ABC и BCD, но не содержащие класс XYZ с BeautifullSoup4.

Я уже знаю об этом подходе:

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

, который ищет как ИЛИ (поэтому должны присутствовать ABC или BCD).

Я также знаю об этом подходе здесь:

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

что вернет все div с длиной имени класса 5

Я попытался решить мою проблему следующим образом:

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» передается myfunction, поэтому theclass = «ABC» а не theclass = 'ABC BCD CDE123', что я ожидал ... это также причина, почему я думаю, почему лямбда-функция не работает.

любая подсказка, как я могу отфильтровать теги в соответствии с моим требованием: Я хочу выбрать все теги с ABC и BCD, но не содержащие класс XYZ с BeautifullSoup4.

??

Спасибо за ваши мысли ...

Ответы [ 3 ]

0 голосов
/ 05 июля 2018

Я не знаю об одношаговом решении, но вы можете использовать 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']]
0 голосов
/ 08 июля 2018

Ваш подход был верным, но вы упустили одну вещь. BeautifulSoup преобразует значения атрибута class в список.

Например:

>>> 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: <strong>'ABC' in c and 'BCD' in c and 'XYZ' not in c</strong>))

Выход:

[<div class="ABC BCD CDE123"></div>,
 <div class="ABC BCD CDE234"></div>,
 <div class="ABC BCD CDE345"></div>]
0 голосов
/ 05 июля 2018

Это можно сделать с помощью SET . Получить список всех результатов с классами ABC и BCD. Вложите результат в набор Python. Примените то же самое для XYZ. Теперь у вас будет два набора, один для ABC и BCD, а другой для XYZ. Вычтите оба набора

Чтобы использовать ABC и BCD в списке поиска, используйте выберите функцию вместо 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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...