Упростите многократную попытку и за исключением цикла for

#python #beautifulsoup #try-catch

Вопрос:

У меня есть цикл в функции, которая удаляет мету бойца с хорошо известного сайта мма. Функция работает, однако мне нужно присвоить значение по умолчанию None, если какая-либо из переменных soup.find или soup.findall вызывает ошибку атрибута или индекса.

Я безуспешно пытался использовать эту функцию:

     def ex_handler(i):
        try:
            return i
        except (AttributeError, IndexError): 
            return None

last_name = ex_handler(soup.find('span', class_='fn').text.strip().split()[1])
 

Код:

 def get_fighter_meta(fighter_urls):
        """Scrapes meta from fighters page"""
        for counter, fighter_url in enumerate(fighter_urls, start=1):
            soup = get_soup(fighter_url)
    
            try:
                first_name = soup.find('span', class_='fn').text.strip().split()[0]
            except (AttributeError, IndexError):
                first_name = None
    
            # todo  try amp; except alternative to catch exceptions on all soup variables
            last_name = soup.find('span', class_='fn').text.strip().split()[1]
            full_name = f'{first_name} {last_name}'
            nickname = soup.find('span', class_='nickname').text.strip()
            image_url = f"https://www.xxxxxx.com/{soup.find('img', attrs={'itemprop': 'image'})['src']}"
    
            dob = soup.find('span', attrs={'itemprop': 'birthDate'}).text.strip()
    
            location = soup.find('span', class_='locality').text.strip()
            nationality = soup.find('strong', attrs={'itemprop': 'nationality'}).text.strip()
            association = soup.find('span', attrs={'itemprop': 'name'}).text.strip()
    
            height = soup.find('span', class_='item height').text.strip()[-9:-2]
            weight = soup.find('span', class_='item weight').text.strip()[-9:-2].strip()
            weight_class = soup.find('strong', class_='title').text.strip()
    
            win_loss_loop = [i.text.strip() for i in soup.find_all('span', class_='counter')]
    
            wins = win_loss_loop[0]
            losses = win_loss_loop[1]
    
            graph_tag_loop = [i.text.strip() for i in soup.find_all('span', class_='graph_tag')]
    
            win_ko = graph_tag_loop[0][:2].strip()
            win_submission = graph_tag_loop[1][:2].strip()
            win_decisions = graph_tag_loop[2][:2].strip()
    
            loss_ko = graph_tag_loop[3][0][:2].strip()
            loss_submission = graph_tag_loop[4][:2].strip()
            loss_decisions = graph_tag_loop[5][:2].strip()
    
            fighter_meta = {
                'First_name': first_name,
                'Last_name': last_name,
                'Full name': full_name,
                'Nickname': nickname,
                'Image_url': image_url,
                'Date_of_birth': dob,
                'Location': location,
                'Nationality': nationality,
                'Association': association,
                'Height': height,
                'Weight': weight,
                'Weight_class': weight_class,
                'Wins': wins,
                'Losses': losses,
                'Win_by_ko': win_ko,
                'Win_by_submission': win_submission,
                'Win_decision': win_decisions,
                'Loss_by_ko': loss_ko,
                'Loss_by_submission': loss_submission,
                'Loss_by_desision': loss_decisions
            }
            fighter_data.append(fighter_meta)
            print(f'Saving: {full_name}  - {counter} of {len(fighter_urls)}')
 

Спасибо вам за вашу помощь!

Ответ №1:

Аргументы функции вычисляются перед вызовом функции, поэтому вы не можете таким образом обнаружить ошибку в функции. Вам нужно передать функцию , которая вызывается ex_handler , чтобы вы могли использовать лямбду.

 def ex_handler(f):
    try:
        return f()
    except (AttributeError, IndexError): 
        return None

last_name = ex_handler(lambda: soup.find('span', class_='fn').text.strip().split()[1])
 

Комментарии:

1. Потрясающе, спасибо! будет ли этот метод наиболее эффективным при применении к нескольким переменным?

2. На практике я бы просто присвоил результат soup.find() переменной и использовал if оператор. Этот метод был бы более полезен, если бы было много вложенных выражений, которые необходимо протестировать.