#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', '-', '-', '-', '-']
# ...