web-dev-qa-db-fra.com

Python + BeautifulSoup: Comment obtenir l'attribut "href" d'un élément "a"?

J'ai les éléments suivants:

  html =
  '''<div class=“file-one”>
    <a href=“/file-one/additional” class=“file-link">
      <h3 class=“file-name”>File One</h3>
    </a>
    <div class=“location”>
      Down
    </div>
  </div>'''

Et j'aimerais obtenir juste le texte de href qui est /file-one/additional. J'ai donc fait:

from bs4 import BeautifulSoup

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

link_text = “”

for a in soup.find_all(‘a’, href=True, text=True):
    link_text = a[‘href’]

print “Link: “ + link_text

Mais il imprime juste un blanc, rien. Juste Link:. Je l'ai donc testé sur un autre site mais avec un HTML différent, et cela a fonctionné.

Que pourrais-je faire de mal? Ou existe-t-il une possibilité que le site soit programmé pour ne pas renvoyer le href?

Merci à l'avance et assurez-vous de voter/accepter la réponse!

9
user3259472

La balise "a" dans votre html n'a pas de texte directement, mais elle contient une balise "h3" qui contient du texte. Cela signifie que text est None, et .find_all() ne parvient pas à sélectionner la balise. N'utilisez généralement pas le paramètre text si une balise contient d'autres éléments html à l'exception du contenu texte.

Vous pouvez résoudre ce problème si vous utilisez uniquement le nom de la balise (et l'argument de mot clé href) pour sélectionner des éléments. Ajoutez ensuite une condition dans la boucle pour vérifier si elles contiennent du texte.

soup = BeautifulSoup(html, 'html.parser')
links_with_text = []
for a in soup.find_all('a', href=True): 
    if a.text: 
        links_with_text.append(a['href'])

Ou vous pouvez utiliser une compréhension de liste, si vous préférez les lignes simples.

links_with_text = [a['href'] for a in soup.find_all('a', href=True) if a.text]

Ou vous pouvez passer un lambda à .find_all().

tags = soup.find_all(lambda tag: tag.name == 'a' and tag.get('href') and tag.text)

Si vous souhaitez collecter tous les liens, qu'ils aient du texte ou non, sélectionnez simplement toutes les balises 'a' qui ont un attribut 'href'. Les balises d'ancrage ont généralement des liens mais ce n'est pas une exigence, donc je pense qu'il est préférable d'utiliser l'argument href.

Utilisation de .find_all().

links = [a['href'] for a in soup.find_all('a', href=True)]

Utilisation de .select() avec des sélecteurs CSS.

links = [a['href'] for a in soup.select('a[href]')]
16
t.m.adam
  1. Tout d'abord, utilisez un éditeur de texte différent qui n'utilise pas de guillemets bouclés.

  2. Ensuite, supprimez le text=True drapeau du soup.find_all

4

Vous pouvez également utiliser attrs pour obtenir la balise href avec la recherche d'expression régulière

soup.find('a', href = re.compile(r'[/]([a-z]|[A-Z])\w+')).attrs['href']
3
Rakshit Vats