Хранение элементов таблицы с веб — страницы в словаре

#python #selenium #web-scraping

Вопрос:

Я пытаюсь извлечь таблицу с веб-страницы, над которой я работаю, чтобы сохранить заголовки в виде ключей, а текст в виде значений, но отдельно, чтобы указать, с какой страницы они взяты. Вот что я попробовал:

 from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.by import By
s=Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=s)
driver.maximize_window()
driver.get('https://www.google.com')


all_data = []
for i in range(1,6):
    url = "https://www.transfermarkt.co.uk/silvio-adzic/profil/spieler/{}".format(i)
    driver.get(url)
    time.sleep(3)
    data = {}
    soup = BeautifulSoup(driver.page_source, 'html5lib')
    print(f"In Page {i}")
    for th in soup.select("#yw2 tr"):
        data[th.get_text(strip = True)] = th.find_next('td').get_text(strip=True)
    all_data.append(data)
 

Однако это приводит к беспорядочному словарю:

 [{'competitionwettbewerb': 'Total :',
  'Total :25169524616.948': 'Total :',
  'Regionalliga Süd': 'Regionalliga Süd',
  'Regionalliga Süd7922-2876.318': '',
  '2. Bundesliga': '2. Bundesliga',
  '2. Bundesliga60933873.487': '',
  'RL West-Südwest': 'RL West-Südwest',
  'RL West-Südwest5818-1943.493': '',
  'Oberliga Südwest': 'Oberliga Südwest',
  'Oberliga Südwest2015-1101.649': '',
  'Bundesliga': 'Bundesliga',
  'Bundesliga1212355355': '',
..
..
..
 

(Ожидаемый результат) есть ли способ разделить их для каждой извлеченной страницы, чтобы сделать что-то вроде этого?

 [{'p1':{'competition': ["Regionalliga Süd", "2. Bundesliga", ...],
'Appearances': [79, 60,...],
'Goals':[22, 9,...],
'Assists':[-, 3, ...]
...},
'p2':{'competition': ["Bundesliga", "2. Bundesliga", ...],
'Appearances': [262, 98,...],
'Goals':[62, 18,...],
'Assists':[79, -, ...]
...}}]
 

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

1. ты ожидаешь слишком многого. Если вы хотите получить ожидаемый результат, то вам придется писать более сложный код и работать с каждой строкой таблицы отдельно. И, возможно, потребуется также работать с каждой ячейкой в строке отдельно, потому что вам нужно добавить одну ячейку p1 и другую ячейку p2 .

2. ваша проблема с разумом заключается в том, что вы читаете строку за строкой — таким образом, вы получаете данные в строках, — но в результатах вы ожидаете значений из столбцов. И для этого нужно сначала создать словари Appearances Goals , и т. Д. , А затем прочитать ячейки в строке, и каждую ячейку поместить в другой словарь.

3. сначала вы должны создать data = {'competition': [], 'Appearances': [], } , затем вы должны поместить правильные ячейки в правильные места data и, наконец, вы должны all_data.append( {'p{}'.format(i): data} )

Ответ №1:

Для этого требуется более сложный код для работы с каждой строкой и каждой ячейкой отдельно.

Сначала я создаю место для всех данных

 data = {'competition': [], 'Appearances': [], 'Goals':[], 'Assists':[]}
 

Затем я использую for -цикл для получения строк в таблице.
Но есть две проблемы:

  • некоторые tr из них пусты, но у них их нет class , поэтому их легко пропустить. Я также использую tbody для пропуска строки в заголовке.
  • на некоторых страницах он использует идентификатор yw2 yw1 , а на других div data-viewport=Leistungsdaten_Saison -и то, и другое, поэтому легко получить правильные таблицы.
 for tr in soup.select("div[data-viewport=Leistungsdaten_Saison] tbody tr[class]"):
 

Затем я получаю все ячейки в строке и помещаю значения в правильные списки.

         cells = tr.find_all('td')
        #print(cells)
        data['competition'].append(cells[1].get_text(strip=True))
        data['Appearances'].append(cells[2].get_text(strip=True))
        data['Goals']      .append(cells[3].get_text(strip=True))
        data['Assists']    .append(cells[4].get_text(strip=True))
 

И, наконец , я вставил data all_data ключ p1 p2 , и т. Д.

         all_data.append({'p{}'.format(i): data})
 

Полный рабочий код:

 from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
import time
from bs4 import BeautifulSoup

s = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=s)
driver.maximize_window()

all_data = []

for i in range(1, 6):
    print('--- page', i, '---')
    
    url = "https://www.transfermarkt.co.uk/silvio-adzic/profil/spieler/{}".format(i)
    driver.get(url)
    time.sleep(5)

    soup = BeautifulSoup(driver.page_source, 'html5lib')
    
    data = {'competition': [], 'Appearances': [], 'Goals':[], 'Assists':[]}
        
    for tr in soup.select("div[data-viewport=Leistungsdaten_Saison] tbody tr[class]"):
        cells = tr.find_all('td')
        #print(cells)
        data['competition'].append(cells[1].get_text(strip=True))
        data['Appearances'].append(cells[2].get_text(strip=True))
        data['Goals']      .append(cells[3].get_text(strip=True))
        data['Assists']    .append(cells[4].get_text(strip=True))
                                   
    all_data.append({'p{}'.format(i): data})

# --- display ---

for player in all_data:
    name, data = list(player.items())[0]
    print('---', name, '---')
    for key, value in data.items():
        print(key, value)

 

Результат:

 --- p1 ---
competition ['Regionalliga Süd', '2. Bundesliga', 'RL West-Südwest', 'Oberliga Südwest', 'Bundesliga', 'NOFV-Oberliga Süd', 'Oberliga Bayern', 'DFB-Pokal', 'UEFA Cup']
Appearances ['79', '60', '58', '20', '12', '9', '6', '6', '1']
Goals ['22', '9', '18', '15', '1', '-', '2', '2', '-']
Assists ['-', '3', '-', '-', '2', '-', '-', '-', '-']
--- p2 ---
competition ['Bundesliga', '2. Bundesliga', 'DFB-Pokal', 'Champions League', '2. BL North', 'UEFA Cup', 'VL Südwest', '2. BL Nord Aufstiegsr.', 'Ligapokal', "Cup Winners' Cup", 'DFB-SuperCup', 'UI Cup', 'Champions League Qu.', 'Südwestpokal', 'Intertoto-Cup (until 94/95)']
Appearances ['262', '98', '38', '23', '21', '15', '11', '9', '6', '4', '2', '2', '1', '1', '0']
Goals ['62', '18', '9', '7', '3', '4', '1', '2', '2', '2', '-', '2', '-', '1', '-']
Assists ['79', '-', '5', '3', '-', '5', '-', '-', '-', '1', '2', '-', '-', '-', '-']
# ...