Подтвердить что ты не робот

Создать список словарей Python

Я хочу получить все iframe с веб-страницы.

Код:

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)

результат 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'}

результат 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'}]

Почему значение содержимого не правильно? Он должен быть таким же, как значение, когда я print(info).

4b9b3361

Ответ 1

Вы не создаете отдельный словарь для каждого iframe, вы просто продолжаете изменять один и тот же словарь много раз, и вы продолжаете добавлять дополнительные ссылки на этот словарь в своем списке.

Помните, что когда вы делаете что-то вроде content.append(info), вы не делаете копию данных, вы просто добавляете ссылку на данные.

Вам нужно создать новый словарь для каждого iframe.

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

Еще лучше, вам не нужно сначала создавать пустой словарь. Просто создайте все сразу:

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

Существуют и другие способы достижения этой цели, такие как итерация по списку атрибутов или использование переходов по спискам или словарю, но трудно улучшить ясность приведенного выше кода.

Ответ 2

Вы неправильно поняли объект Python list. Он похож на C pointer-array. Он фактически не "копирует" объект, который вы добавляете к нему. Вместо этого он просто сохраняет "указатель" на этот объект.

Попробуйте использовать следующий код:

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

Итак, почему print(dlist) не совпадает с print(d)?

В следующем коде показана причина:

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

Итак, вы можете видеть, что все элементы в dlist фактически указывают на тот же объект dict.

Настоящим ответом на этот вопрос будет добавление "копии" целевого элемента с помощью 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}]

Попробуйте трюк id(), вы можете видеть, что элементы списка фактически указывают на совершенно разные объекты.

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

Ответ 3

Если вам нужна одна строка:

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

Ответ 4

info - указатель на словарь - вы продолжаете добавлять тот же указатель в свой список contact.

Вставьте info = {} в цикл и он должен решить проблему:

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