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'
4 Réponses :
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)
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 '
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)
@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.
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')])
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