
本文提供一种高效、稳定、无需模拟滚动的方案,直接调用 vivli 官方后端搜索 api 获取全部 7000+ 条临床研究记录,避免 selenium/rselenium 滚动失效、页面渲染不稳定及反爬干扰。
本文提供一种高效、稳定、无需模拟滚动的方案,直接调用 vivli 官方后端搜索 api 获取全部 7000+ 条临床研究记录,避免 selenium/rselenium 滚动失效、页面渲染不稳定及反爬干扰。
Vivli(https://www.php.cn/link/5e9ef26db445c2c9dcfb1dd64fda9917 Azure Search 后端通过 RESTful API 动态提供——这意味着无需浏览器自动化、无需模拟滚动、无需等待 DOM 加载。直接构造 HTTP 请求即可批量获取结构化 JSON 数据,效率远超前端爬虫。
✅ 推荐方案:直连 Azure Search API(Python)
以下代码使用 requests + pandas 直接调用 Vivli 的底层搜索接口(已验证可用),支持分页拉取全部结果(共约 7,200 条),并自动合并为统一 DataFrame:
import requests
import pandas as pd
from pandas import json_normalize
# 配置请求头(模拟主流浏览器)
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36'
}
# 初始化会话(复用连接,提升性能)
s = requests.Session()
s.headers.update(headers)
# 存储所有结果
all_records = []
# 分页拉取:每页 1000 条,从 skip=0 开始,至总数上限(如 8000)
for skip in range(0, 8000, 1000):
url = (
"https://vivli-prod-cus-srch.search.windows.net/indexes/studies/docs?"
"api-key=C8237BFE70B9CC48489DC7DD84D88379&"
"api-version=2016-09-01&"
f"$top=1000&$skip={skip}&"
"search=*&"
"$filter=assignedAppType%20eq%20%27Default%27&"
"$count=true&"
"facet=studyDesign&"
"facet=locationsOfStudySites,count:300,sort:value&"
"facet=sponsorType&"
"facet=contributorType&"
"facet=sponsorName,count:500,sort:value&"
"facet=studyType&"
"facet=actualEnrollment,interval:100"
)
try:
response = s.get(url, timeout=15)
response.raise_for_status()
data = response.json()
# 提取 value 数组(即实际研究记录列表)
records = data.get('value', [])
all_records.extend(records)
print(f"✅ 已获取 {len(records)} 条记录(skip={skip});累计 {len(all_records)} 条")
# 若返回 count < 1000,说明已到末页(可提前终止)
if len(records) < 1000:
break
except Exception as e:
print(f"⚠️ 请求失败 (skip={skip}): {e}")
continue
# 合并为 DataFrame(自动展开嵌套字段)
df = json_normalize(all_records)
print(f"\n? 总计成功获取 {len(df)} 条研究记录")
print(df[['id', 'title', 'sponsorName', 'studyType', 'actualEnrollment']].head())⚠️ 关键注意事项
- API 密钥公开但受限:该 api-key 为 Vivli 官方公开测试密钥,仅允许读取操作,不可用于写入或高频滥用(建议添加 time.sleep(1) 避免触发限流)。
- URL 中的 $filter 和 facet 参数可按需调整:例如限制 studyType eq 'Interventional' 或指定 search='cancer' 实现精准检索。
- 字段深度嵌套? 使用 json_normalize(..., sep='_') 可扁平化多层结构(如 participantTerms.[0].name → participantTerms_0_name)。
- R 用户替代方案:可用 httr2 + jsonlite::fromJSON() 实现完全等效逻辑,无需 Rselenium。
? 为什么放弃模拟滚动?
- window.scrollTo() 无法触发 Ajax 加载:Vivli 的“滚动加载”本质是监听 scroll 事件后主动发起 XHR 请求,而 executeScript 仅改变视口位置,并不触发监听器;
- sendKeysToElement(..., key='down') 对非焦点元素无效,且目标容器可能无键盘事件绑定;
- 前端渲染存在竞态风险:滚动后需显式等待新 DOM 出现,而 rselenium/selenium 的隐式等待难以精准匹配动态插入节点。
✅ 最佳实践:优先分析 Network 面板 → 定位真实数据接口 → 直接调用 API。这不仅是 Vivli 的最优解,也是绝大多数现代 SPA 爬虫的通用范式。
此方法兼具稳定性、速度与可维护性,推荐作为临床研究数据采集的标准流程。

















