2010-07-31 13 views

Respuesta

8

Piense sobre ello en "pasos". .. ya que algunos x es la raíz del subárbol que está considerando,

x.findAll(text='price') 

es la lista de todos los artículos de ese subárbol que contiene el texto 'price'. Los padres de esos artículos a continuación, por supuesto, serán los siguientes:

[t.parent for t in x.findAll(text='price')] 

y si sólo quiere mantener aquellos cuyas (etiqueta) "nombre" es 'th', entonces, por supuesto

[t.parent for t in x.findAll(text='price') if t.parent.name=='th'] 

y desea que el "próximos" hermanos de aquellos (pero sólo si son también 'th' s), por lo que

[t.parent.nextSibling for t in x.findAll(text='price') 
if t.parent.name=='th' and t.parent.nextSibling and t.parent.nextSibling.name=='th'] 

Aquí se ve el problema con el uso de una lista por comprensión: demasiada repetición, ya que no podemos asignar resultados intermedios a nombres simples. Vamos por lo tanto, de cambiar a un buen lazo viejo ...:

Editar: tolerancia añadido para una cadena de texto entre el padre th y el "siguiente hermano", así como la tolerancia para el último es un td lugar, por Comentario de OP.

for t in x.findAll(text='price'): 
    p = t.parent 
    if p.name != 'th': continue 
    ns = p.nextSibling 
    if ns and not ns.name: ns = ns.nextSibling 
    if not ns or ns.name not in ('td', 'th'): continue 
    print ns.string 

He añadido ns.string, que dará a los contenidos de la siguiente hermano si y sólo si son sólo de texto (no hay más etiquetas anidadas) -, por supuesto, en su lugar puede analizar más a fondo en este punto, depende de las necesidades de su aplicación! -). Del mismo modo, me imagino que no estarás haciendo solo print sino algo más inteligente, pero te doy la estructura.

Hablando de la estructura, el aviso de que dos veces utilizo if...: continue: esto reduce la anidación en comparación con la alternativa de invertir la condición if 's y sangría todas las siguientes declaraciones en el bucle - y 'piso es mejor que anidado' es uno de los koans en el Zen de Python (import this) en un aviso interactivo para verlos a todos y meditar ;-).

+0

gran respuesta alex, acabo de utilizar findAll hasta ahora y ahora siento que puedo atravesar el dom con este conocimiento, ¡vaya python! jeje – Blankman

+0

en el enlace 'if not ns or ns.name ...', si ns es None, entonces ns.name no? – Blankman

+0

en realidad mi HTML es como: precio $ 99.99 y p.nextSibling está vacío, intenté p.next y eso tampoco funciona. – Blankman

0

Con pyparsing, es fácil llegar a la mitad de algo de HTML para un patrón de etiqueta de la siguiente manera:

from pyparsing import makeHTMLTags, Combine, Word, nums 

th,thEnd = makeHTMLTags("TH") 
floatnum = Combine(Word(nums) + "." + Word(nums)) 
priceEntry = (th + "price" + thEnd + 
       th + "$" + floatnum("price") + thEnd) 

tokens,startloc,endloc = priceEntry.scanString(html).next() 

print tokens.price 

makeHTMLTags ayudante de Pyparsing devuelve un par de expresiones pyparsing, uno para la etiqueta de inicio y otro para la etiqueta final El patrón de etiqueta de inicio es mucho más que simplemente agregar "<>" alrededor de la cadena dada, pero también permite espacios en blanco adicionales, mayúsculas y minúsculas, y la presencia o ausencia de atributos de etiquetas. Por ejemplo, tenga en cuenta que aunque he especificado "TH" como la etiqueta de cabecera de tabla, también coincidirá con "th", "Th", "tH" y "TH". El comportamiento de omisión del espacio en blanco predeterminado de Pyparsing también manejará espacios adicionales, entre la etiqueta y "$", entre "$" y el precio numérico, etc., sin tener que rociar "cero o más caracteres en el espacio en blanco podría ir aquí". Por último, al asignar el nombre del resultado "precio" (después de floatum en la definición de priceEntry), es muy simple acceder a ese valor específico de la lista completa de tokens que coinciden con la expresión general priceEntry.

(combinar se utiliza para 2 propósitos: no permite espacios en blanco entre los componentes del número, y devuelve un solo contador combinado "99.99" en lugar de la lista ["99", ".", "99"].)

Cuestiones relacionadas