2010-10-21 13 views
1

Je suit le code python:Beautiful Soup: Obtenez le contenu des sous-noeuds

def scrapeSite(urlToCheck): 
    html = urllib2.urlopen(urlToCheck).read() 
    from BeautifulSoup import BeautifulSoup 
    soup = BeautifulSoup(html) 
    tdtags = soup.findAll('td', { "class" : "c" }) 
    for t in tdtags: 
      print t.encode('latin1') 

Cela me retourner suivant le code html:

<td class="c"> 
<a href="more.asp">FOO</a> 
</td> 
<td class="c"> 
<a href="alotmore.asp">BAR</a> 
</td> 

J'aimerais obtenir le texte entre le a-Node (par exemple FOO ou BAR), qui serait t.contents.contents. Malheureusement, cela ne fonctionne pas si facilement :) Quelqu'un at-il une idée de comment résoudre ce problème?

Merci beaucoup, toute aide est appréciée!

Cheers, Joseph

Répondre

3

Dans ce cas, vous pouvez utiliser t.contents[1].contents[0] pour obtenir FOO et BAR.

La chose est que le contenu retourne une liste avec tous les éléments (balises et NavigableStrings), si vous imprimez contenu, vous pouvez le voir est quelque chose comme

[u'\n', <a href="more.asp">FOO</a>, u'\n']

Alors, pour se rendre à l'étiquette réelle vous besoin d'accéder contents[1] (si vous avez exactement le même contenu, cela peut varier en fonction de la source HTML), après avoir trouvé l'index approprié, vous pouvez utiliser contents[0] ensuite pour obtenir la chaîne à l'intérieur de la balise a. Maintenant, comme cela dépend du contenu exact de la source HTML, c'est très fragile. Une solution plus générique et robuste serait d'utiliser find() à nouveau pour trouver la balise «a», via t.find('a') et ensuite utiliser la liste de contenu pour obtenir les valeurs dans t.find('a').contents[0] ou simplement t.find('a').contents pour obtenir la liste entière.

+0

Non cela ne fonctionne pas, ceci est le message d'erreur: AttributeError: objet 'NavigableString' n'a aucun attribut 'contenu' –

+0

@Joseph: J'ai testé cela et cela fonctionne sur BeautifulSoup 3.0.4, Python 2.5 .. Si cela ne fonctionne pas pour vous, vous pouvez avoir des contenus différents dans la liste du contenu réel. J'ai modifié la réponse avec une solution plus générique. –

+0

Le t.find ('a'). Contents [0] -part a fait l'affaire :) Merci beaucoup –

1

Pour votre exemple précis, les makeHTMLTags de pyparsing peuvent être utiles, car ils tolèrent beaucoup variabilités HTML dans les balises HTML, mais fournissent une structure pratique pour les résultats:

html = """ 
<td class="c"> 
<a href="more.asp">FOO</a> 
</td> 
<td class="c"> 
<a href="alotmore.asp">BAR</a> 
</td> 
<td class="d"> 
<a href="alotmore.asp">BAZZ</a> 
</td> 
""" 

from pyparsing import * 

td,tdEnd = makeHTMLTags("td") 
a,aEnd = makeHTMLTags("a") 
td.setParseAction(withAttribute(**{"class":"c"})) 

pattern = td + a("anchor") + SkipTo(aEnd)("aBody") + aEnd + tdEnd 

for t,_,_ in pattern.scanString(html): 
    print t.aBody, '->', t.anchor.href 

imprime:

FOO -> more.asp 
BAR -> alotmore.asp 
+0

Merci pour votre solution! Je n'avais pas encore utilisé de pypars, mais je vais certainement vérifier pour les problèmes futurs. –