Cómo encontrar etiquetas con solo ciertos atributos - BeautifulSoup

84

¿Cómo podría, usando BeautifulSoup, buscar etiquetas que contengan SOLO los atributos que busco?

Por ejemplo, quiero encontrar todas las <td valign="top">etiquetas.

El siguiente código: raw_card_data = soup.fetch('td', {'valign':re.compile('top')})

obtiene todos los datos que quiero, pero también toma cualquier <td>etiqueta que tenga el atributovalign:top

También lo intenté: raw_card_data = soup.findAll(re.compile('<td valign="top">')) y esto no devuelve nada (probablemente debido a una expresión regular incorrecta)

Me preguntaba si en BeautifulSoup había alguna forma de decir "Buscar <td>etiquetas cuyo único atributo sea valign:top"

ACTUALIZAR Por ejemplo, si un documento HTML contiene las siguientes <td>etiquetas:

<td valign="top">.....</td><br />
<td width="580" valign="top">.......</td><br />
<td>.....</td><br />

Me gustaría que solo regresara la primera <td>etiqueta ( <td width="580" valign="top">)

Snaxib
fuente

Respuestas:

96

Como se explica en la documentación de BeutifulSoup

Puedes usar esto:

soup = BeautifulSoup(html)
results = soup.findAll("td", {"valign" : "top"})

EDITAR:

Para devolver etiquetas que solo tienen el atributo valign = "top", puede verificar la longitud de la attrspropiedad de la etiqueta :

from BeautifulSoup import BeautifulSoup

html = '<td valign="top">.....</td>\
        <td width="580" valign="top">.......</td>\
        <td>.....</td>'

soup = BeautifulSoup(html)
results = soup.findAll("td", {"valign" : "top"})

for result in results :
    if len(result.attrs) == 1 :
        print result

Que regresa:

<td valign="top">.....</td>
Loïc G.
fuente
Según mi comentario a julio.alegria, esto encontrará todas las <tr>etiquetas con el atributo valign="top", incluidas las que tienen otros atributos ( <td width="580" valign="top">también se devuelve en esta búsqueda) Estoy buscando un método para encontrar <tr>etiquetas cuyo único atributo seavalign="top"
Snaxib
Entonces, puede verificar len (tag.attrs). Si len (tag.attrs)> 1, ignore la etiqueta (he editado mi publicación)
Loïc G.
51

Puede utilizar lambdafunciones findAllcomo se explica en la documentación . De modo que, en su caso, busque una tdetiqueta con solo valign = "top"usar lo siguiente:

td_tag_list = soup.findAll(
                lambda tag:tag.name == "td" and
                len(tag.attrs) == 1 and
                tag["valign"] == "top")
Yogesh
fuente
4
la mejor respuesta ya que utiliza todo el poder de BS
Rafael T
2
Gran respuesta porque te da un resultado de una manera muy optimizada.
CrazyGeek
32

si solo desea buscar con nombre de atributo con cualquier valor

from bs4 import BeautifulSoup
import re

soup= BeautifulSoup(html.text,'lxml')
results = soup.findAll("td", {"valign" : re.compile(r".*")})

según Steve Lorimer, es mejor pasar True en lugar de regex

results = soup.findAll("td", {"valign" : True})
Amr
fuente
2
Le falta un paréntesis después r".*", lo que hace que no se compile.
Jack Cole
9
No se necesita una expresión regular, solo pase True:results = soup.findAll("td", {"valign" : True})
Steve Lorimer
14

La forma más sencilla de hacerlo es con el nuevo selectmétodo de estilo CSS :

soup = BeautifulSoup(html)
results = soup.select('td[valign="top"]')
Chris Redford
fuente
4

Simplemente páselo como un argumento de findAll:

>>> from BeautifulSoup import BeautifulSoup
>>> soup = BeautifulSoup("""
... <html>
... <head><title>My Title!</title></head>
... <body><table>
... <tr><td>First!</td>
... <td valign="top">Second!</td></tr>
... </table></body><html>
... """)
>>>
>>> soup.findAll('td')
[<td>First!</td>, <td valign="top">Second!</td>]
>>>
>>> soup.findAll('td', valign='top')
[<td valign="top">Second!</td>]
juliomalegria
fuente
1
¿Qué pasa si hay etiquetas como estas <td width="580" valign="top">:? No quiero agarrar esas, solo etiquetas cuyo único atributo esvalign="top"
Snaxib
2

Al agregar una combinación de la respuesta de Chris Redford y Amr, también puede buscar un nombre de atributo con cualquier valor con el comando de selección:

from bs4 import BeautifulSoup as Soup
html = '<td valign="top">.....</td>\
    <td width="580" valign="top">.......</td>\
    <td>.....</td>'
soup = Soup(html, 'lxml')
results = soup.select('td[valign]')
PastoreoCientífico
fuente
He intentado de la misma manera, pero esto no funciona, ¿hay alguna solución?
Phaneendra Charyulu Kanduri
1
@PhaneendraCharyuluKanduri Lo sentimos, hubo un error de codificación en el código. ¡Ahora copiar y pegar debería funcionar!
GrazingScientist