2012-01-29 17 views
5

estoy usando el módulo BeautifulSoup para seleccionar todo href de html de esta manera:módulo de Python BeautifulSoup anclas extracción href

def extract_links(html): 
    soup = BeautifulSoup(html) 
    anchors = soup.findAll('a') 
    print anchors 
    links = [] 
    for a in anchors: 
    links.append(a['href']) 
    return links 

pero en algún momento se fallido de este mensaje de error:

Traceback (most recent call last): 
File "C:\py\main.py", line 33, in <module> 
urls = extract_links(page) 
File "C:\py\main.py", line 11, in extract_links 
links.append(a['href']) 
File "C:\py\BeautifulSoup.py", line 601, in __getitem__ 
return self._getAttrMap()[key] 
KeyError: 'href' 

Respuesta

5

No todos anclaje las etiquetas tendrán un atributo href. Debería verificar que el anclaje tenga un href antes de intentar acceder a ese atributo.

if a.has_key('href') 
    links.append(a['href']) 

Después de comprobar algunos comentarios aquí, creo que esta es la manera más Pythonic de manejar este caso.

+0

Gracias, pero ahora IR devolver este mensaje de error: Rastreo (llamada más reciente pasado): archivo "C: \ py \ principal .py ", línea 34, en urls = extract_links (página) Archivo" C: \ py \ main.py ", línea 11, en extract_links si 'href' en a.keys(): TypeError: ' NoneType 'object no se puede llamar – Michal

+0

@micheal Está colocando etiquetas 'a' en su diccionario que no tienen atributos' href'. En lugar de pedirle al diccionario que arroje etiquetas que pueden o no dar un atributo 'href', pregúntele a los datos si lo hace * antes * de ponerlo en el diccionario. – Droogans

+0

Creo que el nuevo error se debe a que un nodo BeautifulSoup no es un diccionario, por lo que 'keys' no es lo que esperas. –

0

forma en que el Pythonic sería algo como esto:

for a in anchors: 
    try: 
     links.append(a['href']) 
    except KeyError: 
     pass 

Eso simplemente omite cualquier <a> etiquetas sin un href.

+1

Creo que 'has_key()' es más pitónico que el uso de errores para la lógica, pero las personas parecen estar en desacuerdo sobre eso en la comunidad. –

+0

@MattLuongo: depende de lo que estés haciendo. Siento que se expresa mejor como "obtener la dirección de cada enlace, y si no tiene un enlace, no importa", en lugar de "verificar si cada enlace tiene una dirección, y si lo hace, obtener eso". No ayuda que 'has_key' esté en desuso para los diccionarios, pero' in' no hace lo mismo para los nodos BS. –

+0

Supongo que es por eso que 'Tag' no es un descendiente de' dict'. De todos modos, la desaprobación no es demasiado relevante por esa razón. –

2

Pruebe esto.

links = [a['href'] for a in anchors if a.has_key('href')] 

O, si prefiere mutar una lista existente

links = [] 
#... 
links.extend(a['href'] for a in anchors if a.has_key('href')) 
+0

Bonito delineador. – tjarratt

+0

O, como los documentos lo prefieren, 'if 'href' en a' :) – Gabriel

+0

@Gabriel los documentos pueden preferirlo, pero considere esto. 's = BeautifulSoup (' href'); 'href' en s.findAll ('a') [0] 'evalúa como' True'. 'has_key' no tiene fugas de esa manera. –

0

, es necesario especificar a.attrs a un dict primero, y luego acceder al elemento.

links.append(dict(a.attrs)['href']) 
+0

Erm, creo que te refieres a 'links.append (dict (a.attrs) ['href'])' ..? Pero eso no maneja el caso donde hay etiquetas con 'href's. –

+0

¿Quiere decir * sin * 'href's? Entonces estás en lo correcto. Mi experiencia personal muestra que necesito lanzar. – 0605002

+0

Ha, * sin, gracias. Solo quise decir que el código anterior no arroja 'a.attrs' a un' dict', sino que convierte 'a.attrs ['href']' en 'dict', lo que genera un' TypeError'. –

2

soup.findAll() devuelve una lista de "etiquetas", que contienen los diccionarios de atributos. Entonces necesita extraer sus atributos y trabajar en ellos.

Tomando su ejemplo y modificación, este es el código que funciona:

def extract_links(html): 
    soup = BeautifulSoup(html) 
    anchors = soup.findAll('a') 
    print anchors 
    links = [] 
    for a in anchors: 
    if a.attrs.has_key('href'): 
     links.append(a['href']) 
return links 
Cuestiones relacionadas