@aqau123

Как реализовать валидацию?

year = soup.find('li', class_='CardInfoRow_year').find_all('span', class_ = 'CardInfoRow__cell')[1].find('a', class_ = 'Link').contents[0]

есть такой код.
допустим, в теории, что-то идет не так, элемента этого не будет и выплюнет он ошибку, но мне этого не надо, поэтому я хочу написать функцию валидации. если все хорошо, то все хорошо и возвращаем текст элемента, а если же нет - возвращаем строку "-".
как я вижу эту функцию
def validate(soupFunction(сюда мы передаем функцию супа. пример: soup.find('li', class_='CardInfoRow_year').find_all('span', class_ = 'CardInfoRow__cell')[1].find('a', class_ = 'Link')):
      #здесь мы ее вызываем
      try:
            item = soupFunction()
            return item.contents[0]
     except ... as e:
            return '-'

а вызываться она будет как-то так
year = validate(soup.find('li', class_='CardInfoRow_year').find_all('span', class_ = 'CardInfoRow__cell')[1].find('a', class_ = 'Link'))

как это можно реализовать? я знаю, как-то можно это сделать через лямбда функции.
  • Вопрос задан
  • 55 просмотров
Пригласить эксперта
Ответы на вопрос 1
Vindicar
@Vindicar
RTFM!
Ну можно и через лямбды, но - имеет ли это смысл? В чем будет выигрыш по сравнению с простым try except?
Будет менее читаемо, по-моему.

К сожалению, суп не поддерживает из коробки XPath - эта штука позволяла бы задать селектор как в примере одной строкой вида
//li[contains-token(@class, 'CardInfoRow_year')]//span[contains-token(@class, 'CardInfoRow__cell')][1]/a[contains-token(@class, 'link')]


Можно наколхозить грубое подобие:
class BSItem: # одиночный элемент
    def __init__(self, item):
        self._item = start
    
    def __bool__(self):
        return bool(self._item)
    
    def __str__(self):
        return self._item.contents[0] if self else ''
    
    @property
    def tag(self):
        return self._item
    
    def __truediv__(self, other): # оператор / ищет один элемент
        if not self: # пустой элемент так и останется пустым
            return self
        if isinstance(other, str): # item / 'tag.classname'
            tag, _, cls = other.partition('.')
            if cls:
                return BSItem(self._item.find(tag, class_=cls))
            else:
                return BSItem(self._item.find(tag))
        if isinstance(other, int) and other == 0: # item / 0 == item
            return self
        if callable(other): # item / lambda tag: tag.has_attr('id')
            return BSItem(self._item.find(other))
        raise ValueError() # передали ерунду
    
    def __floordiv__(self, other): # оператор // ищет все элементы
        if not self:
            return BSItems([])
        if isinstance(other, str): # item // 'tag.classname'
            tag, _, cls = other.partition('.')
            if cls:
                return BSItems(self._item.find_all(tag, class_=cls))
            else:
                return BSItems(self._item.find_all(tag))
        if callable(other): # item // lambda tag: tag.has_attr('id')
            return BSItems(self._item.find_all(other))
        raise ValueError()


class BSItems: # коллекция элементов
    def __init__(self, items):
        self._items = items
    
    def __bool__(self):
        return bool(self._items)
    
    def __iter__(self): #позволяет делать for tag in BSItems:
        return iter(self._items)
    
    def __len__(self):
        return len(self._items)
    
    def __truediv__(self, other): # оператор / ищет один элемент в каждом элементе
        if not self: # пустой элемент так и останется пустым
            return self
        if isinstance(other, str): # item / 'tag.classname'
            tag, _, cls = other.partition('.')
            if cls:
                return BSItems([item.find(tag, class_=cls) for item in self._items])
            else:
                return BSItem([item.find(tag) for item in self._items])
        if isinstance(other, int): # items / 2 найдет третий элемент в коллекции
            return BSItem(self._items[other]) if len(self._items) > other else BSItem(None)
        if callable(other): # items / lambda tag: tag.has_attr('id')
            return BSItems([item.find(other) for item in self._items])
        raise ValueError() # передали ерунду
    
    def __floordiv__(self, other): # оператор // ищет все элементы
        if not self:
            return self
        if isinstance(other, str): # item // 'tag.classname'
            tag, _, cls = other.partition('.')
            result = []
            for item in self._items:
                result.extend(item.find_all(tag, class_=cls) if cls else item.find_all(tag))
            return BSItems(result)
        if callable(other): # item // lambda tag: tag.has_attr('id')
            result = []
            for item in self._items:
                result.extend(item.find_all(other))
            return BSItems(result)
        raise ValueError()


За точность кода не ручаюсь, но идею должен передать.
Пример использования будет примерно такой:
year_tag = BSItem(soup) / 'li.CardInfoRow_year' // 'span.CardInfoRow__cell' / 1 / 'a.Link'
    year = str(year_tag) or '-'
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы