Как добавить ключи и значения в dict в al oop? - PullRequest
0 голосов
/ 01 февраля 2020

Попытка создать дикт, который содержит имя, позицию и номер для каждого игрока для каждой команды. Но при попытке создать окончательный словарь players[team_name] =dict(zip(number,name,position)) выдает ошибку (см. Ниже). Кажется, я не могу понять это правильно, любые мысли о том, что я делаю неправильно, будут высоко оценены. Большое спасибо,

from bs4 import BeautifulSoup as soup
import requests
from lxml import html


clubs_url = 'https://www.premierleague.com/clubs'
parent_url = clubs_url.rsplit('/', 1)[0]
data = requests.get(clubs_url).text
html = soup(data, 'html.parser')

team_name = []
team_link = []

for ul in html.find_all('ul', {'class': 'block-list-5 block-list-3-m block-list-1-s block-list-1-xs block-list-padding dataContainer'}):
    for a in ul.find_all('a'):
        team_name.append(str(a.h4).split('>', 1)[1].split('<')[0])
        team_link.append(parent_url+a['href'])
team_link = [item.replace('overview', 'squad') for item in team_link]
team = dict(zip(team_name, team_link))

data = {}
players = {}

for team_name, team_link in team.items():
    player_page = requests.get(team_link)
    cont = soup(player_page.content, 'lxml')
    clud_ele = cont.find_all('span', attrs={'class' : 'playerCardInfo'})
    for i in clud_ele:
        v_number = [100 if v == "-" else v.get_text(strip=True) for v in i.select('span.number')]
        v_name = [v.get_text(strip=True) for v in i.select('h4.name')]
        v_position = [v.get_text(strip=True) for v in i.select('span.position')]
        key_number = [key for element in i.select('span.number') for key in element['class']]
        key_name = [key for element in i.select('h4.name') for key in element['class']]
        key_position = [key for element in i.select('span.position') for key in element['class']]
        number = dict(zip(key_number,v_number))
        name = dict(zip(key_name,v_name))
        position = dict(zip(key_position,v_name))
        players[team_name] = dict(zip(number,name,position))

---> 21         players[team_name] = dict(zip(number,name,position))
     22 
     23 

ValueError: dictionary update sequence element #0 has length 3; 2 is required

Ответы [ 2 ]

1 голос
/ 01 февраля 2020

В вашем коде много проблем. Причиной ошибки является то, что вы пытаетесь создать экземпляр словаря с набором из трех элементов в списке, что невозможно. См. the dict do c для деталей.


Тем не менее, я бы предложил переработать весь вложенный l oop.

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

for player_info in clud_ele:
    number = player_info.select('span.number')[0].get_text(strip=True)
    if number == '-':
        number = 100
    name = player_info.select('h4.name')[0].get_text(strip=True)
    position = player_info.select('span.position')[0].get_text(strip=True)

Здесь использование метода select возвращает список, но, поскольку вы знаете, что список содержит только один элемент, можно заставить этот предмет звонить get_text. Но вы можете проверить, что длина player_info.select('span.number') на самом деле равна 1, прежде чем продолжать работать, если хотите быть уверенным ...

Таким образом, вы получите скалярный тип данных, которым будет намного легче манипулировать. Также обратите внимание, что я переименовал i в player_info, что гораздо более явно.

Тогда вы можете легко добавить данные вашего игрока в ваш players dict:

players[team_name].append({'name': name,
                           'position': position
                           'number': number})

This предположим, что вы создаете players[team_name] перед вложенным l oop с помощью players[team_name] = [].

Редактировать: как указано в ответе @ kederra c , использование defaultdict - это разумный и удобный способ избежать ручного создания каждого players[team_name] списка

Наконец, это даст вам:

  • словарь содержит значения для name, position и number ключей для каждого игрока
  • список команд со словарями игроков для каждой команды
  • словарь игроков, связывающий список команд для каждого team_name

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

1 голос
/ 01 февраля 2020

вы не можете создать экземпляр dict с 3 аргументами, проблема в том, что у вас есть 3 переменные в zip: zip(number, name, position), для которых вы хотите создать экземпляр dict, вы должны дать только 2 аргумента за раз, ключ и значение

Я переписал вашу las часть кода:

from collections import defaultdict
data = {}
players = defaultdict(list)

for team_name, team_link in team.items():
    player_page = requests.get(team_link)
    cont = soup(player_page.text, 'lxml')
    clud_ele = cont.find_all('span', attrs={'class' : 'playerCardInfo'})
    for i in clud_ele:
        num = i.select('span.number')[0].get_text(strip=True)
        number = 100 if num == '-' else num
        name = i.select('h4.name')[0].get_text(strip=True)
        position = i.select('span.position')[0].get_text(strip=True)
        players[team_name].append({'number': number, 'position': position, 'name': name})

вывод:

defaultdict(list,
            {'Arsenal': [{'number': '1',
               'position': 'Goalkeeper',
               'name': 'Bernd Leno'},
              {'number': '26',
               'position': 'Goalkeeper',
               'name': 'Emiliano Martínez'},
              {'number': '33', 'position': 'Goalkeeper', 'name': 'Matt Macey'},
              {'number': '2',
               'position': 'Defender',
               'name': 'Héctor Bellerín'},
                 .......................
...