2009-06-09 8 views
2

Je voudrais savoir comment récupérer tous les résultats de chaque balise <p>.Python expression régulière pour plusieurs balises

import re 
htmlText = '<p data="5" size="4">item1</p><p size="4">item2</p><p size="4">item3</p>' 
print re.match('<p[^>]*size="[0-9]">(.*?)</p>', htmlText).groups() 

Résultat:

('item1',) 

ce que je dois:

('item1', 'item2', 'item3') 
+0

-1 pour essayer d'analyser des langues non régulières avec des expressions régulières. – Svante

+0

est d'accord, n'y at-il pas une bibliothèque python, qui est célèbre pour l'analyse de HTML? BeautifulSoup? htmllib? – DevelopingChris

+0

Merci pour votre réponse. J'avais besoin d'un moyen python pour imprimer toutes les valeurs des balises p à partir d'un petit HTML sans rien installer de nouveau sur le serveur. –

Répondre

4

La réponse est regex extrêmement fragile. Voici une preuve (et un exemple BeautifulSoup en cours de fonctionnement).

from BeautifulSoup import BeautifulSoup 

# Here's your HTML 
html = '<p data="5" size="4">item1</p><p size="4">item2</p><p size="4">item3</p>' 

# Here's some simple HTML that breaks your accepted 
# answer, but doesn't break BeautifulSoup. 
# For each example, the regex will ignore the first <p> tag. 
html2 = '<p size="4" data="5">item1</p><p size="4">item2</p><p size="4">item3</p>' 
html3 = '<p data="5" size="4" >item1</p><p size="4">item2</p><p size="4">item3</p>' 
html4 = '<p data="5" size="12">item1</p><p size="4">item2</p><p size="4">item3</p>' 

# This BeautifulSoup code works for all the examples. 
paragraphs = BeautifulSoup(html).findAll('p') 
items = [''.join(p.findAll(text=True)) for p in paragraphs] 

Utilisez BeautifulSoup.

+0

Je ne pense pas que vous devez importer re. En outre, je suis curieux de savoir ce que votre exemple fournit que le mien n'est autre que la compréhension de la liste. –

+0

Brett - le mien va gérer correctement les cas comme

item1

, alors que le vôtre va échouer. En outre, le tableau d'éléments ici sera converti en une liste de chaînes, alors que votre exemple retournera tag.contents, qui est en fait un objet BeautifulSoup (très affamé de mémoire). – Triptych

+0

Cool! Je ne savais pas que l'objet consommait beaucoup de mémoire, je l'ai seulement utilisé sur de petits projets d'analyse et je n'ai jamais rencontré de problèmes. Merci pour la mise à jour. J'ai voté le vôtre en fonction de votre explication. –

2

Vous pouvez utiliser re.findall comme ceci:

import re 
html = '<p data="5" size="4">item1</p><p size="4">item2</p><p size="4">item3</p>' 
print re.findall('<p[^>]*size="[0-9]">(.*?)</p>', html) 
# This prints: ['item1', 'item2', 'item3'] 

Modifier: ... mais la de nombreux commentateurs ont souligné, en utilisant des expressions régulières pour analyser HTML est généralement une mauvaise idée.

+0

Merci! Je viens de le trouver sur des docs Python! http://docs.python.org/dev/howto/regex.html –

+2

Je suis désolé mais c'est une réponse affreuse. Que faire s'il existe un espace entre l'attribut size et la parenthèse de fermeture:

? – Triptych

+1

@Triptych: Il n'y en a pas. Avez-vous envisagé la possibilité que l'OP sache ce qu'il fait? 8-) Si la question avait été "Comment puis-je analyser ce code HTML?" alors je n'aurais pas suggéré une expression régulière. Mais c'était "Comment faire fonctionner mon expression régulière?", Et c'est une réponse à cette question. – RichieHindle

11

Pour ce type de problème, il est recommandé d'utiliser un analyseur DOM, non regex.

Je l'ai vu Beautiful Soup souvent recommandé pour Python

2

Alternativement, xml.dom.minidom analysera votre HTML si,

  • ... il est wellformed
  • ... vous intégrez dans un seul élément racine.

Par ex,

>>> import xml.dom.minidom 
>>> htmlText = '<p data="5" size="4">item1</p><p size="4">item2</p><p size="4">item3</p>' 
>>> d = xml.dom.minidom.parseString('<not_p>%s</not_p>' % htmlText) 
>>> tuple(map(lambda e: e.firstChild.wholeText, d.firstChild.childNodes)) 
('item1', 'item2', 'item3') 
5

soupe Belle est certainement la voie à suivre avec un problème comme celui-ci. Le code est plus propre et plus facile à lire. Une fois que vous l'avez installé, obtenir tous les tags ressemble à ceci.

from BeautifulSoup import BeautifulSoup 
import urllib2 

def getTags(tag): 
    f = urllib2.urlopen("http://cnn.com") 
    soup = BeautifulSoup(f.read()) 
    return soup.findAll(tag) 


if __name__ == '__main__': 
    tags = getTags('p') 
    for tag in tags: print(tag.contents) 

Ceci affichera toutes les valeurs des points p.

+0

Merci pour votre réponse. J'avais juste besoin d'un moyen python pour imprimer toutes les valeurs des balises p sans rien installer de nouveau sur le serveur. –

Questions connexes