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>
3 Réponses :
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']
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>
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.
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.