您好:参可书籍范例要到driver.get("http://stats.nba.com/players/traditional/?sort=PTS&dir=-1")去抓资料以下程式码中

1.应该是版本问题,select_one 位置不对所以抓不到ValueError: No tables found请问,一般要如何去解析 这一个表格的路径?

  • By.XPATH 后面的路径 与 select_one 有相关性?谢谢

    但是

    pages_remaining = True
    page_num = 1
    while pages_remaining:
    # 使用Beautiful Soup剖析HTML网页
    soup = BeautifulSoup(driver.page_source, "lxml")
    table = soup.select_one("body > main > div.stats-container__inner > div > div.row > div > div > nba-stat-table > div.nba-stat-table > div.nba-stat-table__overflow > table")

    df = pd.read_html(str(table))
    # print(df[0].to_csv())
    df[0].to_csv("ALL_players_stats" + str(page_num) + ".csv")
    print("储存页面:", page_num)

    try:
    # 自动按下一页按钮
    next_link = driver.find_element( By.XPATH ,\'/html/body/main/div[2]/div/div[2]/div/div/nba-stat-table/div[3]/div/div/a[2]\')
    next_link.click()
    time.sleep(5)
    if page_num < 11:
    page_num = page_num + 1
    else:
    pages_remaining = False
    except Exception:
    pages_remaining = False

    3 个回答

    • 旧至新
    • 新至旧
    • 最高Like数

    1

    ccutmis

    iT邦高手 2 级 ‧ 2024-10-05 03:24:18

    最佳解答

    1.应该是版本问题,select_one 位置不对所以抓不到
    ValueError: No tables found
    请问,一般要如何去解析 这一个表格的路径?

    以你这边的例子来说,不是你想的那样,而是因为网页载入后会先弹出一个让使用者按同意的按钮,你没处理这部份,后面的表格还没载入(这是动态载入的表格)就会有 No tables found的错误,解决参考如下:

    from selenium import webdriver
    from selenium.webdriver.common.by import By 
    driver = webdriver.Chrome()
    url="http://stats.nba.com/players/traditional/?sort=PTS&dir=-1"
    driver.get(url)  # 进网站首页
    
    btn = driver.find_element( By.XPATH ,"/html/body/div[3]/div[2]/div/div[1]/div/div[2]/div/button[1]")
    btn.click() # 要先按我同意
    

    到这里为止才算真正看到表格内容刷新,接着就可以获取表格内容:

    table = driver.find_element( By.XPATH ,"/html/body/div[1]/div[2]/div[2]/div[3]/section[2]/div/div[2]/div[3]/table")
    #print(table.get_attribute(\'innerHTML\'))
    print(table.text)
    

    2.By.XPATH 后面的路径 与 select_one 有相关性?

    以你附的代码来看它们是各个独立的,前面的 select_one 是获取 table 的 html 原始码(但因为没处理要先按我同意的部份造成 table未载入而失败)。
    By.XPATH是按Next Page的按钮。


    用 Python Selenium 写网页爬虫有个小妙招跟您,那就是用 Visual Studio Code + jupyter notebook,这里有个简单网页教学:
    https://ccutmis.github.io/study-coding/vscode-for-python.htm#ch4

    这样用的好处就是可以分段写,以上面的範例来说,我的测试.ipynb档案内容为:
    第一段,开启Chrome视窗进入网页,按下我同意...

    第二段,取得表格内容...

    这样就不用一再重覆执行第一段的 driver.get(url)
    只需修改第二段的内容再按执行就能看到测试的内容,提供您参考,楼上的网友提到的 playright 是比较新的技术,有空也可以研究一下。


    • 7

    看更多先前的...收起先前的...

    noway

    iT邦研究生 1 级 ‧
    2024-10-06 18:48:58

    您好:
    (1) 我参考您的第一个问题範例

    btn = driver.find_element( By.XPATH ,"/html/body/div[3]/div[2]/div/div[1]/div/div[2]/div/button[1]")
    

    这一段,结果 没找到您说的按钮

    我改用
    btn = driver.find_element( By.ID,"onetrust-accept-btn-handler")
    可以用

    接下来再用您的

    table = driver.find_element( By.XPATH ,"/html/body/div[1]/div[2]/div[2]/div[3]/section[2]/div/div[2]/div[3]/table")
    

    是有抓到您50笔资料

    但,若改用 原本範例
    要再去抓 下笔 按钮
    就有抓不到

    所以还是想了解有什么方式可以抓 路径
    谢谢

    修改

    ccutmis

    iT邦高手 2 级 ‧
    2024-10-06 21:09:19

    抓路径的方式只能多试了,就如同楼上网友说的多利用浏览器的开发者工具,我用这个方式抓到按下笔按钮:

    再来就是思考怎么让它一次性跑全部表格内容,以这网页为例,页面上可以看它有列出共有几页(Ex:of 5),所以我用同样的方式抓到它的 xpath,然后取得文字后将它转成数值,再用for迴圈重覆去点下笔按钮,但这边有个要特别注意的地方是,按了下笔按钮后,要暂停一下让网页表格载入新的内容(它是动态载入的)我这边是用 time.sleep(5) 让它停五秒,就可以抓到全部表格内容了,以下是测试过可运作的代码:

    import time
    row_txt=driver.find_element( By.XPATH, "/html/body/div[1]/div[2]/div[2]/div[3]/section[2]/div/div[2]/div[2]/div[1]/div[4]")
    page_num=int(row_txt.text.replace("of ",""))
    
    for i in range(0,page_num,1):
        print(f"Page{i+1}")
        table = driver.find_element( By.XPATH ,"/html/body/div[1]/div[2]/div[2]/div[3]/section[2]/div/div[2]/div[3]/table")
        print(table.text) #印出表格内容
        btn = driver.find_element( By.XPATH ,"/html/body/div[1]/div[2]/div[2]/div[3]/section[2]/div/div[2]/div[2]/div[1]/div[5]/button[2]")
        btn.click() #按下页
        time.sleep(5) #休5秒
    

    修改

    noway

    iT邦研究生 1 级 ‧
    2024-10-07 22:43:25

    您好:
    谢谢您,您的方式可以
    不过想再请教一下
    原本他是用BeautifulSoup(driver.page_source, "lxml")
    取得网页TABLE内容
    再用 df = pd.read_html(str(table))
    转成要汇出的内容

    但是现在改用 table.text ,
    他应该已经是一行一行的资料了
    这时候试过
    df=pd.read_csv(table.text)

    似乎都无法过

    这一段,又需要那些技巧呢?
    谢谢

    修改

    ccutmis

    iT邦高手 2 级 ‧
    2024-10-08 01:35:51

    我用你在提问本文里面附的代码稍作修改如下:

    import time
    from bs4 import BeautifulSoup
    import pandas as pd
    
    row_txt=driver.find_element( By.XPATH, "/html/body/div[1]/div[2]/div[2]/div[3]/section[2]/div/div[2]/div[2]/div[1]/div[4]")
    page_num=int(row_txt.text.replace("of ",""))
    
    for i in range(0,page_num,1):
        print(f"Page{i+1}")
        soup = BeautifulSoup(driver.page_source, "lxml")
        table = soup.select_one("table.Crom_table__p1iZz")
        df=pd.read_html(str(table))
        df[0].to_csv("ALL_players_stats" + str(i+1) + ".csv")
        btn = driver.find_element( By.XPATH ,"/html/body/div[1]/div[2]/div[2]/div[3]/section[2]/div/div[2]/div[2]/div[1]/div[5]/button[2]")
        btn.click()
        time.sleep(5)
    

    其实这题的作法有好几种,第一种是上面的範例,第二种是已经有它的逐行text内容其实也可以直接写成csv文字档,当然还有第三种...略。
    soup.select_one() 里面的参数是 CSS SELECTOR,我用开发者工具查了一下,目标表格有个className="Crom_table__p1iZz",所以不用写的落落长,直接用 "table.Crom_table__p1iZz" 应该就可以抓到正确的table。

    修改

    noway

    iT邦研究生 1 级 ‧
    2024-10-08 21:23:33

    谢谢您。
    原本有想要抓TABLE,但用滑鼠点,一直找不到.....
    下次要认真找

    不过我还是很好奇,
    用您最原先的方式,要如何用pandas 输出CSV
    我比较两种table.text
    他是有差异的

    #table = soup.select_one("table.Crom_table__p1iZz") # <TABLE   class="Crom_table__p1iZz" >        
    print(table.text) #印出表格内容
    

    IngramNOP2640436.414.34.813.834.50.52.025.04.34.889.50.34.34.53.32.31.01.32.029.00.00.0-11.0

    table = driver.find_element( By.XPATH ,"/html/body/div[1]/div[2]/div[2]/div[3]/section[2]/div/div[2]/div[3]/table")
    print(table.text) #印出表格内容
    

    50 Brandon Ingram NOP 26 4 0 4 36.4 14.3 4.8 13.8 34.5 0.5 2.0 25.0 4.3 4.8 89.5 0.3 4.3 4.5 3.3 2.3 1.0 1.3 2.0 29.0 0.0 0.0 -11.0

    修改

    ccutmis

    iT邦高手 2 级 ‧
    2024-10-09 10:00:11

    原本有想要抓TABLE,但用滑鼠点,一直找不到.....

    你是用下图的方法抓吗? Step1. 点开发者工具左上角的小箭头 Step.2 移到想找的网页元素位置

    用这方式很好找才是,只是要仔细看清楚是不是正确的位置,因为有些网页标籤包来包去的...。


    用您最原先的方式,要如何用pandas 输出CSV
    我比较两种table.text
    他是有差异的

    原先我用那个方式是想说简单列出表格内容,就知道是不是捞到正确的资讯,我在那一行的前面还有注解一行是可以取得表格内容的html原始码,不知你有没有留意到:

    #print(table.get_attribute(\'innerHTML\'))
    

    达成目的的方法不只一种,只要能达成目的的就是好方法,以这边来说,你最终要的是输出CSV,既已获得表格内容,就不一定需要用到 pandas了(当然这要看情况而定,这里是可以不用),
    CSV是用逗点跟换行把资料逐行逐行记录下来的一种资料格式,例如: "111,222,333,444,555\\n",
    用 print(table.text) 得到的资料如下:

      PLAYER TEAM AGE GP W L MIN PTS FGM FGA FG% 3PM 3PA 3P% FTM FTA FT% OREB DREB REB AST TOV STL BLK PF FP DD2 TD3 +/-
    1 Jaden Ivey DET 22 1 1 0 22.9 22.0 6.0 8.0 75.0 3.0 3.0 100 7.0 9.0 77.8 2.0 0.0 2.0 1.0 0.0 0.0 1.0 2.0 28.9 0.0 0.0 -1.0
    ...略...
    

    它是逐行列出内容,通常只需要留意内容有没有逗点(,),有的话要把它转成别的,没有的话再把分隔符号(这里是空格)转成逗点,然后输出文字档即完成,例如:

    source_ls = table.text.split("\\n")
    # print(source_ls)
    with open("test1.csv","w+",encoding="utf-8") as f:
        for ln in source_ls:
            tmp = ln.replace(",","").replace(" ",",")
            # 把逗点去掉,再把所有空格转成逗点
            f.writelines(f"{tmp}\\n")
    

    上面的範例结果会输出一个 "test1.csv" ,看起来没问题,但仔细一对照下就会看到里面的内容有问题,这是因为球员名字通常是好几个单字中间用空格作分隔,球员名字后面接着的是队名缩写,也是用空格作分隔,用上面的方式处理的话,会多出好几栏原本不该有的栏位,导致资料变成废料,那该怎么解决呢? 我通常是儘量不用这方式处理的,我个人比较偏好分析html原始码,直接用它捞资料(搭配RegEx),既然这里提了,就用RegEx试一下,把名字跟队名的部份分隔开,以下是範例:

    import re
    
    with open("test2.csv","w+",encoding="utf-8") as f:
        for ln in source_ls:
            re_ls = re.findall(\'^\\d{1,3} (.*) [A-Z]{3} \\d{1,3}\', ln)
            if len(re_ls)>0 and re_ls[0]!=\'\':
                tmp = ln.replace(re_ls[0],re_ls[0].replace(" ","_")).replace(" ",",")
                print(tmp) # 把球员名称中间的空格替换成"_"之后再把所有空格替换成",""
                f.writelines(f"{tmp}\\n")
    

    如果对 RegEx 不熟的话,可能看最后这个範例会有点看不懂,也是没关係的,你有兴趣的话就去找 Python RegEx 的教学来看,很多技巧都是基本功的延伸,像这边我不需要 panads 也可以整理数据并输出为 csv 档,当然有的人可能会觉得这是在自找苦吃(现成的模组不用),这里只是举个例子,实际情况该怎么解题就需要自己动动脑了。

    修改

    noway

    iT邦研究生 1 级 ‧
    2024-10-09 21:21:06

    您好:
    谢谢

    你是用下图的方法抓吗? Step1. 点开发者工具左上角的小箭头 Step.2 移到想找的网页元素位置

    对,我是用这方式去找, 箭头是比较好找
    但 TABLE 这一区块,点半天点不到 TABLE

    谢谢您的指导!

    修改

    2

    sam0407

    iT邦大师 1 级 ‧ 2024-10-04 10:29:32

    像这种爬虫範例最常发生的问题就是网页改版了,我通常会先去找一下出版社或作者的网页,看有没有更新的程式码,若没有更新的程式码,您也可以向出版社或作者提出您的问题,当然会不会有就不一定啦~~

    因为有段时间没碰Python了,爬虫也没特别去研究,以下的方法是我可能会去尝试的方向,仅供参考:
    1.我会将soap内容print出来,複製到文字编辑器去,把XML内容排列成下方的格式,这样就可以知道table到底在那个path上,当然这是个笨方法,偶一为之还可以,如果您以后还会持续处理这样的问题,建议可以google一下,找个自动能将网页自动格式化的工具来协助

    <html>
        <body>
        ...
        </body>
    </html>
    

    2.直接用浏览器打开您要抓取的网页,按F12进入网页开发者工具,之前看过其他人都是从这里去找网页相关问题的,建议您花点时间学好这个工具,只要有在作网页相关的工作,绝对是会经常用到。

    2

    echochio

    iT邦高手 1 级 ‧ 2024-10-04 14:21:05

    python 爬虫对于初学者用 playwright for python 比较简单
    录製动作都帮你做好了 ........
    只要重新播放就好
    ps : python版本要求3.7+以上才可安装

    pip install playwright
    python -m playwright install
    playwright install
    python -m playwright codegen --target python -o my.py -b chromium https://www.google.com
    

    再配合 BeautifulSoup 抓取 所需资讯
    例如:

    soup = BeautifulSoup(page.content(),\'html.parser\')    
    element = soup.find("a", {"id": "totalpayed"})
    

    要用 开发者工具 找你要看的


    • 1

    noway

    iT邦研究生 1 级 ‧
    2024-10-06 18:42:14

    您好:
    这后续会找时间学习!
    谢谢

    修改