Python使用Selenium等工具爬取动态网页无法获取完整文本问题求助
可行解决方案
方案1:直接抓取后端接口(最优推荐)
该站点的所有卡片数据都是通过GraphQL接口动态拉取的,不需要解析前端渲染的HTML,直接请求接口就能拿到结构化的全量数据,是效率最高、最稳定的方案。
操作逻辑:
- 打开浏览器F12开发者工具,切换到「网络」面板,筛选「Fetch/XHR」请求,刷新页面后找到名称带
graphql的列表请求 - 复制该请求的请求头、请求参数,直接用requests库模拟请求即可,返回的JSON数据里直接包含所有套餐的ID、名称、份额、购买链接等所有需要的字段
- 定时请求接口后,对比两次返回的套餐ID列表的差异,就能直接判断是否有新套餐上线
示例代码:
import requests import time # 接口地址 url = "https://staking.pocketfives.com/api/graphql" # 复制浏览器里的请求头,主要保证user-agent和浏览器一致即可 headers = { "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36", "content-type": "application/json" } # 复制浏览器里的请求体参数,即查询套餐列表的GraphQL语句 payload = { "operationName": "getStakeListings", "variables": {"page":1,"limit":100,"filter":{"type":"all","sort":"newest","search":"","tournamentSite":"","gameType":"","stakeType":"","buyin":{"min":0,"max":10000},"return":{"min":0,"max":100},"markup":{"min":0,"max":100},"sold":{"min":0,"max":100}}}, "query": "query getStakeListings($page: Int, $limit: Int, $filter: StakeListingFilter) {\n stakeListings(page: $page, limit: $limit, filter: $filter) {\n items {\n id\n title\n buyinAmount\n markupPercent\n totalSoldPercent\n __typename\n }\n total\n __typename\n }\n}\n" } *注:如果接口返回异常,可以重新从浏览器里复制最新的请求头和请求体参数替换即可,一般只要User-Agent和请求体的查询语句正确就能正常返回。* # 存储上一次的套餐ID集合 last_ids = set() while True: resp = requests.post(url, json=payload, headers=headers) data = resp.json() current_list = data['data']['stakeListings']['items'] current_ids = set([item['id'] for item in current_list]) # 第一次运行初始化ID集合 if not last_ids: last_ids = current_ids print(f"初始化完成,当前共有{len(current_list)}个套餐") else: new_ids = current_ids - last_ids if new_ids: print(f"检测到新套餐上线,ID为:{new_ids}") # 此处可自行添加提醒逻辑,比如发邮件、企业微信/钉钉通知等 last_ids = current_ids else: print("暂无新套餐上线") # 每10分钟检查一次,可自行调整间隔时长 time.sleep(600)
该方案不需要启动浏览器,资源占用极低,也不会出现内容加载不全的问题。
方案2:优化Selenium实现(如果一定要用浏览器渲染的话)
之前的写法问题在于用复制粘贴的方式拿内容,且固定sleep无法保证内容完全加载,优化后的写法直接从渲染后的DOM里提取卡片元素,用显式等待保证元素加载完成:
示例代码:
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 from webdriver_manager.chrome import ChromeDriverManager import time # 启动无头模式,不需要打开浏览器窗口 options = webdriver.ChromeOptions() options.add_argument("--headless=new") options.add_argument("--user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36") driver = webdriver.Chrome(ChromeDriverManager().install(), options=options) driver.get("https://staking.pocketfives.com/staking/market-place") wait = WebDriverWait(driver, 20) # 等待卡片元素加载出来 wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, ".stake-listing-card"))) # 滚动加载所有内容,每次滚动后等待新内容加载 last_height = driver.execute_script("return document.body.scrollHeight") while True: driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") time.sleep(2) new_height = driver.execute_script("return document.body.scrollHeight") if new_height == last_height: break last_height = new_height # 提取所有卡片的内容 cards = driver.find_elements(By.CSS_SELECTOR, ".stake-listing-card") current_data = [] for card in cards: # 提取卡片里需要的字段,比如标题、购买按钮存在与否等 card_text = card.text card_id = card.get_attribute("data-id") # 如果有ID属性可直接提取 current_data.append(card_id if card_id else card_text) driver.quit() # 后续对比两次current_data的差异即可判断是否有新内容上线
内容的提问来源于stack exchange,提问作者Python404
相关产品推荐
相关产品推荐

