Python Selenium Webdriver无法滚动div内元素获取完整输出
Selenium爬取SubGraph数据截断问题的代码疏漏分析
现存核心疏漏
- 滚动逻辑完全失效
- 调用
find_elements获取到的是WebElement列表,直接将列表传入execute_script作为参数,JS无法直接解析元素列表执行滚动操作 scrollIntoView()仅能实现页面级滚动,将目标元素对齐到视口,无法操作结果区域的内部滚动条。SubGraph页面的返回结果是在独立的CodeMirror容器内滚动,长内容不会随页面滚动加载
- 调用
- 等待逻辑不可靠
- 硬编码的
sleep()固定等待完全依赖经验值,网络波动、接口响应慢时会在结果未完全返回时就执行取数,直接导致内容截断;响应快时又会无意义浪费等待时间
- 硬编码的
- 取数逻辑存在天然缺陷
- CodeMirror编辑器默认使用虚拟滚动优化性能,不在容器可视区域的内容行不会被渲染到DOM树中,哪怕元素存在于页面,未渲染的行也无法通过
.text属性获取到
- CodeMirror编辑器默认使用虚拟滚动优化性能,不在容器可视区域的内容行不会被渲染到DOM树中,哪怕元素存在于页面,未渲染的行也无法通过
- 窗口配置加剧截断问题
- 设置的
window-size=800,600窗口尺寸过小,结果区域的可视高度有限,单次渲染的内容行数更少,进一步提升了截断概率
- 设置的
修正方案
优先推荐直接拦截接口响应的方式,完全不需要操作DOM、处理滚动,拿到的数据100%完整无截断;如果需要保留DOM操作逻辑,就正确操作结果容器的内部滚动条。
修正后参考代码
from selenium.webdriver.chrome.service import Service from selenium.webdriver.chrome.options import Options from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from webdriver_manager.chrome import ChromeDriverManager from selenium import webdriver import json def find_datasets(): datasets_url = [] s = Service(ChromeDriverManager().install()) options = Options() options.headless = False # 调大窗口尺寸,增加结果区域可视范围 options.add_argument('window-size=1920,1080') driver = webdriver.Chrome(service=s, options=options) # 开启网络监听,用于捕获接口返回 driver.execute_cdp_cmd("Network.enable", {}) resp_result = {} # 监听接口响应,直接拿到完整返回数据 def capture_resp(request_id): try: resp = driver.execute_cdp_cmd("Network.getResponseBody", {"requestId": request_id}) # 识别graphql接口返回 if "pools" in resp.get("body", ""): resp_result["data"] = json.loads(resp["body"]) except: pass driver.on("Network.responseReceived", lambda r: capture_resp(r["requestId"])) driver.get("https://v4.subgraph.polygon.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph/graphql?query=%7B%0A%20%20pools(orderBy%3A%20createdTimestamp%2C%20orderDirection%3A%20desc)%20%7B%0A%20%20%20%20id%0A%20%20%20%20datatoken%20%7B%0A%20%20%20%20%20%20address%0A%20%20%20%20%7D%0A%20%20%20%20publishMarketSwapFee%0A%20%20%20%20liquidityProviderSwapFee%0A%20%20%7D%0A%7D%0A") wait = WebDriverWait(driver, 20) # 等执行按钮可点击再点击,替代固定sleep execute_btn = wait.until(EC.element_to_be_clickable((By.XPATH, "//button[contains(@class, 'execute-button')]"))) execute_btn.click() # 等接口返回拿到完整数据 wait.until(lambda d: "data" in resp_result.keys()) full_data = resp_result["data"] print("完整返回数据:", full_data) # 如果一定要从DOM取内容,执行以下滚动逻辑,替代原来的scrollIntoView # # 定位结果区域的内部滚动容器 # result_scroll_container = wait.until(EC.presence_of_element_located((By.XPATH, "//div[contains(@class, 'result-window')]//div[contains(@class, 'CodeMirror-scroll')]"))) # # 持续滚动到底部,直到滚动高度不再变化,确保所有行渲染完成 # last_height = 0 # while True: # current_height = driver.execute_script("return arguments[0].scrollHeight", result_scroll_container) # if current_height == last_height: # break # last_height = current_height # driver.execute_script("arguments[0].scrollTop = arguments[0].scrollHeight", result_scroll_container) # # 滚动完成后再取文本 # result_text = driver.find_element(By.XPATH, "//div[contains(@class, 'result-window')]").text # print(result_text) driver.get_screenshot_as_file("screenshot.png") driver.quit() return full_data find_datasets()
如果只是需要拿SubGraph的查询数据,甚至不需要用Selenium模拟浏览器操作,直接构造POST请求调用GraphQL接口即可,代码量更少、效率更高,完全不会遇到DOM渲染、滚动相关的问题。
内容的提问来源于stack exchange,提问作者giacomomaraglino
相关产品推荐
相关产品推荐

