0
votes

Beautifulsoup - obtenir tous les éléments li de ul où seul le premier li a un nom de classe spécifique

J'ai une liste non ordonnée comme celle-ci en HTML:

 carBasics = soup.select('li.label')

    for li in carBasics:
         if li.contents[0]=="Equipement":
            carAdditionalEquipement = (li.previousSibling).find_all('li')

Seul le premier élément li de la liste ul contient le titre de la liste , d'autres éléments contiennent la liste des fonctionnalités qui doivent être extraites en texte brut. Je sais comment localiser ce premier li mais je ne sais pas comment sélectionner tous les autres éléments.

Considérez que ce ul n'a pas class et ses dans le document HTML avec beaucoup d'autres éléments ul . Je peux localiser ce ul via li avec:

 (li.previousSibling).get_text() 

mais je ne peux pas extraire tous les éléments avec get_text () , j'obtiens:

AttributeError: l'objet 'NavigableString' n'a pas d'attribut 'get_text'

J'ai également besoin d'extraire tous les li sauf le premier qui contient le titre. J'ai plusieurs ul sur la page comme celle-ci et ils sont tous de longueur variable (ont plus ou moins d'éléments li ).

EDIT

Mon code pour l'instant. Je trouve des éléments avec:

<ul> 
<li class="label">Equipement</li>
<li>Aluminum tyres</li>
<li>4x4</li>
<li>3. stop lights</li>
<li>Bluetooth</li>
</ul>

AttributeError: l'objet 'NavigableString' n'a pas d'attribut 'get_text'


0 commentaires

4 Réponses :


1
votes
from bs4 import BeautifulSoup
import requests

html = requests.get(
    'yoururl')

soup = BeautifulSoup(html.content, 'html.parser')

for li in soup.select('ul li.labela'):
  if li.contents[0]=="Equipement":
    print(li.parent.text)

2 commentaires

Oui, je l'ai supprimé car je ne veux pas le publier. J'ai vu votre lien - vous avez extrait les titres correctement. J'ai besoin d'extraire tout ce qui se trouve sous ce titre, tous les éléments jusqu'à la fin de la liste sous forme de texte.


La majorité des articles n'ont qu'une valeur unique. Je n'ai aucun problème à obtenir cette valeur ou à obtenir seulement le 1er élément de la liste après le titre avec l'option nextSibling. Mais les 4-5 derniers articles ont plus d'articles li en dessous d'eux. Le meilleur exemple est b '

  • Dodatna oprema vozila
  • '



    1
    votes

    Utilisez find_next_siblings()

    import requests
    from bs4 import BeautifulSoup
    html = requests.get('https://www.index.hr/oglasi/bmw-serija-5-3-0-xd/oid/1971034')
    
    soup = BeautifulSoup(html.content, 'html.parser')
    
    for item in soup.select("ul li.labela"):
       if item.text=="Dodatna oprema vozila":
          siblings=[s.text for s in item.find_next_siblings('li')]
          print(siblings)
    

    A modifié la réponse:

    from bs4 import BeautifulSoup
    
    html='''<ul>
    <li class="label">Equipement</li>
    <li>Aluminum tyres</li>
    <li>4x4</li>
    <li>3. stop lights</li>
    <li>Bluetooth</li>
    </ul>
    <ul>
    <li class="label">Equipement</li>
    <li>Aluminum tyres</li>
    <li>4x4</li>
    <li>3. stop lights</li>
    <li>Bluetooth</li>
    </ul>'''
    soup = BeautifulSoup(html, 'lxml')
    for item in soup.select("ul li.label"):
        if item.text=="Equipement":
            siblings=[s.text for s in item.find_next_siblings('li')]
            print(siblings)
    


    1 commentaires

    @Harvey J'ai vérifié que votre code que vous aviez fournit le nom de classe label au lieu de labela . Cela fonctionne très bien.



    1
    votes

    Utilisez un combinateur général des frères et sœurs css et avec bs4 4.7.1+, vous pouvez utiliser: contains pour spécifier également le texte de l'étiquette s'il est connu

    from bs4 import BeautifulSoup as bs
    
    html = '''
    <ul> 
    <li class="label">Equipement</li>
    <li>Aluminum tyres</li>
    <li>4x4</li>
    <li>3. stop lights</li>
    <li>Bluetooth</li>
    </ul>
    '''
    soup = bs(html, 'lxml')
    print([li.text for li in soup.select('.label:contains("Equipement") ~ li')])
    


    0 commentaires

    0
    votes

    L'idée est d'omettre d'abord li . Personne n'a donné de réponse à cela, alors voici comment je l'ai fait à la fin:

    for item in soup.select("ul li.labela"):
       if item.text=="Equipement":
           carAdditionalEquipement = li.parent.text[len(li.contents[0])+1:].strip().splitlines()  
    

    À partir de là, j'obtiens une belle liste sans première ligne qui est retirée avec [len ( li.contents [0]) + 1:] .

    Fondamentalement, je coupe la longueur du premier élément de la liste de chaînes et je la divise car il y a un caractère de nouvelle ligne à la fin de chaque liste


    0 commentaires