【问题标题】:Assistance needed scraping a site with Selenium in Python需要协助在 Python 中使用 Selenium 抓取网站
【发布时间】:2023-03-23 11:24:01
【问题描述】:

我正在尝试使用 selenium 抓取 NBA 球员姓名和预计的幻想得分(不是单一统计 DFS)。我已经使用 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 PM CST 这是我的代码的第一部分,由 C. Peck 修复(谢谢!) 下一段代码也不成功。

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

这个项目的目标是首先抓取 PrizePicks 并获取 NBA 球员姓名和幻想得分点,然后使用存储的 dataframe 数据将抓取的数据存储到 dataframe 中,我尝试遍历每一行,然后获取球员名称并将其插入 ESPN 搜索框。这应该会打开播放器页面。在球员页面上,我尝试抓取得分、篮板、助攻、抢断、盲注、失误等,然后使用projectedPoints 变量中的公式将它们相加

所以最终,我将能够计算每个玩家的预计分数,并将这些分数与从奖品选择中获取的幻想分数进行比较。使用此比较,我将决定玩家是否会超过或低于幻想得分

【问题讨论】:

  • 我可以看到类名projections..

标签: python pandas selenium selenium-webdriver


【解决方案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'])

输出:

name points
0 Donovan Mitchell 46
1 Kawhi Leonard 50
2 Rudy Gobert 40
3 Paul George 44
4 Mike Conley 29.5

【讨论】:

  • 不熟悉这种方法。不过谢谢!它简单、简短且有效
  • ...并且更加高效和强大。如果可用,请始终使用 api 提要。
【解决方案2】:

我对您的代码进行了一些更改,现在我认为它可以提供您想要的输出。

我所做的更改:

  1. 当你使用.click()时,定义一个变量为element.click()是没有用的,所以我把那些去掉了。
  2. 您想使用 find_elements 而不是 find_element 来获取要迭代的 WebElement 数组。
  3. namespoints 的 xpath 不太正确,所以我修复了它们。
  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

【讨论】:

  • 非常感谢。这就是为什么我喜欢这个社区。我花了几个小时试图自己解决这个问题并感到沮丧
【解决方案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 web 元素。但是您的要求需要一份球员名单,对吗?

    所以请改用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

    【讨论】:

      猜你喜欢
      • 2021-10-07
      • 1970-01-01
      • 1970-01-01
      • 2019-04-20
      • 1970-01-01
      • 2018-05-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多