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.