Невозможно очистить все данные из таблицы с отложенной загрузкой с помощью Selenium

Я пытаюсь извлечь три поля (player, logo, dkprice) из таблицы, расположенной в середине веб-страницы . Чтобы увидеть все данные в этой таблице, необходимо прокрутить ее вниз.

Я создал скрипт в selenium, который может прокручивать содержимое таблицы вниз, но может очищать только последние 16 результатов. Однако в таблице 240 элементов.

Моя цель — очистить все содержимое таблицы с помощью selenium, поскольку я уже успешно захватил содержимое с помощью модуля requests. Я хочу знать, почему даже после прокрутки вниз Selenium все еще не может проанализировать все содержимое этой таблицы.

Я добился успеха, используя модуль запросов:

import requests

link = 'https://fantasyteamadvice.com/api/user/get-ownership'

res = requests.post(link,json = {"sport":"mlb"})
for item in res.json()['ownership']:
    print(item['fullname'],item['team'],item['dkPrice'])

Скрипт, созданный с помощью Selenium, может анализировать только последние 16 элементов:

import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager

link = 'https://fantasyteamadvice.com/dfs/mlb/ownership'

def get_content(driver,link):
    driver.get(link)
    scroll_to_get_more(driver)
    for elem in WebDriverWait(driver,20).until(EC.presence_of_all_elements_located((By.CSS_SELECTOR,".ownership-table-container [class$='player-row']"))):
        player = elem.find_element(By.CSS_SELECTOR,"[data-testid='ownershipPlayer']").text
        logo = elem.find_element(By.CSS_SELECTOR,"[data-testid='ownershipPlayerTeam'] > img").get_attribute("alt")
        dkprice = elem.find_element(By.CSS_SELECTOR,"[data-testid='ownershipPlayerDkPrice']").text
        yield player,logo,dkprice


def scroll_to_get_more(driver):
    last_elem = ''
    while True:
        current_elem = WebDriverWait(driver,20).until(EC.visibility_of_element_located((By.CSS_SELECTOR,".ownership-table-container [class$='player-row']:last-child")))
        driver.execute_script("arguments[0].scrollIntoView();", current_elem)
        time.sleep(3) # wait for page to load new content
        if (last_elem == current_elem):
           break
        else:
           last_elem = current_elem


if __name__ == '__main__':
    driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))
    try:
        for item in get_content(driver,link):
            print(item)
    finally:
        driver.quit()

Как я могу очистить все данные этой таблицы отложенной загрузки с помощью Selenium?

🤔 А знаете ли вы, что...
Python был создан Гвидо ван Россумом и впервые выпущен в 1991 году.


122
3

Ответы:

Все данные в таблице вы можете получить из ответа на следующий запрос:


Решено

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

Итак, вот мой код, например:

import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager

link = 'https://fantasyteamadvice.com/dfs/mlb/ownership'

def get_content(driver):
    rows = WebDriverWait(driver,20).until(EC.presence_of_all_elements_located((By.CSS_SELECTOR,".ownership-table-container [class$='player-row']")))
    
    tempData = []
    for elem in rows:
        player = elem.find_element(By.CSS_SELECTOR,"[data-testid='ownershipPlayer']").text
        logo = elem.find_element(By.CSS_SELECTOR,"[data-testid='ownershipPlayerTeam'] > img").get_attribute("alt")
        dkprice = elem.find_element(By.CSS_SELECTOR,"[data-testid='ownershipPlayerDkPrice']").text

        tempData.append((player,logo,dkprice))
        
    return tempData
            
            
    
    


def scroll_to_get_more(driver):
    current_elem = WebDriverWait(driver,20).until(EC.visibility_of_element_located((By.CSS_SELECTOR,".ownership-table-container [class$='player-row']:last-child")))
    driver.execute_script("arguments[0].scrollIntoView();", current_elem)
    time.sleep(3) # wait for page to load new content


# To remove duplicates and maintain the order
def de_dup(data):
    dedup_data = []
    for x in data:
        if x not in dedup_data:
            dedup_data.append(x)
            
    return dedup_data


if __name__ == '__main__':
    driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))
    driver.get(link)
    complete = False
    data = []
    while complete == False:
        current_data = data.copy()
        data += get_content(driver)
        data = de_dup(data)
        scroll_to_get_more(driver)
        
        # Once the code no longer adds new data, we know it's complete
        if len(current_data) == len(data):
            complete = True
            
    driver.close()
    
    for tup in data:
        print(tup)

Результат: 158 игроков.

('Carlos Santana', 'MIN logo', '$4200')
('Tommy Pham', 'CWS logo', '$3800')
('Jose Altuve', 'HOU logo', '$5300')
('Jd Martinez', 'NYM logo', '$4900')
('Salvador Perez', 'KAN logo', '$4900')
('Nathan Eovaldi', 'TEX logo', '$9300')
('Paul Goldschmidt', 'STL logo', '$4500')
('Christian Vazquez', 'MIN logo', '$2900')
('Nolan Arenado', 'STL logo', '$4100')
('Andrew Mccutchen', 'PIT logo', '$4200')
('Randal Grichuk', 'ARI logo', '$3200')
('Marcell Ozuna', 'ATL logo', '$5800')
('Jon Singleton', 'HOU logo', '$2700')
('Adam Duvall', 'ATL logo', '$3200')
('Jose Quintana', 'NYM logo', '$7400')
('Willson Contreras', 'STL logo', '$5100')
...
('Masataka Yoshida', 'BOS logo', '$3700')
('Jake Bloss', 'HOU logo', '$6600')
('Wyatt Langford', 'TEX logo', '$4200')
('Paul Skenes', 'PIT logo', '$10500')

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

На сайте используется window.innerHeight для установки высоты контейнера/видимых элементов. Вы можете заставить его отображать все, переопределив InnerHeight большим значением:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC


driver = webdriver.Chrome()
driver.get('https://fantasyteamadvice.com/dfs/mlb/ownership')
driver.execute_script('window.innerHeight = 100000;')

rows = WebDriverWait(driver, 30).until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, 'div[data-testid = "ownershipPlayerRow"]'))) 
print(f'{len(rows) = }')