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">)

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>

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")

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})

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"]')

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>]

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]')

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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.