使用Selenium爬取CoinMarketCap Uniswap V2数据出现行缺失问题求解
问题原因分析
- 虚拟滚动机制:CoinMarketCap的交易对表格采用虚拟滚动设计,仅会渲染当前可视区域及附近的数十行DOM节点,滚动出可视区的行会被自动销毁。你当前等待所有加载完成后一次性提取全量元素的逻辑,本身只能拿到当前渲染的部分数据,无法获取全量1853行。
- 滚动逻辑缺陷:你仅在页面初始化时计算了一次
total_height,后续点击「Load More」加载更多数据后页面总高度会持续升高,但你依然使用初始高度值执行滚动,导致无法滚动到最新的页面底部,无法触发中间行的渲染,因此出现行号跳跃的问题。 - 固定等待不可靠:全使用固定的
time.sleep控制等待时长,不同网络环境下页面渲染速度波动大,很容易出现还未等行渲染完成就继续滚动的情况,导致中间行未被捕获就被跳过。
修复方案与完整代码
调整为边滚动边收集数据的逻辑,每次滚动到新区域待行渲染完成后就立刻提取数据存入本地列表,同时自动去重;每次点击「Load More」后重新计算页面高度,直到加载完所有1853行数据为止。
from selenium import webdriver from webdriver_manager.chrome import ChromeDriverManager import time from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By driver = webdriver.Chrome(ChromeDriverManager().install()) driver.maximize_window() driver.get('https://coinmarketcap.com/exchanges/uniswap-v2/') wait = WebDriverWait(driver, 10) # 先关闭cookie弹窗 try: wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, 'div.cmc-cookie-policy-banner__close'))).click() except: pass results = [] exist_ranks = set() target_count = 1853 while len(results) < target_count: # 每次滚动前先获取当前页面总高度 total_height = int(driver.execute_script("return document.body.scrollHeight")) # 逐段滚动,每次滚动后提取数据 for i in range(1, total_height, 200): driver.execute_script("window.scrollTo(0, {});".format(i)) time.sleep(0.5) # 提取当前渲染的所有行数据 try: ranks = driver.find_elements(By.CSS_SELECTOR, 'td.cmc-table__cell.cmc-table__cell--sticky.cmc-table__cell--sortable.cmc-table__cell--left.cmc-table__cell--sort-by__rank > div') names = driver.find_elements(By.CSS_SELECTOR, 'div.cwwgik-0.bCvAgC') pairs = driver.find_elements(By.CSS_SELECTOR, 'div.hmd6df-0.kCRNNr') volumes = driver.find_elements(By.CSS_SELECTOR, 'div.cmc-table__column-market-pair-volume-24h') vol_percents = driver.find_elements(By.CSS_SELECTOR, 'div.cmc-table__column-market-pair-volume-percent') liquidity = driver.find_elements(By.CSS_SELECTOR, 'td.cmc-table__cell.cmc-table__cell--sortable.cmc-table__cell--right.cmc-table__cell--sort-by__quote-usd-effective-liquidity > div') fee_types = driver.find_elements(By.CSS_SELECTOR, 'td.cmc-table__cell.cmc-table__cell--sortable.cmc-table__cell--right.cmc-table__cell--sort-by__fee-type > div') recency = driver.find_elements(By.CSS_SELECTOR, 'div.ghkc60-0.fLaXDt') # 遍历当前行,去重存入结果 for idx in range(len(ranks)): try: rank = ranks[idx].get_attribute("innerText").strip() if not rank or rank in exist_ranks: continue row_data = f"{rank} {names[idx].get_attribute('innerText')} {pairs[idx].get_attribute('innerText')} {volumes[idx].get_attribute('innerText')} {vol_percents[idx].get_attribute('innerText')} {liquidity[idx].get_attribute('innerText')} {fee_types[idx].get_attribute('innerText')} {recency[idx].get_attribute('innerText')}" results.append(row_data) exist_ranks.add(rank) # 达到目标数量直接退出 if len(results) >= target_count: break except: continue if len(results) >= target_count: break except: continue if len(results) >= target_count: break # 点击加载更多 try: load_more_btn = wait.until(EC.element_to_be_clickable((By.XPATH, '//button[text() = "Load More"]'))) load_more_btn.click() time.sleep(2) except: # 找不到加载更多按钮说明已经到最后一页,退出循环 break # 输出结果 print(f"共获取到{len(results)}行数据") for row in results: print(row)
内容的提问来源于stack exchange,提问作者user16028670
相关产品推荐
相关产品推荐

