You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无法抓取BSCScan动态表格,requests_html返回空、Selenium失效如何解决?

问题根源

你遇到的所有报错/返回空的核心原因是BSCScan的持币人表格是嵌套在独立iframe中的,直接在主页面DOM中查找元素必然返回空,其次你的两段代码都存在语法/逻辑错误。

原有代码的错误点

requests_html 版本错误

  1. 没有切换iframe逻辑,requests_html的render对iframe支持度差,且BSCScan对无头浏览器的反爬拦截概率很高,不推荐用这个方案
  2. xpath选择器没有定位到正确的表格范围,直接查找全局td自然匹配不到

Selenium版本错误

  1. 逻辑错误:调用get_attribute('innerHTML')拿到的是字符串类型,不能继续调用Selenium的元素查找方法find_elements_by_xpath
  2. 位置错误:driver.close()放在for循环内部,第一次遍历就会关闭浏览器,后续遍历直接失效
  3. 选择器错误:持仓占比的xpath写法错误,//td[4]/text无法匹配到元素,需要获取对应td的textContent属性
  4. 缺少等待:没有设置页面渲染等待/iframe加载等待,元素还没加载完成就开始查找,必然返回空

修复后的可运行Selenium代码

import pandas as pd
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

# 注意:请自行替换为你的chromedriver路径,且chromedriver版本要和你的Chrome浏览器版本匹配
driver_path = "/Users/XXX/Downloads/chromedriver"
driver = webdriver.Chrome(driver_path)
# 全局等待超时时间设置为10秒
wait = WebDriverWait(driver, 10)

def get_top_holders(driver, contract_address):
    list_holders = []
    url = f"https://bscscan.com/token/{contract_address}#balances"
    driver.get(url)
    
    # 第一步:切换到持币人表格的iframe,这是最关键的一步
    iframe = wait.until(EC.presence_of_element_located((By.ID, "tokenholderiframe")))
    driver.switch_to.frame(iframe)
    
    # 等待表格tbody加载完成
    wait.until(EC.presence_of_element_located((By.XPATH, "//tbody/tr")))
    # 遍历所有行,跳过表头
    rows = driver.find_elements(By.XPATH, "//tbody/tr")
    for row in rows:
        try:
            # 提取三个字段,注意索引是从1开始的
            address = row.find_element(By.XPATH, "./td[2]/span/a").get_attribute("textContent").strip()
            quantity = row.find_element(By.XPATH, "./td[3]").get_attribute("textContent").strip()
            percentage = row.find_element(By.XPATH, "./td[4]").get_attribute("textContent").strip()
            
            holder_dict = {
                '地址': address,
                '持仓数量': quantity,
                '持仓占比': percentage
            }
            list_holders.append(holder_dict)
            print(holder_dict)
        except Exception as e:
            # 跳过异常行(比如末尾的分页行)
            continue
    
    # 操作完成后切回主页面,不要放在循环里
    driver.switch_to.default_content()
    driver.quit()
    
    # 转成DataFrame
    holders_df = pd.DataFrame(list_holders)
    return holders_df

# 调用测试
contract = "0x84c0160d55a05a28a034e1e6776f84c5995aba3a"
df = get_top_holders(driver, contract)
print(df)

补充说明

如果想搭配BeautifulSoup解析,只需要在切换iframe、等待加载完成后,调用driver.page_source拿到iframe的完整源码,传给BeautifulSoup后用css选择器提取即可,逻辑更简单,不容易写错xpath。
如果遇到反爬拦截,可以给Chrome添加启动参数,设置普通用户的User-Agent,降低拦截概率。

内容的提问来源于stack exchange,提问作者heeervas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 11:39:04