Я пытаюсь очистить таблицу с веб-страницы с помощью Selenium и BeautifulSoup, но не знаю, как получить реальные данные с помощью BeautifulSoup.
веб-страница: https://leetify.com/app/match-details/5c438e85-c31c-443a-8257-5872d89e548c/details-general
Я попытался извлечь строки таблицы (тег <tr>), но когда я вызываю find_all, массив оказывается пустым.
Когда я проверяю элемент, я вижу несколько элементов с тегом tr, почему они не отображаются с помощью BeautifulSoup.find_all() ??
Я попытался извлечь строки таблицы (тег <tr>), но когда я вызываю find_all, массив оказывается пустым.
Код:
from selenium import webdriver
from bs4 import BeautifulSoup
driver = webdriver.Chrome()
driver.get("https://leetify.com/app/match-details/5c438e85-c31c-443a-8257-5872d89e548c/details-general")
html_source = driver.page_source
soup = BeautifulSoup(html_source, 'html.parser')
table = soup.find_all("tbody")
print(len(table))
for entry in table:
print(entry)
print("\n")
почему они не появляются с помощью BeautifulSoup.find_all() ??
после беглого взгляда кажется, что загрузка страницы занимает много времени.
Дело в том, что когда вы передаете driver.page_source
BeautifulSoup
, еще не весь HTML/CSS загружается.
Итак, решением было бы использовать явное ожидание:
Подождите, пока страница загрузится с помощью Selenium WebDriver для Python
или даже (менее рекомендуется):
from time import sleep
sleep(10)
но я не уверен на 100%, поскольку в настоящее время на моей машине не установлен Selenium
Однако я хотел бы принять совершенно другое решение:
Если вы посмотрите на сетевые вызовы вашего браузера (нажмите F12 в браузере, и откроется параметры разработчика), вы увидите, что данные (таблица), которые вы ищете, загружаются путем отправки запроса GET
их API:
Конечная точка находится под:
https://api.leetify.com/api/games/5c438e85-c31c-443a-8257-5872d89e548c
который вы можете просмотреть прямо из вашего браузера.
Итак, вы можете напрямую использовать библиотеку запросов , чтобы отправить GET-запрос к указанной выше конечной точке, что будет намного эффективнее:
import requests
from pprint import pprint
response = requests.get('https://api.leetify.com/api/games/5c438e85-c31c-443a-8257-5872d89e548c')
data = response.json()
pprint(data)
Отпечатки (срезанные):
{'agents': [{'gameFinishedAt': '2024-07-06T07:10:02.000Z',
'gameId': '5c438e85-c31c-443a-8257-5872d89e548c',
'id': '63e38340-d1ae-4e19-b51c-e278e3325bbb',
'model': 'customplayer_tm_balkan_variantk',
'steam64Id': '76561198062922849',
'teamNumber': 2},
{'gameFinishedAt': '2024-07-06T07:10:02.000Z',
'gameId': '5c438e85-c31c-443a-8257-5872d89e548c',
'id': 'e10f9fc4-759d-493b-a17f-a85db2fcd09d',
'model': 'customplayer_ctm_fbi_variantg',
'steam64Id': '76561198062922849',
'teamNumber': 3},
Этот подход позволяет избежать необходимости ждать загрузки страницы и позволяет получить прямой доступ к данным.
Вам нужно дать веб-странице время загрузиться. В настоящее время на большинстве веб-сайтов данные заполняются с помощью AJAX от клиента. Приведенный ниже код может помочь, но это не идеальный способ. Вы должны добавить логику ожидания, пока определенный элемент не станет видимым. См. https://selenium-python.readthedocs.io/waits.html
from selenium import webdriver
from bs4 import BeautifulSoup
import time
driver = webdriver.Chrome()
driver.get("https://leetify.com/app/match-details/5c438e85-c31c-443a-8257-5872d89e548c/details-general")
time.sleep(2)
html_source = driver.page_source
soup = BeautifulSoup(html_source, 'html.parser')
table = soup.find_all("tbody")
print(len(table))
for entry in table:
print(entry)
print("\n")
Вам не нужно использовать BeautifulSoup, поскольку все можно сделать с помощью модуля селена следующим образом:
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver import ChromeOptions
from selenium.webdriver.support.expected_conditions import presence_of_all_elements_located as POAEL
URL = "https://leetify.com/app/match-details/5c438e85-c31c-443a-8257-5872d89e548c/details-general"
options = ChromeOptions()
options.add_argument("--headless")
with webdriver.Chrome(options=options) as driver:
driver.get(URL)
wait = WebDriverWait(driver, 10)
selector = By.CSS_SELECTOR, "table tr"
for tr in wait.until(POAEL(selector)):
print(tr.text)
Суть ожидания заключается в том, что страница, которую вы очищаете, управляется JavaScript, поэтому вам необходимо быть уверенным, что элемент таблицы (тег) был отображен, прежде чем пытаться проанализировать его содержимое.
Содержимое HTML на этой странице немного необычно: таблица содержит более одного элемента tbody, поэтому вам, вероятно, захочется это обработать. Код в этом ответе просто генерирует текст из всех/любых элементов tr в таблице, не принимая во внимание тело, откуда они пришли.