如何抓取动态渲染页面?Uniswap核心数据抓取失败求助
解决Uniswap信息站数据抓取的元素定位问题
问题根源
- 动态渲染的SPA页面:Uniswap信息站是React构建的单页应用,核心数据通过AJAX动态加载,直接获取
page_source时可能内容还未渲染完成。 - 错误的无头模式参数:代码中
--headlesss多了一个s,导致无头模式未正确启用;即使启用,未设置窗口大小也可能引发页面布局异常,元素无法正常渲染。 - 无效的元素定位方式:使用的
sc-jKJlTe sc-hMqMXs sc-hSdWYo eJnjNO是CSS Modules生成的动态类名,每次部署都会变化,无法稳定定位元素。 - 错误的等待逻辑:
WebDriverWait(driver, 20)仅声明了等待对象,但未指定等待条件(如元素可见),等同于未等待数据加载。
解决方案
1. 修正无头模式参数
将错误的--headlesss改为--headless=new(Chrome 112+推荐的新无头模式,兼容性更好),同时添加窗口大小参数避免布局异常:
options.add_argument('--headless=new') options.add_argument('--window-size=1920x1080')
2. 实现正确的等待逻辑
通过WebDriverWait配合expected_conditions,等待目标元素加载完成后再获取页面源码,确保数据渲染完毕。
3. 换用稳定的元素定位方式
优先使用页面提供的data-testid属性(查看开发者工具可知,Volume、Fees、TVL的容器分别对应stat-card-volume、stat-card-fees、stat-card-tvl),这类属性专为测试/爬虫设计,稳定性远高于动态类名。
修改后的完整代码
''' THIS CODE WILL BE USED TO EXTRACT ETHERIUM DATA FROM UNISWAP V3 SITE ''' # import required files from selenium import webdriver from selenium.webdriver.chrome.options import Options from selenium.webdriver.chrome.service import Service from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By from bs4 import BeautifulSoup as BSoup # base url eth_uniswap_url = 'https://info.uniswap.org/#/' # function to get driver def get_driver(): options = Options() options.add_argument('--no-sandbox') options.add_argument('--headless=new') # 修正无头模式参数 options.add_argument('--disable-dev-shm-usage') options.add_argument('--window-size=1920x1080') # 添加窗口大小,避免布局异常 webdriver_service = Service("D:\Software\Selenium WebDrivers\chrome_v107\chromedriver_win32\chromedriver.exe") driver = webdriver.Chrome(options=options, service=webdriver_service) return driver # function to open site def access_site(driver,url): driver.get(url) # 等待目标元素加载完成,确保数据渲染完毕 WebDriverWait(driver, 20).until( EC.presence_of_element_located((By.DATA_TEST_ID, "stat-card-volume")) ) bs_Object = BSoup(driver.page_source, 'html.parser') return bs_Object if __name__ == '__main__': print('We are going to create the driver') driver = get_driver() print('We are now going to access the page') site_access = access_site(driver, eth_uniswap_url) # 使用data-testid定位核心数据卡片,稳定性更高 volume_card = site_access.find('div', {'data-testid': 'stat-card-volume'}) fees_card = site_access.find('div', {'data-testid': 'stat-card-fees'}) tvl_card = site_access.find('div', {'data-testid': 'stat-card-tvl'}) # 提取数值和标签文本 def extract_stat(card): if card: value = card.select_one('div.sc-hKgILt').text label = card.select_one('div.sc-hAZoDl').text return f"{label}: {value}" return "未找到对应数据" print(extract_stat(volume_card)) print(extract_stat(fees_card)) print(extract_stat(tvl_card)) driver.quit() # 关闭浏览器,释放资源
额外说明
- 如果
data-testid发生变化,可改用XPath根据文本定位,示例:volume_value = WebDriverWait(driver,20).until(EC.presence_of_element_located((By.XPATH, "//div[contains(text(), 'Volume')]/../div[1]"))).text - 确保ChromeDriver版本与本地Chrome浏览器版本完全匹配,避免兼容性报错。
内容的提问来源于stack exchange,提问作者Steel8
相关产品推荐
相关产品推荐

