Я пытаюсь очистить данные с веб-сайта TransferMarkt на Python. Однако структура сайта сложна. Я пробовал использовать запросы и модули Beautiful Soup, а также следующий код. Однако конечный результат, который я получаю, — это два пустых фрейма данных для «входящих» и «исходящих» передач. Я хочу извлечь информацию из таблиц (показанных на рисунке) в два отдельных фрейма данных. In_transfers_df должен содержать информацию, отображаемую в таблицах «In», а out_transfers_df должен содержать информацию, отображаемую в таблице «Out». Это следует повторить для каждого заголовка, например. Арсенал, Астон Вилла
Я приложил фотографию, показывающую структуру веб-сайта и мою попытку кода. Любая помощь будет принята с благодарностью.
import requests
from bs4 import BeautifulSoup
import pandas as pd
# URL of the Transfermarkt page
url = 'https://www.transfermarkt.com/premier-league/transfers/wettbewerb/GB1/plus/?saison_id=2023&s_w=&leihe=0&intern=0'
# Send a GET request to the URL
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
}
response = requests.get(url, headers=headers)
response.raise_for_status() # Raise an exception if the request was unsuccessful
# Parse the page content using BeautifulSoup
soup = BeautifulSoup(response.content, 'html.parser')
# Function to extract transfer data
def extract_transfer_data(table):
transfers = []
rows = table.find_all('tr', class_=['odd', 'even'])
for row in rows:
cols = row.find_all('td')
if len(cols) >= 5: # Ensure there are enough columns
transfers.append({
'Player': cols[0].text.strip(),
'Age': cols[1].text.strip(),
'Club': cols[2].text.strip(),
'Fee': cols[4].text.strip()
})
return transfers
# Locate the main transfer table container
transfer_containers = soup.find_all('div', class_='grid-view')
# Debugging: print the number of transfer containers found
print(f"Found {len(transfer_containers)} transfer containers.")
# Extract 'In' and 'Out' transfers data
in_transfers = []
out_transfers = []
for container in transfer_containers:
headers = container.find_all('h2')
tables = container.find_all('table')
for header, table in zip(headers, tables):
if 'In' in header.text:
in_transfers.extend(extract_transfer_data(table))
elif 'Out' in header.text:
out_transfers.extend(extract_transfer_data(table))
# Convert to DataFrames
in_transfers_df = pd.DataFrame(in_transfers)
out_transfers_df = pd.DataFrame(out_transfers)
Извините, мой отредактированный вопрос лучше объясняет, что я хотел бы сделать?
ты сам написал этот код?
Да, но я использовал руководство, которому следовал в Интернете, почему оно актуально? Если это не так, то поэтому я и задаю вопрос
потому что код не имеет смысла? на странице нет классов нечетного/четного или сетки, нет заголовков, содержащих «отправление» или «прибытие»?
Как правильно заметил @GTK, ваше руководство устарело. Если присмотреться внимательнее, то теперь нужные вам данные находятся в элементах div
с классом box
. Именно за них и нужно «цепляться», чтобы получить необходимые данные.
Однако, если не считать таких элементов, это может быть не то, что мы ищем. Например, этот блок также имеет аналогичную структуру. Итак, вы должны быть осторожны.
Итак, если вам нужна помощь, вот решение, которое я набросал на лету, и которое подойдет вам. Однако вам следует делать это шаг за шагом и понимать, как это в конечном итоге работает. Улучшите обработку ошибок, а также при необходимости загрузите данные в pandas
.
from collections import defaultdict
from pprint import pprint
import requests
from bs4 import BeautifulSoup
start_url = (
'https://www.transfermarkt.com/premier-league/transfers/wettbewerb/GB1/'
'plus/?saison_id=2023&s_w=&leihe=0&intern=0'
)
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
}
response = requests.get(start_url, headers=headers)
soup = BeautifulSoup(response.text, 'html.parser')
def extract_club_name(node):
try:
return node.find('a')['title']
except (TypeError, KeyError):
return None
def parse_transfers_table(node):
for tr in node.find('tbody').find_all('tr'):
national = tr.find('td', class_='nat-transfer-cell')
prev_club_data = tr.find(
'td',
class_='no-border-links verein-flagge-transfer-cell',
)
previous_club = (
'' if prev_club_data.find('a') is None
else prev_club_data.find('a')['title']
)
yield {
'name': tr.find('span').find('a')['title'],
'age': tr.find('td', class_='alter-transfer-cell').text,
'national': [c['title'] for c in national if c.has_attr('title')],
'position': tr.find('td', class_='kurzpos-transfer-cell').text,
'market_price': tr.find('td', class_='mw-transfer-cell').text,
'previous_club': previous_club,
'transfer_value': tr.find('td', class_='rechts').text,
}
result = defaultdict(defaultdict)
for club_info in soup.find_all('div', class_='box'):
club_name = extract_club_name(club_info)
if club_name is None:
continue
in_transfers_table, out_transfers_table = (
club_info.find_all('div', class_='responsive-table')
)
result[club_name]['in'] = [*parse_transfers_table(in_transfers_table)]
result[club_name]['out'] = [*parse_transfers_table(out_transfers_table)]
pprint(result)
Да, мне действительно нужна была помощь, и я благодарю вас за ответ. Это очень полезно
Замечательно! В таком случае, возможно, вам стоит принять ответ?
Вы забыли задать свой вопрос.