Необходима помощь в очистке сайта с помощью Selenium на Python

#python #pandas #selenium #selenium-webdriver

Вопрос:

Я пытаюсь соскрести имена игроков НБА и прогнозируемый результат фантазии (не один показатель DFS), используя selenium. Я дошел до того, что использовал selenium для автоматизации нажатия NBA и выбора вкладки «Оценка фантазии».

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

Может кто-нибудь, пожалуйста, взглянуть на мой код и указать мне правильное направление ?

 from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time
import pandas as pd

PATH = "C:Program Files (x86)chromedriver.exe"
driver = webdriver.Chrome(PATH)

driver.get("https://app.prizepicks.com/")

popup = driver.find_element_by_class_name("close").click()
NBA = driver.find_element_by_xpath("//div[@class='name'][normalize-space()='NBA']").click()
fantasyScore = driver.find_element_by_xpath("//div[@class='segment-selector-button']").click()

projections = driver.find_element_by_class_name('projections')

nbaPlayers = []

for projection in projections:
    
    names = projection.find_element_by_xpath('.//*[@id="projections"]/div/div/div[1]/div[2]/div[1]/div[3]/div[1]').text
    points= projection.fine_element_by_xpath('.//*[@id="projections"]/div/div/div[1]/div[2]/div[2]/div[1]/text()').text
    print(names, points)
    
    players = {
        'Name': names,
        'FantasyPoints':points,
        }
    
    nbaPlayers.append(players)

df = pd.DataFrame(nbaPlayers)
print(df)

driver.quit()
    
 

Изменить: 6.12.21 5:22 ВЕЧЕРА по восточному времени
Это была первая часть моего кода, которая была исправлена С. Пеком (Спасибо!)
Следующая часть кода также оказалась неудачной.

 from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time
import pandas as pd
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

#sample data
pp = {'Player Name':['Donovan Mitchell', 'Kawhi Leonard', 'Rudy Gobert', 'Paul George','Reggie Jackson', 'Jordan Clarkson'],
      'Fantasy Score': [46.0, 50.0, 40.0, 44.0, 25.0, 26.5]}

#Creating a dataframe from dictionary
dfNBA = pd.DataFrame(pp)

#Scraping ESPN
PATH = "C:Program Files (x86)chromedriver.exe"
driver = webdriver.Chrome(PATH)
driver.get("https://www.espn.com/")

#Clicking the search button
driver.find_element_by_xpath("//a[@id='global-search-trigger']").click() 

#sending data to the search button
driver.find_element_by_xpath("//input[@placeholder='Search Sports, Teams or Players...']").send_keys(dfNBA.iloc[0,:].values[0])
WebDriverWait(driver, 20).until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, ".search_results__details")))
playerPage = driver.find_element_by_css_selector(".search_results__details").click()

#Scraping data from last 10 games
points = driver.find_element_by_xpath("//*[@id='fittPageContainer']/div[2]/div[5]/div/div[1]/div[1]/section/div/div[3]/div/div/div[2]/table/tbody/tr[1]/td[13]")
rebs = driver.find_element_by_xpath("//*[@id='fittPageContainer'']/div[2]/div[5]/div/div[1]/div[1]/section/div/div[3]/div/div/div[2]/table/tbody/tr[1]/td[7]")                                    
asts = driver.find_element_by_xpath("//*[@id='fittPageContainer']/div[2]/div[5]/div/div[1]/div[1]/section/div/div[3]/div/div/div[2]/table/tbody/tr[1]/td[8]")
blks = driver.find_element_by_xpath("//*[@id='fittPageContainer']/div[2]/div[5]/div/div[1]/div[1]/section/div/div[3]/div/div/div[2]/table/tbody/tr[1]/td[9]")
stls = driver.find_element_by_xpath("//*[@id='fittPageContainer']/div[2]/div[5]/div/div[1]/div[1]/section/div/div[3]/div/div/div[2]/table/tbody/tr[1]/td[10]")
tnvrs = driver.find_element_by_xpath("//*[@id='fittPageContainer']/div[2]/div[5]/div/div[1]/div[1]/section/div/div[3]/div/div/div[2]/table/tbody/tr[1]/td[12]")

projectedPoints = points (rebs*1.2) (asts*1.5) (blks*3) (stls*3)-(tnvrs*1)
print(projectedPoints)


#my final table should look like:
#Index   Name           FantasyPoints  ESPN L10 Avg
#0     Donovan Mitchell      46           27.8

 

Цель этого проекта состоит в том, чтобы сначала собрать призовые места и получить имена игроков NBA и очки fantasy, затем сохранить очищенные данные во фрейме данных, используя сохраненные данные фрейма данных, я попытался повторить каждую строку, затем взять имена игроков и подключить их в поле поиска ESPN. Это должно открыть страницу игроков. На странице игроков я попытался соскрести очки, переборы, задницы, кражи, блки, обороты и т. Д., А затем сложить их, используя формулу в переменной projectedPoints

Таким образом, в конечном счете, я смогу рассчитать прогнозируемые баллы для каждого игрока и сравнить эти баллы с фантастическими баллами, полученными в результате выбора призов. Используя это сравнение, я приму решение, будет ли игрок СТАРШЕ или НИЖЕ фантастических очков

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

1. Я вижу там элементы, расположенные по имени класса projections ..

Ответ №1:

Вы могли бы сделать это проще без Selenium этого, так как данные динамически загружаются из api:

 import pandas as pd
import requests

params = (
    ('league_id', '7'),
    ('per_page', '250'),
    ('projection_type_id', '1'),
    ('single_stat', 'true'),
)

session = requests.Session() 
response = session.get('https://api.prizepicks.com/projections', data=params)

df1 = pd.json_normalize(response.json()['included'])
df1 = df1[df1['type'] == 'new_player']

df2 = pd.json_normalize(response.json()['data'])

df = pd.DataFrame(zip(df1['attributes.name'], df2['attributes.line_score']), columns=['name', 'points'])
 

Выход:

Имя Очки
0 Донован Митчелл 46
1 Кауи Леонард 50
2 Руди Гоберт 40
3 Пол Джордж 44
4 Майк Конли 29.5

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

1. Не знаком с этим методом. Но спасибо! Это просто, коротко и работает

2. …и гораздо более эффективный и надежный. Всегда используйте канал api, если он доступен.

Ответ №2:

Я внес некоторые изменения в ваш код, и теперь я думаю, что он дает желаемый результат.

Изменения, которые я внес:

  1. Когда вы используете .click() , бесполезно определять переменную как element.click() , поэтому я избавился от них.
  2. Вы хотите использовать find_elements вместо find_element того, чтобы получать массив веб-элементов для итерации.
  3. Xpath для names и points были не совсем правильными, поэтому я их исправил.
  4. Мне нужно было побудить WebDriverWait , чтобы projection элементы существовали, когда вы их ищете. Для этого требуется следующий импорт:
 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 import webdriver
from selenium.webdriver.common.keys import Keys
import time
import pandas as pd
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

PATH = "C:Program Files (x86)chromedriver.exe"
driver = webdriver.Chrome(PATH)
driver.get("https://app.prizepicks.com/")
driver.find_element_by_class_name("close").click()
driver.find_element_by_xpath("//div[@class='name'][normalize-space()='NBA']").click()
driver.find_element_by_xpath("//div[@class='segment-selector-button']").click()
projections = WebDriverWait(driver, 20).until(
 EC.presence_of_all_elements_located((By.CSS_SELECTOR, ".projection")))

nbaPlayers = []

for projection in projections:

    names = projection.find_element_by_xpath('.//div[@class="name"]').text
    points= projection.find_element_by_xpath('.//div[@class="presale-score"]').get_attribute('innerHTML')
    print(names, points)

    players = {
        'Name': names,
        'FantasyPoints':points,
        }

    nbaPlayers.append(players)

df = pd.DataFrame(nbaPlayers)
print(df)

driver.quit()
 

Выход есть:

 Donovan Mitchell 46.0
Kawhi Leonard 50.0
Rudy Gobert 40.0
Paul George 44.0
Mike Conley 29.5
Reggie Jackson 25.0
Jordan Clarkson 25.0
Marcus Morris 23.0
Bojan Bogdanovic 25.0
Ivica Zubac 16.0
Royce O'Neale 22.0
Nicolas Batum 19.0
Joe Ingles 22.0
Patrick Beverley 10.0
                Name FantasyPoints
0   Donovan Mitchell          46.0
1      Kawhi Leonard          50.0
2        Rudy Gobert          40.0
3        Paul George          44.0
4        Mike Conley          29.5
5     Reggie Jackson          25.0
6    Jordan Clarkson          25.0
7      Marcus Morris          23.0
8   Bojan Bogdanovic          25.0
9        Ivica Zubac          16.0
10     Royce O'Neale          22.0
11     Nicolas Batum          19.0
12        Joe Ingles          22.0
13  Patrick Beverley          10.0
 

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

1. Огромное спасибо. Вот почему я люблю это сообщество. Я потратил несколько часов, пытаясь разобраться в этом самостоятельно, и был разочарован

Ответ №3:

Я не вижу там элементов, соответствующих projections названию класса, но если они должны быть там, вы должны использовать find_elements вместо find_element .
Я думаю, ваш код должен быть таким, чтобы получать имена игроков и оценки:

 nbaPlayers = []

players = driver.find_elements_by_xpath("//div[@class='player']")
for player in players:
    name = player.find_element_by_xpath('.//div[@class='name']').text
    points = player.find_element_by_xpath('./../..//div[@class='presale-score']').text
    print(names, points)
    data = {
        'Name': name,
        'FantasyPoints':points,
        }
    
    nbaPlayers.append(data)
 

Ответ №4:

Видите, вы используете

 projections = driver.find_element_by_class_name('projections')
 

и прокручивается вот так :

 for projection in projections:
 

Это вернет веб-элемент sing. Но ваше требование требует списка имен игроков, верно ?

так что используйте find_elements вместо этого :

 names = driver.find_elements_by_css_selector("div.player div.name")
for player_name in names:
    print(player_name.text)
 

То же самое, что вы можете повторить для рейтингов, CSS_SELECTOR было бы div.score div