2012-07-15 25 views
20

Quiero obtener todos los iframe desde una página web.Crear lista de diccionario Python

Código:

site = "http://" + url 
f = urllib2.urlopen(site) 
web_content = f.read() 

soup = BeautifulSoup(web_content) 
info = {} 
content = [] 
for iframe in soup.find_all('iframe'): 
    info['src'] = iframe.get('src') 
    info['height'] = iframe.get('height') 
    info['width'] = iframe.get('width') 
    content.append(info) 
    print(info)  

pprint(content) 

resultado de print(info):

{'src': u'abc.com', 'width': u'0', 'height': u'0'} 
{'src': u'xyz.com', 'width': u'0', 'height': u'0'} 
{'src': u'http://www.detik.com', 'width': u'1000', 'height': u'600'} 

resultado de pprint(content):

[{'height': u'600', 'src': u'http://www.detik.com', 'width': u'1000'}, 
{'height': u'600', 'src': u'http://www.detik.com', 'width': u'1000'}, 
{'height': u'600', 'src': u'http://www.detik.com', 'width': u'1000'}] 

¿Por qué es el valor del contenido no está bien? Se supone que debe ser igual que el valor cuando I print(info).

Respuesta

43

No están creando un diccionario separado para cada marco flotante, que acaba de seguir modificando el mismo diccionario una y otra, y seguir añadiendo adicional referencias a ese diccionario en su lista.

Recuerde, cuando hace algo como content.append(info), no está haciendo una copia de los datos, simplemente está agregando una referencia a los datos.

Necesita crear un nuevo diccionario para cada iframe.

for iframe in soup.find_all('iframe'): 
    info = {} 
    ... 

Mejor aún, no es necesario crear primero un diccionario vacío. Basta con crear todo a la vez:

for iframe in soup.find_all('iframe'): 
    info = { 
     "src": iframe.get('src'), 
     "height": iframe.get('height'), 
     "width": iframe.get('width'), 
    } 
    content.append(info) 

Hay otras maneras de lograr esto, como se itera sobre una lista de atributos, o el uso de la lista o por comprensión del diccionario, pero es difícil de mejorar la claridad del código anterior .

+0

Gracias por breve explicación, este es mi primer código usando Python: D. Gracias también por su respuesta rápida – l1th1um

2

info es un puntero a un diccionario: sigue agregando el mismo puntero a su lista contact.

Insertar info = {} en el bucle y se debe resolver el problema:

... 
content = [] 
for iframe in soup.find_all('iframe'): 
    info = {} 
    info['src'] = iframe.get('src') 
    info['height'] = iframe.get('height') 
    info['width'] = iframe.get('width') 
... 
25

Ha malentendido el objeto Python list. Es similar a un C pointer-array. En realidad, no "copia" el objeto que le anexa. En cambio, solo almacena un "puntero" a ese objeto.

Prueba el siguiente código:

>>> d={} 
>>> dlist=[] 
>>> for i in xrange(0,3): 
    d['data']=i 
    dlist.append(d) 
    print(d) 

{'data': 0} 
{'data': 1} 
{'data': 2} 
>>> print(dlist) 
[{'data': 2}, {'data': 2}, {'data': 2}] 

¿Por qué es print(dlist) no es el mismo que print(d)?

El código siguiente muestra la razón:

>>> for i in dlist: 
    print "the list item point to object:", id(i) 

the list item point to object: 47472232 
the list item point to object: 47472232 
the list item point to object: 47472232 

para que pueda ver todos los elementos de la dlist apunta realmente a la misma dict objeto.

La verdadera respuesta a esta pregunta será adjuntar la "copia" del elemento de destino, utilizando d.copy().

>>> dlist=[] 
>>> for i in xrange(0,3): 
    d['data']=i 
    dlist.append(d.copy()) 
    print(d) 

{'data': 0} 
{'data': 1} 
{'data': 2} 
>>> print dlist 
[{'data': 0}, {'data': 1}, {'data': 2}] 

Prueba el truco id(), se puede ver los elementos de la lista en realidad apuntan a objetos completamente diferentes.

>>> for i in dlist: 
    print "the list item points to object:", id(i) 

the list item points to object: 33861576 
the list item points to object: 47472520 
the list item points to object: 47458120 
+1

Entonces ... ¿está abogando por que el usuario use el método '.copy()' en lugar de simplemente crear un nuevo diccionario en cada iteración? Creo que eso está mal en este caso específico. –

+0

En muchos casos, solo puede cambiar parte del elemento, en el aspecto de rendimiento y concisión, prefiero '.copy()'. En el aspecto de la educación, '.copy()' también proporciona un concepto más claro. – Wang

+2

Creo que '.copy()' solo tiene sentido cuando realmente quiere copiar algo. Si bien estoy de acuerdo en que en algunos casos puede querer cambiar solo una parte de un elemento, en el caso de esta pregunta en particular, creo que el OP claramente tenía la intención de crear un nuevo diccionario para cada iframe, en lugar de copiar y modificar.

3

Si desea una línea:

list_of_dict = [{} for i in range(list_len)] 
Cuestiones relacionadas