Python Красивый Суп Веб-Соскабливание Массивов Transfermkt Не Одинаковой Длины

#python #web-scraping #beautifulsoup

Вопрос:

Я ищу, чтобы собрать данные для команд за несколько лет в разных странах из https://www.transfermarkt.com/premier-league/startseite/wettbewerb/GB1/plus/?saison_id=2019

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

Вот код, который у меня есть до сих пор:

 import pandas as pd
import numpy as np
import requests
import time
from bs4 import BeautifulSoup

import warnings
warnings.filterwarnings('ignore')

#create a dictionary for league and iterate over seasons
dct_GB1 = {}
dct_IT1 = {}
dct_ES1 = {}
dct_L1 = {}
dct_FR1 = {}
dct_PO1 = {}
dct_NL1 = {}
dct_TR1 = {}
dct_BE1 = {}
dct_UKR1 = {}
dct_A1 = {}
dct_GR1 = {}
dct_TS1 = {}
dct_SC1 = {}
dct_KR1 = {}
dct_C1 = {}
dct_PL1 = {}
dct_DK1 = {}
dct_ER1 = {}
dct_RO1 = {}
dct_SE1 = {}
dct_ZYP1 = {}
dct_NO1 = {}
dct_KAS1 = {}
dct_UNG1 = {}
dct_ISR1 = {}
dct_BU1 = {}
dct_WER1 = {}
dct_SLO1 = {}
dct_SL1 = {}
dct_AZ1 = {}
dct_BOS1 = {}
dct_MAL1 = {}
dct_ALB1 = {}
dct_MAZ1 = {}
dct_ARM1 = {}
dct_GE1N = {}
dct_FI1 = {}
dct_MO1N = {}
dct_LET1 = {}
dct_MNE1 = {}
dct_KO1 = {}
dct_LUX1 = {}
dct_LI1 = {}
dct_EST1 = {}
dct_IS1 = {}
dct_WAL1 = {}
dct_FARO = {}
dct_AND1 = {}
dct_IR1 = {}
dct_NIR1 = {}
dct_SMR1 = {}
dct_GI1 = {}
dct_GB2 = {}
dct_ES2 = {}
dct_IT2 = {}
dct_FR2 = {}
dct_L2 = {}
dct_NL2 = {}
dct_TR2 = {}
dct_PO2 = {}
dct_A2 = {}
dct_C2 = {}
dct_BE2 = {}
dct_GRS2 = {}
dct_RO2 = {}
dct_PL2 = {}
dct_UN2 = {}

for m in range(2007,2020):
    dct_GB1['df_GB1_%s' % m] = pd.DataFrame()
    dct_IT1['df_IT1_%s' % m] = pd.DataFrame()
    dct_ES1['df_ES1_%s' % m] = pd.DataFrame()
    dct_L1['df_L1_%s' % m] = pd.DataFrame()
    dct_FR1['df_FR1_%s' % m] = pd.DataFrame()
    dct_PO1['df_PO1_%s' % m] = pd.DataFrame()
    dct_NL1['df_NL1_%s' % m] = pd.DataFrame()
    dct_TR1['df_TR1_%s' % m] = pd.DataFrame()
    dct_BE1['df_BE1_%s' % m] = pd.DataFrame()
    dct_UKR1['df_UKR1_%s' % m] = pd.DataFrame()
    dct_A1['df_A1_%s' % m] = pd.DataFrame()
    dct_GR1['df_GR1_%s' % m] = pd.DataFrame()
    dct_TS1['df_TS1_%s' % m] = pd.DataFrame()
    dct_SC1['df_SC1_%s' % m] = pd.DataFrame()
    dct_KR1['df_KR1_%s' % m] = pd.DataFrame()
    dct_C1['df_C1_%s' % m] = pd.DataFrame()
    dct_PL1['df_PL1_%s' % m] = pd.DataFrame()
    dct_DK1['df_DK1_%s' % m] = pd.DataFrame()
    dct_ER1['df_ER1_%s' % m] = pd.DataFrame()
    dct_RO1['df_RO1_%s' % m] = pd.DataFrame()
    dct_SE1['df_SE1_%s' % m] = pd.DataFrame()
    dct_ZYP1['df_ZYP1_%s' % m] = pd.DataFrame()
    dct_NO1['df_NO1_%s' % m] = pd.DataFrame()
    dct_KAS1['df_KAS1_%s' % m] = pd.DataFrame()
    dct_UNG1['df_UNG1_%s' % m] = pd.DataFrame()
    dct_ISR1['df_ISR1_%s' % m] = pd.DataFrame()
    dct_BU1['df_BU1_%s' % m] = pd.DataFrame()
    dct_WER1['df_WER1_%s' % m] = pd.DataFrame()
    dct_SLO1['df_SLO1_%s' % m] = pd.DataFrame()
    dct_SL1['df_SL1_%s' % m] = pd.DataFrame()
    dct_AZ1['df_AZ1_%s' % m] = pd.DataFrame()
    dct_BOS1['df_BOS1_%s' % m] = pd.DataFrame()
    dct_MAL1['df_MAL1_%s' % m] = pd.DataFrame()
    dct_ALB1['df_ALB1_%s' % m] = pd.DataFrame()
    dct_MAZ1['df_MAZ1_%s' % m] = pd.DataFrame()
    dct_ARM1['df_ARM1_%s' % m] = pd.DataFrame()
    dct_GE1N['df_GE1N_%s' % m] = pd.DataFrame()
    dct_FI1['df_FI1_%s' % m] = pd.DataFrame()
    dct_MO1N['df_MO1N_%s' % m] = pd.DataFrame()
    dct_LET1['df_LET1_%s' % m] = pd.DataFrame()
    dct_MNE1['df_MNE1_%s' % m] = pd.DataFrame()
    dct_KO1['df_KO1_%s' % m] = pd.DataFrame()
    dct_LUX1['df_LUX1_%s' % m] = pd.DataFrame()
    dct_LI1['df_LI1_%s' % m] = pd.DataFrame()
    dct_EST1['df_EST1_%s' % m] = pd.DataFrame()
    dct_IS1['df_IS1_%s' % m] = pd.DataFrame()
    dct_WAL1['df_WAL1_%s' % m] = pd.DataFrame()
    dct_FARO['df_FARO_%s' % m] = pd.DataFrame()
    dct_AND1['df_AND1_%s' % m] = pd.DataFrame()
    dct_IR1['df_IR1_%s' % m] = pd.DataFrame()
    dct_NIR1['df_NIR1_%s' % m] = pd.DataFrame()
    dct_SMR1['df_SMR1_%s' % m] = pd.DataFrame()
    dct_GI1['df_GI1_%s' % m] = pd.DataFrame()
    dct_GB2['df_GB2_%s' % m] = pd.DataFrame()
    dct_ES2['df_ES2_%s' % m] = pd.DataFrame()
    dct_IT2['df_IT2_%s' % m] = pd.DataFrame()
    dct_FR2['df_FR2_%s' % m] = pd.DataFrame()
    dct_L2['df_L2_%s' % m] = pd.DataFrame()
    dct_NL2['df_NL2_%s' % m] = pd.DataFrame()
    dct_TR2['df_TR2_%s' % m] = pd.DataFrame()
    dct_PO2['df_PO2_%s' % m] = pd.DataFrame()
    dct_A2['df_A2_%s' % m] = pd.DataFrame()
    dct_C2['df_C2_%s' % m] = pd.DataFrame()
    dct_BE2['df_BE2_%s' % m] = pd.DataFrame()
    dct_GRS2['df_GRS2_%s' % m] = pd.DataFrame()
    dct_RO2['df_RO2_%s' % m] = pd.DataFrame()
    dct_PL2['df_PL2_%s' % m] = pd.DataFrame()
    dct_UN2['df_UN2_%s' % m] = pd.DataFrame()

#list of URL bases for each league
league_urls = (['https://www.transfermarkt.com/premier-league/startseite/wettbewerb/GB1/plus/?saison_id=', 
                'https://www.transfermarkt.com/serie-a/startseite/wettbewerb/IT1/plus/?saison_id=',
                'https://www.transfermarkt.com/laliga/startseite/wettbewerb/ES1/plus/?saison_id=',
                'https://www.transfermarkt.com/bundesliga/startseite/wettbewerb/L1/plus/?saison_id=',
                'https://www.transfermarkt.com/ligue-1/startseite/wettbewerb/FR1/plus/?saison_id=',
                'https://www.transfermarkt.com/liga-nos/startseite/wettbewerb/PO1/plus/?saison_id=',
                'https://www.transfermarkt.com/eredivisie/startseite/wettbewerb/NL1/plus/?saison_id=',
                'https://www.transfermarkt.com/super-lig/startseite/wettbewerb/TR1/plus/?saison_id=',
                'https://www.transfermarkt.com/jupiler-pro-league/startseite/wettbewerb/BE1/plus/?saison_id=',
                'https://www.transfermarkt.com/premier-liga/startseite/wettbewerb/UKR1/plus/?saison_id=',
                'https://www.transfermarkt.com/bundesliga/startseite/wettbewerb/A1/plus/?saison_id=',
                'https://www.transfermarkt.com/super-league-1/startseite/wettbewerb/GR1/plus/?saison_id=',
                'https://www.transfermarkt.com/fortuna-liga/startseite/wettbewerb/TS1/plus/?saison_id=',
                'https://www.transfermarkt.com/scottish-premiership/startseite/wettbewerb/SC1/plus/?saison_id=',
                'https://www.transfermarkt.com/1-hnl/startseite/wettbewerb/KR1/plus/?saison_id=',
                'https://www.transfermarkt.com/super-league/startseite/wettbewerb/C1/plus/?saison_id=',
                'https://www.transfermarkt.com/pko-ekstraklasa/startseite/wettbewerb/PL1/plus/?saison_id=',
                'https://www.transfermarkt.com/superligaen/startseite/wettbewerb/DK1/plus/?saison_id=',
                'https://www.transfermarkt.com/super-liga-srbije/startseite/wettbewerb/SER1/plus/?saison_id=',
                'https://www.transfermarkt.com/liga-1/startseite/wettbewerb/RO1/plus/?saison_id=',
                'https://www.transfermarkt.com/allsvenskan/startseite/wettbewerb/SE1/plus/?saison_id=',
                'https://www.transfermarkt.com/protathlima-cyta/startseite/wettbewerb/ZYP1/plus/?saison_id=',
                'https://www.transfermarkt.com/eliteserien/startseite/wettbewerb/NO1/plus/?saison_id=',
                'https://www.transfermarkt.com/premier-liga/startseite/wettbewerb/KAS1/plus/?saison_id=',
                'https://www.transfermarkt.com/nemzeti-bajnoksag/startseite/wettbewerb/UNG1/plus/?saison_id=',
                'https://www.transfermarkt.com/ligat-haal/startseite/wettbewerb/ISR1/plus/?saison_id=',
                'https://www.transfermarkt.com/efbet-liga/startseite/wettbewerb/BU1/plus/?saison_id=',
                'https://www.transfermarkt.com/vysheyshaya-liga/startseite/wettbewerb/WER1/plus/?saison_id=',
                'https://www.transfermarkt.com/fortuna-liga/startseite/wettbewerb/SLO1/plus/?saison_id=',
                'https://www.transfermarkt.com/prva-liga/startseite/wettbewerb/SL1/plus/?saison_id=',
                'https://www.transfermarkt.com/premyer-liqa/startseite/wettbewerb/AZ1/plus/?saison_id=',
                'https://www.transfermarkt.com/premijer-liga/startseite/wettbewerb/BOS1/plus/?saison_id=',
                'https://www.transfermarkt.com/premier-league/startseite/wettbewerb/MAL1/plus/?saison_id=',
                'https://www.transfermarkt.com/kategoria-superiore/startseite/wettbewerb/ALB1/plus/?saison_id=',
                'https://www.transfermarkt.com/prva-makedonska-fudbalska-liga/startseite/wettbewerb/MAZ1/plus/?saison_id=',
                'https://www.transfermarkt.com/bardzragujn-khumb/startseite/wettbewerb/ARM1/plus/?saison_id=',
                'https://www.transfermarkt.com/crystalbet-erovnuli-liga/startseite/wettbewerb/GE1N/plus/?saison_id=',
                'https://www.transfermarkt.com/veikkausliiga/startseite/wettbewerb/FI1/plus/?saison_id=',
                'https://www.transfermarkt.com/divizia-nationala/startseite/wettbewerb/MO1N/plus/?saison_id=',
                'https://www.transfermarkt.com/virsliga/startseite/wettbewerb/LET1/plus/?saison_id=',
                'https://www.transfermarkt.com/telekom-1-cfl/startseite/wettbewerb/MNE1/plus/?saison_id=',
                'https://www.transfermarkt.com/superliga-e-kosoves/startseite/wettbewerb/KO1/plus/?saison_id=',
                'https://www.transfermarkt.com/bgl-ligue/startseite/wettbewerb/LUX1/plus/?saison_id=',
                'https://www.transfermarkt.com/a-lyga/startseite/wettbewerb/LI1/plus/?saison_id=',
                'https://www.transfermarkt.com/premium-liiga/startseite/wettbewerb/EST1/plus/?saison_id=',
                'https://www.transfermarkt.com/pepsi-max-deild/startseite/wettbewerb/IS1/plus/?saison_id=',
                'https://www.transfermarkt.com/cymru-premier/startseite/wettbewerb/WAL1/plus/?saison_id=',
                'https://www.transfermarkt.com/betri-deildin/startseite/wettbewerb/FARO/plus/?saison_id=',
                'https://www.transfermarkt.com/primera-divisio/startseite/wettbewerb/AND1/plus/?saison_id=',
                'https://www.transfermarkt.com/premier-league/startseite/wettbewerb/IR1/plus/?saison_id=',
                'https://www.transfermarkt.com/danske-bank-premiership/startseite/wettbewerb/NIR1/plus/?saison_id=',
                'https://www.transfermarkt.com/campionato-sammarinese/startseite/wettbewerb/SMR1/plus/?saison_id=',
                'https://www.transfermarkt.com/gibraltar-national-league/startseite/wettbewerb/GI1/plus/?saison_id=',
                'https://www.transfermarkt.com/championship/startseite/wettbewerb/GB2/plus/?saison_id=',
                'https://www.transfermarkt.com/laliga2/startseite/wettbewerb/ES2/plus/?saison_id=',
                'https://www.transfermarkt.com/serie-b/startseite/wettbewerb/IT2/plus/?saison_id=',
                'https://www.transfermarkt.com/ligue-2/startseite/wettbewerb/FR2/plus/?saison_id=',
                'https://www.transfermarkt.com/2-bundesliga/startseite/wettbewerb/L2/plus/?saison_id=',
                'https://www.transfermarkt.com/keuken-kampioen-divisie/startseite/wettbewerb/NL2/plus/?saison_id=',
                'https://www.transfermarkt.com/1-lig/startseite/wettbewerb/TR2/plus/?saison_id=',
                'https://www.transfermarkt.com/liga-portugal-2/startseite/wettbewerb/PO2/plus/?saison_id=',
                'https://www.transfermarkt.com/2-liga/startseite/wettbewerb/A2/plus/?saison_id=',
                'https://www.transfermarkt.com/challenge-league/startseite/wettbewerb/C2/plus/?saison_id=',
                'https://www.transfermarkt.com/proximus-league/startseite/wettbewerb/BE2/plus/?saison_id=',
                'https://www.transfermarkt.com/super-league-2/startseite/wettbewerb/GRS2/plus/?saison_id=',
                'https://www.transfermarkt.com/liga-2/startseite/wettbewerb/RO2/plus/?saison_id=',
                'https://www.transfermarkt.com/fortuna-1-liga/startseite/wettbewerb/PL2/plus/?saison_id=',
                'https://www.transfermarkt.com/nemzeti-bajnoksag-ii-/startseite/wettbewerb/UN2/plus/?saison_id='])
 

Это моя настройка со всеми URL-адресами для повторения в течение каждого сезона. Затем я пытаюсь извлечь данные, используя приведенный ниже код:

 #Scraping part
#The first loop is for each url in our URL-list
for m in range(0, len(league_urls)):
    time.sleep(0.5)
    #The second loop is for each year we want to scrape
    for n in range(2007,2020):
        time.sleep(0.5)
        df_soccer1 = None
        url = league_urls[m]   str(n)
        headers = {"User-Agent":"Mozilla/5.0"}
        response = requests.get(url, headers=headers, verify=False)
        time.sleep(0.5)
        soup = BeautifulSoup(response.text, 'html.parser')

        #Table 1 with information about the value
        table = soup.find("table", {"class" : "items"})

        team = []
        squad = []
        age = []
        foreigners = []
        total_market_value = []
        average_market_value = []

        for row in table.findAll('tr'):
            try:
                col = row.findAll('td')
                team.append(col[2].text)
                squad.append(col[3].text)
                age.append(col[4].text)
                foreigners.append(col[5].text)
                total_market_value.append(col[6].text)
                average_market_value.append(col[7].text)
            except:
                pass

        team = [elem.replace('n','').replace('xa0','').strip() for elem in team]

        #Table 2 with information about placement, goals and points
        df_soccer2 = None

        table2 = soup.findAll("div", {"class" : "responsive-table"})

        team2 = []
        place = []
        matches = []
        difference = []
        pts = []

        if len(table2) <= 2:
            for row in table2[1].findAll('tr'):
                try:
                    col = row.findAll('td')
                    team2.append(col[2].text)
                    place.append(col[0].text)
                    matches.append(col[3].text)
                    difference.append(col[4].text)
                    pts.append(col[5].text)
                except:
                    pass
        else:
            #Sometimes the information you need is in another table
            for row in table2[2].findAll('tr'):
                try:
                    col = row.findAll('td')
                    team2.append(col[2].text)
                    place.append(col[0].text)
                    matches.append(col[3].text)
                    difference.append(col[4].text)
                    pts.append(col[5].text)
                except:
                    pass
                
        team2 = [elem.replace('n','').replace('xa0','').strip() for elem in team2]

        df_soccer1 = pd.DataFrame({'Team': team[1:], 'Season': n, 'Squad': squad[1:], 'Age': age[1:], 'Foreigners': foreigners[1:],
                                     'Total Value': total_market_value[1:], 'Average value': average_market_value[1:]})

        df_soccer2 = pd.DataFrame({'Team': team2, 'Place': place, 'Matches': matches, 'Difference': difference,
                                     'Points': pts})

        #Store all dictionaries in a list
        dct_all = [dct_GB1,dct_IT1,dct_ES1,dct_L1,dct_FR1,dct_PO1,dct_NL1,dct_TR1,dct_BE1,dct_UKR1,dct_A1,
                   dct_GR1,dct_TS1,dct_SC1,dct_KR1,dct_C1,dct_PL1,dct_DK1,dct_ER1,dct_RO1,dct_SE1,dct_ZYP1,dct_NO1,
                   dct_KAS1,dct_UNG1,dct_ISR1,dct_BU1,dct_WER1,dct_SLO1,dct_SL1,dct_AZ1,dct_BOS1,dct_MAL1,dct_ALB1,
                   dct_MAZ1,dct_ARM1,dct_GE1N,dct_FI1,dct_MO1N,dct_LET1,dct_MNE1,dct_KO1,dct_LUX1,dct_LI1,dct_EST1,
                   dct_IS1,dct_WAL1,dct_FARO,dct_AND1,dct_IR1,dct_NIR1,dct_SMR1,dct_GI1,dct_GB2,dct_ES2,dct_IT2,
                   dct_FR2,dct_L2,dct_NL2,dct_TR2,dct_PO2,dct_A2,dct_C2,dct_BE2,dct_GRS2,dct_RO2,dct_PL2,dct_UN2]
        
        #Merge df_soccer1 and df_soccer2 for each season
        dct_all[l]['df_bl_%s' % n] = pd.merge(df_soccer1, df_soccer2, how="inner", left_on="Team", right_on="Team")
 

Проблема в том, что я получаю ошибку:

Ошибка значения: все массивы должны быть одинаковой длины

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

Редактировать:

Вот ошибка, которую я получаю

 --------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-7-534e3145bb5f> in <module>
     50 
     51 
---> 52         df_soccer1 = pd.DataFrame({'Team': team[1:], 'Season': n, 'Squad': squad[1:], 'Age': age[1:], 'Foreigners': foreigners[1:],
     53                                      'Total Value': total_market_value[1:], 'Average value': average_market_value[1:]})
     54 

~anaconda3libsite-packagespandascoreframe.py in __init__(self, data, index, columns, dtype, copy)
    527 
    528         elif isinstance(data, dict):
--> 529             mgr = init_dict(data, index, columns, dtype=dtype)
    530         elif isinstance(data, ma.MaskedArray):
    531             import numpy.ma.mrecords as mrecords

~anaconda3libsite-packagespandascoreinternalsconstruction.py in init_dict(data, index, columns, dtype)
    285             arr if not is_datetime64tz_dtype(arr) else arr.copy() for arr in arrays
    286         ]
--> 287     return arrays_to_mgr(arrays, data_names, index, columns, dtype=dtype)
    288 
    289 

~anaconda3libsite-packagespandascoreinternalsconstruction.py in arrays_to_mgr(arrays, arr_names, index, columns, dtype, verify_integrity)
     78         # figure out the index, if necessary
     79         if index is None:
---> 80             index = extract_index(arrays)
     81         else:
     82             index = ensure_index(index)

~anaconda3libsite-packagespandascoreinternalsconstruction.py in extract_index(data)
    399             lengths = list(set(raw_lengths))
    400             if len(lengths) > 1:
--> 401                 raise ValueError("arrays must all be same length")
    402 
    403             if have_dicts:

ValueError: arrays must all be same length
 

Ответ №1:

Было бы полезно, если бы вы указали, какая часть вашего кода выдает ошибку. Я предполагаю, что это та часть, где вы инициализируетесь df_soccer1 .

Ваша проблема в том, что try: выполняется до тех пор , пока этого не произойдет , что означает , что если в a всего 5 <td> <tr> , к нему добавляется текст team , squad а age затем возникает ошибка, потому что вы повторяете больше <td> , чем есть, и ничего не добавляется к foreigners двум другим точкам данных. Это означает, что ваши массивы имеют неравномерную длину.

Следующий код разделяет шаги, сначала он извлекает текст из всех <td> , и только если все они были возвращены, информация добавляется, добавляется «еще».

 for row in table.findAll('tr'):
            try:
                col = row.findAll('td')
                team_ = col[2].text
                squad_ = col[3].text
                age_ = col[4].text
                foreigners_ = col[5].text
                total_ = col[6].text
                average_ = col[7].text
                team.append(team_)
                squad.append(squad_)
                age.append(age_)
                foreigners.append(foreigners_)
                total_market_value.append(total_)
                average_market_value.append(average_)
            except:
                team.append('')
                squad.append('')
                age.append('')
                foreigners.append('')
                total_market_value.append('')
                average_market_value.append('')
 

Вы также можете использовать try/except (или более эффективно, если/иначе) для каждой из шести точек данных в отдельности, однако вам нужно быть осторожным, если строки, которые не работают должным образом, действительно содержат интересующую вас информацию.

Комментарии:

1. Я отредактировал свой пост, чтобы включить сообщение об ошибке