Попытка консолидации: кроме блоков в Beaufifulsoup4 - PullRequest
0 голосов
/ 18 декабря 2018

Это, возможно, гораздо более широкий вопрос, чем мой вариант использования.

Я использую Beautifulsoup для извлечения данных из HTML-документов.

Для тех, кто не знаком с Beautifulsoup, это по сути парсинг HTMLСтрока и использование методов класса для поиска и выделения определенных данных, с учетом явной инструкции.

Шаг первый: soup = Beautifulsoup(html_string)

Шаг второй: title= soup.find('h1').get_text()

Шаг первый анализируетВ документе, шаг два, содержится инструкция о том, какие данные извлекать, и, в вышеупомянутом случае, используя get_text(), также некоторое форматирование.

У меня обычно есть список таких действий, в которых данные могут присутствовать или не присутствовать,и любое условие является приемлемым.Например, на ряде страниц профиля некоторые пользователи могут вводить или не вводить favorite_color, favorite_movie или etc.Если эти данные есть, я хочу их, но если нет, то значение None в порядке.

Обычно я подхожу к этим случаям так:

soup = Beautifulsoup(html)

try:
    data_one = soup.find('div', class_='data_one').get_text()
except AttributeError as e:
    data_one = None

try:
    data_two= soup.find('div', class_='data_two').get_text()
except AttributeError as e:
    data_two= None

try:
    data_three = soup.find('div', class_='data_three ').get_text()
except AttributeError as e:
    data_three = None

Как можно себе представить, мойфайлы быстро становятся большими и трудными для навигации.

Какой самый СУХОЙ способ приблизиться к этому?

ПРИМЕЧАНИЕ. В моем случае использования каждые Блок try:except будет обращаться к одному классу исключений, AttributeError, который представляет данные, отсутствующие в html.

ПРИМЕЧАНИЕ. Я ищу что-то, что не ограничивало бы тип метода извлечения.Например, это то, что я хотел бы также использовать:

try:
    list_items = [x.get_text() for x in soup.find('div', class_='first').find_all('li', class_='first-child') and x.find('a', class_='conditional-link') is not None]
except AttributeError as e:
    list_items = None      

ОБНОВЛЕНИЕ 12/30/2018 Я все еще чувствую, что принятый ответ является наиболее правильным подходом.Я также чувствую, что это немного абстрактно по сравнению с другими подходами.Я хотел бы включить альтернативный подход здесь.Во-первых, позвольте мне сказать, что одной из основных проблем, которые пытается решить этот вопрос, является дальнейший доступ к данным с Beautifulsoup, когда они могут не быть данными.Например, метод get_text() вызывает AttributeError для элементов класса NoneType.

Это альтернативный подход, когда такая дополнительная спецификация необходима для извлечения данных из списка элементов, которые могут включать или не включать элементы NoneType:

# Get Initial Elements (NoneType assigned if Error)
data_one = soup.find('element', class_='e_one class_name')
data_two = soup.find('elemment', value='1')
data_three = soup.find('element', class_='parent').find('div', class_='name')

# Further parsing/extraction if element is not NoneType Object
data = [x.get_text(strip=True) if x is not None for x in [data_one, data_two, data_three]]

Это ничегореволюционный, но, кажется, обеспечивает очень плавный способ объединения некоторых частей кода.

Ответы [ 3 ]

0 голосов
/ 18 декабря 2018

Более специфичным для вашей ситуации способом обработки может быть цикл по списку значений класса:

classes = ['data_one', 'data_two', 'data_three']

result = {}
for class_value in classes:
    try:
        result[class_value] = soup.find('div', class_=class_value).get_text()
    except AttributeError:
        result[class_value]

print(result)
0 голосов
/ 18 декабря 2018

Или, вы можете просто использовать getattr() встроенную функцию в режиме LBYL :

data_one = getattr(soup.find('div', class_='data_one'), 'text', None)
data_two = getattr(soup.find('div', class_='data_two'), 'text', None)
data_three = getattr(soup.find('div', class_='data_three'), 'text', None)
0 голосов
/ 18 декабря 2018

Извлечение метода :

def get_text_or_none(element)
    try:
        return element.get_text()
    except AttributeError:
        return None

data_one = get_text_or_none(soup.find('div', class_='data_one'))
data_two = get_text_or_none(soup.find('div', class_='data_two'))
data_three = get_text_or_none(soup.find('div', class_='data_three'))

Это подход EAFP .

LBYL люди будут делатьэто так:

return element.get_text() if element else None
...