1
votes

Remplir la valeur avec Beautifulsoup lorsque la balise est vide

J'essaie d'analyser le contenu de toutes les balises td d'une certaine classe dans une page Web, mais je souhaite avoir un contenu d'espace réservé, même si la balise elle-même n'en a pas. Par exemple, le html contient des balises td comme ceci:

soup.find_all('td', attrs={'class': 'odds bdevtt moneylineodds '})

J'essaie d'obtenir une liste comme ['+134', '-', '-140'] en sortie, donc le nombre d'entrées dans la liste est égal au nombre de balises correspondantes avec '-' comme espace réservé indiquant que la balise était vide. Cependant, ce qui suit ne renvoie que ['+134', '- 140'].

<td class="odds bdevtt moneylineodds " cfg="">+134</td>
<td class="odds bdevtt moneylineodds " cfg=""></td>
<td class="odds bdevtt moneylineodds " cfg="">-140</td>


0 commentaires

3 Réponses :


0
votes
from bs4 import BeautifulSoup

html = """
<td class="odds bdevtt moneylineodds " cfg="">+134</td>
<td class="odds bdevtt moneylineodds " cfg=""></td>
<td class="odds bdevtt moneylineodds " cfg="">-140</td>
"""
soup = BeautifulSoup(html,"html.parser")
all = [i.text if i.text != "" else "-" for i in soup.find_all('td', attrs={'class': 'odds bdevtt moneylineodds '})]
print(all)

# output: ['+134', '-', '-140']

0 commentaires

0
votes

Supprimez l'espace de fin de la valeur de l'attribut class et vous obtiendrez le résultat attendu.

Code:

<td cfg="" class="odds bdevtt moneylineodds">+134</td>
<td cfg="" class="odds bdevtt moneylineodds"></td>
<td cfg="" class="odds bdevtt moneylineodds">-140</td>


0 commentaires

1
votes

Une solution possible est d'utiliser l'opérateur ou :

0.7735823660041206
0.8084569670027122
0.776867889042478

Imprime:

txt = '''<td class="odds bdevtt moneylineodds " cfg="">+134</td>
<td class="odds bdevtt moneylineodds " cfg=""></td>
<td class="odds bdevtt moneylineodds " cfg="">-140</td>'''
​
from bs4 import BeautifulSoup
from timeit import timeit
​
soup = BeautifulSoup(txt, 'html.parser')
​
def using_or():
    return [td.get_text(strip=True) or '-' for td in soup.select('td.odds.bdevtt.moneylineodds')]
​
def using_if_else_1():
    return [td.text if td.text else '-' for td in soup.select('td.odds.bdevtt.moneylineodds')]
​
def using_if_else_2():
    return [t if (t := td.get_text(strip=True)) else '-' for td in soup.select('td.odds.bdevtt.moneylineodds')]
​
​
t1 = timeit(lambda: using_or(), number=10_000)
t2 = timeit(lambda: using_if_else_1(), number=10_000)
t3 = timeit(lambda: using_if_else_2(), number=10_000)
​
print(t1)
print(t2)
print(t3)
​

Certains benchmark rapide:

['+134', '-', '-140']

Ceci imprime:

out = [td.get_text(strip=True) or '-' for td in soup.select('td.odds.bdevtt.moneylineodds')]
print(out)

Comme il semble, les solutions sont +/- les mêmes performances.


3 commentaires

Intéressant. Savez-vous comment ou se compare à sinon en termes d'efficacité?


Merci d'avoir ajouté ça. Je me demande ce qui se passe avec 2 et 3. Peut-être même sur une plus grande taille de test.


@QHarr Je les laisse courir 1_000_000 fois chacun, et les résultats sont 78.19792580400826, 81.93139944702853, 79.0471791360178 , donc oui, la méthode ou a une avance légère . La méthode 2 est perdante car td.text est accédé 2 fois.