2012-06-06 28 views
5

Estoy trabajando en un proyecto en el que necesito un poco de raspado. El proyecto está en Google App Engine, y actualmente estamos usando Python 2.5. Idealmente, usaríamos PyQuery pero debido a la ejecución en App Engine y Python 2.5, esta no es una opción.¿Cómo puedo emular ": contiene" usando BeautifulSoup?

He visto preguntas como esta en finding an HTML tag with certain text, pero no dan en el clavo.

tengo algo de HTML que tiene este aspecto:

<div class="post"> 
    <div class="description"> 
     This post is about <a href="http://www.wikipedia.org">Wikipedia.org</a> 
    </div> 
</div> 
<!-- More posts of similar format --> 

En PyQuery, podría hacer algo como esto (por lo que yo sé):

s = pq(html) 
s(".post:contains('This post is about Wikipedia.org')") 
# returns all posts containing that text 

Ingenuamente, tenía sin embargo que Podría hacer algo como esto en BeautifulSoup:

soup = BeautifulSoup(html) 
soup.findAll(True, "post", text=("This post is about Google.com")) 
# [] 

Sin embargo, eso no dio ningún resultado. He cambiado de consulta para utilizar una expresión regular, y dieron un poco más lejos, pero aún ninguna suerte:

soup.findAll(True, "post", text=re.compile(".*This post is about.*Google.com.*")) 
# [] 

funciona si omito Google.com, pero luego tengo que hacer todo el filtrado de forma manual. ¿Hay alguna forma de emular :contains usando BeautifulSoup?

Alternativamente, ¿hay alguna biblioteca similar a PyQuery que funcione en App Engine (en Python 2.5)?

+0

¿Por qué no migrar a 2.7 donde [lxml está disponible] (https://developers.google.com/appengine/docs/python/python27/newin27#Supported_Third-Party_Libraries)? – schlamar

+0

Definitivamente queremos, simplemente no hemos podido todavía. Antigua base de código, falta de tiempo, etc. Es una crítica justa. – NT3RP

+0

Bueno, la [migración] (https://developers.google.com/appengine/docs/python/python27/using27#Considerations_When_Migrating_Your_Application) no parece demasiado compleja y, como sus aplicaciones tienen versiones, puede intentarlo y retroceder. si no está funcionando. – schlamar

Respuesta

5

De los documentos BeautifulSoup (el énfasis es mío):

"texto es un argumento que le permite buscar NavigableString objetos en lugar de Etiquetas"

es decir, su código:

soup.findAll(True, "post", text=re.compile(".*This post is about.*Google.com.*")) 

no es lo mismo que:

regex = re.compile('.*This post is about.*Google.com.*') 
[post for post in soup.findAll(True, 'post') if regex.match(post.text)] 

La razón por la que tiene que quitar el Google.com es que hay un objeto en el árbol NavigableString BeautifulSoup para "This post is about", y otro para "Google.com", pero están bajo diferentes elementos.

Por cierto, post.text existe pero no está documentado, así que tampoco me fiaría de eso, ¡escribí ese código por accidente! Utilice algún otro medio para agrupar todo el texto en post.

+1

Definitivamente, leí esa cita, pero no pude entender la diferencia. Esto es definitivamente lo que necesitaba. Gracias :) – NT3RP

+0

@ NT3RP "couldn 'no entiendo la diferencia': lo mismo para mí, la documentación de BeautifulSoup es IMO realmente un desastre. ;) – schlamar

Cuestiones relacionadas