> ## Content Index
> Fetch the complete content index at: https://blog.vercanti.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# DrissionPage 完全指南
- URL: https://blog.vercanti.com/drissionpage-wan-quan-zhi-nan/
- Published: 2026-08-28T14:34:40.000Z
- Updated: 2026-08-28T14:57:03.000Z
- Description: 相关文档：Selenium完全指南(/selenium-wan-quan-zhi-nan/) Scrapy分布式采集(/scrapy-fen-bu-shi-cai-ji-wan-quan-zhi-nan/) httpx完全指南(/httpx-wan-quan-zhi-nan/) DrissionPage 是国产的新一代网页自动化工具，融合了浏览器控制和请求发送两种模式： 核心优势： DrissionPage 提供统一的定位语法，比 Selenium 的 find_element(By.XXX) 更简洁。 WebPage 是 DrissionPage 最强
- Author: yellowdog
- Tags: Python, 框架与库

> 官方文档：<https://drissionpage.cn/>  
> 适用版本：DrissionPage 4.x（2026-05-07 核实）

相关文档：[Selenium完全指南](https://blog.vercanti.com/selenium-wan-quan-zhi-nan/) [Scrapy分布式采集](https://blog.vercanti.com/scrapy-fen-bu-shi-cai-ji-wan-quan-zhi-nan/) [httpx完全指南](https://blog.vercanti.com/httpx-wan-quan-zhi-nan/)

---

## 1\. 基础概念

### DrissionPage 是什么

DrissionPage 是国产的新一代网页自动化工具，融合了浏览器控制和请求发送两种模式：

| 模式            | 说明                                       |
| ------------- | ---------------------------------------- |
| ChromiumPage  | 控制 Chromium 浏览器（类 Selenium，但更稳定、API 更简洁） |
| WebPage（d 模式） | 浏览器控制模式（同 ChromiumPage）                  |
| WebPage（s 模式） | 纯 requests 模式（复用浏览器 cookies）             |
| SessionPage   | 纯 requests 封装，无浏览器                       |

核心优势：

- **d/s 模式一键切换**：浏览器模式登录获取 cookie，切到 requests 模式高速采集
- **元素定位更简洁**：支持语义化选择器，比 XPath/CSS 更易读
- **无需 WebDriver**：直接通过 CDP 协议控制 Chrome，更稳定
- **内置等待机制**：自动等待元素出现，无需手动 sleep

### 安装

```bash
pip install DrissionPage

# 首次使用自动下载 Chromium（或指定已有 Chrome 路径）

```

---

## 2\. ChromiumPage — 浏览器控制

### 基础启动

```python
from DrissionPage import ChromiumPage, ChromiumOptions

# 直接启动（自动管理浏览器）
page = ChromiumPage()
page.get("https://example.com")
page.quit()

# 自定义配置
options = ChromiumOptions()
options.headless(False)               # 显示浏览器
options.set_argument("--no-sandbox")
options.set_user_data_path("/tmp/chrome_profile")  # 使用已有 profile（含登录状态）

page = ChromiumPage(options)

```

### ChromiumOptions 常用参数

| 方法                          | 说明             |
| --------------------------- | -------------- |
| headless(True/False)        | 无头模式           |
| no\_imgs(True)              | 不加载图片（加速）      |
| mute(True)                  | 静音             |
| set\_argument(arg)          | 添加启动参数         |
| set\_user\_data\_path(path) | 指定用户数据目录       |
| set\_proxy(proxy)           | 设置代理           |
| set\_local\_port(port)      | 指定调试端口         |
| auto\_port(True)            | 自动分配端口（多实例时必用） |

---

## 3\. 元素定位

DrissionPage 提供统一的定位语法，比 Selenium 的 `find_element(By.XXX)` 更简洁。

### 定位方法

```python
page.get("https://example.com")

# 通过 CSS 选择器（默认，以 # 开头为 id，以 . 开头为 class）
ele = page.ele("#username")
ele = page.ele(".btn-primary")
ele = page.ele("input[name='email']")

# 通过文本内容（精确匹配）
ele = page.ele("登录")

# 通过文本包含
ele = page.ele("text:登录")
ele = page.ele("text^:登录")  # 以"登录"开头

# 通过 XPath
ele = page.ele("xpath://div[@class='content']")

# 通过属性
ele = page.ele("@name=username")
ele = page.ele("@type=submit")

# 通过 tag + 属性
ele = page.ele("tag:input@name=email")

# 查找多个元素
eles = page.eles("tag:li")
eles = page.eles(".item")

```

### 相对定位

```python
# 父元素
parent = ele.parent()
parent = ele.parent(2)       # 上两级父元素
parent = ele.parent("div")   # 向上找第一个 div 祖先

# 子元素
child = ele.child()          # 第一个子元素
child = ele.child(2)         # 第二个子元素
child = ele.child("span")    # 第一个 span 子元素
children = ele.children()    # 所有子元素

# 兄弟元素
next_ele = ele.next()
prev_ele = ele.prev()

```

---

## 4\. 元素操作

```python
# 点击
ele.click()
ele.click(by_js=True)      # JS 点击（绕过遮罩层）

# 输入文本
ele.input("hello world")
ele.clear()                # 清空
ele.input("hello", clear=True)  # 清空后输入

# 获取属性和文本
text = ele.text            # 文本内容（去除 HTML 标签）
html = ele.inner_html      # innerHTML
attr = ele.attr("href")    # 获取属性值
src = ele.attr("src")

# 获取元素状态
ele.is_displayed           # 是否可见
ele.is_enabled             # 是否可用
ele.is_checked             # 复选框是否选中

# 下拉框
ele.select.by_text("选项文本")
ele.select.by_value("value")
ele.select.by_index(1)

```

---

## 5\. 页面操作

```python
# 导航
page.get("https://example.com")
page.back()
page.forward()
page.refresh()

# 等待
page.wait.load_start()     # 等待页面开始加载
page.wait.doc_loaded()     # 等待文档加载完成
page.wait.ele_displayed("#result")   # 等待元素出现
page.wait.ele_deleted("#loading")    # 等待元素消失
page.wait(2)               # 等待 2 秒

# 滚动
page.scroll.to_bottom()    # 滚动到底部
page.scroll.to_top()
page.scroll.down(300)      # 向下滚动 300px
ele.scroll.to_see()        # 滚动直到元素可见

# JS 执行
result = page.run_js("return document.title")
page.run_js("window.scrollTo(0, document.body.scrollHeight)")

# 截图
page.get_screenshot(path="screenshot.png")
ele.get_screenshot(path="element.png")

# Cookie
cookies = page.cookies()
page.set.cookies({"name": "value"})

# 标签页管理
new_tab = page.new_tab("https://example.com")
page.close()
tabs = page.tab_ids

```

---

## 6\. WebPage — d/s 模式切换（核心功能）

`WebPage` 是 DrissionPage 最强大的特性：浏览器模式获取登录态，无缝切换到请求模式高速采集。

```python
from DrissionPage import WebPage

page = WebPage()

# === d 模式（浏览器控制）===
# 模拟登录，获取 cookie
page.get("https://example.com/login")
page.ele("#username").input("myuser")
page.ele("#password").input("mypass")
page.ele("button[type=submit]").click()
page.wait.url_change("https://example.com/dashboard")

# 此时浏览器已登录，cookies 自动同步到 s 模式

# === 切换到 s 模式（纯 requests，速度快 10 倍以上）===
page.change_mode("s")

# 用 requests 模式采集数据（自动携带浏览器的 cookies）
for i in range(1, 100):
    page.get(f"https://example.com/api/list?page={i}")
    data = page.json  # 直接解析 JSON
    print(data)

# 遇到需要 JS 渲染的页面再切回 d 模式
page.change_mode("d")

```

### SessionPage — 纯请求模式

```python
from DrissionPage import SessionPage

page = SessionPage()

# 类似 requests.Session，但 API 更统一
page.get("https://httpbin.org/get", params={"key": "value"})
print(page.json)

page.post("https://httpbin.org/post", json={"name": "Alice"})
print(page.response.status_code)

# 设置 headers
page.set.headers({"User-Agent": "Mozilla/5.0 ..."})
page.set.cookies({"session": "abc123"})

```

---

## 7\. 监听网络请求（数据包监听）

```python
from DrissionPage import ChromiumPage

page = ChromiumPage()

# 监听指定 URL 的请求（精确捕获 Ajax 数据）
page.listen.start("api/list")

page.get("https://example.com")
page.ele("button.load-more").click()

# 等待并获取数据包
packet = page.listen.wait()
print(packet.response.body)  # 响应体（JSON 数据）
print(packet.response.headers)
print(packet.url)

# 停止监听
page.listen.stop()

```

### 批量监听

```python
page.listen.start("api/")

for _ in range(10):
    page.ele(".next-page").click()
    packet = page.listen.wait()
    data = packet.response.body
    process(data)

```

---

## 8\. 多标签页 / 多实例

```python
from DrissionPage import ChromiumPage, ChromiumOptions

# 多标签页
page = ChromiumPage()
tab1 = page  # 当前标签页
tab2 = page.new_tab("https://example.com/page2")

# 在不同标签页操作
tab1.ele(".item").click()
tab2.ele(".other").click()

# 多浏览器实例（爬虫并发）
from DrissionPage import ChromiumOptions

options = ChromiumOptions().auto_port()  # 自动分配端口

page1 = ChromiumPage(options)
page2 = ChromiumPage(options)

```

---

## 9\. 反检测

```python
from DrissionPage import ChromiumOptions

options = ChromiumOptions()

# 去除 webdriver 标记
options.set_argument("--disable-blink-features=AutomationControlled")

# 设置真实 User-Agent
options.set_user_agent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...")

# 使用真实浏览器 Profile（含登录状态和历史记录）
options.set_user_data_path("/path/to/real/chrome/profile")

page = ChromiumPage(options)

# 注入 JS 隐藏 webdriver 特征
page.run_js("""
    Object.defineProperty(navigator, 'webdriver', {get: () => undefined});
""")

```

---

## 10\. 最佳实践

### 元素定位失败处理

```python
# 默认等待 10 秒，可调整
ele = page.ele("#result", timeout=30)
if ele:
    print(ele.text)
else:
    print("元素未找到")

# 关闭等待（立即返回，找不到返回 None）
ele = page.ele("#result", timeout=0)

```

### 组合 ChromiumPage 与 requests（最高效模式）

```python
import httpx
from DrissionPage import ChromiumPage

page = ChromiumPage()
# 浏览器登录...
cookies = {c["name"]: c["value"] for c in page.cookies()}

# 用 httpx 高并发采集（复用 cookies）
async with httpx.AsyncClient(cookies=cookies) as client:
    tasks = [client.get(f"/api/data?id={i}") for i in range(100)]
    results = await asyncio.gather(*tasks)

```

---

## 11\. 踩坑与注意事项

### 元素定位优先用属性而非 XPath

DrissionPage 的属性定位比 XPath 更稳定，不受 DOM 层级变化影响：

```python
# 不推荐（结构变化就失效）
page.ele("xpath://div[2]/form/input[1]")

# 推荐（语义稳定）
page.ele("@name=username")
page.ele("tag:input@placeholder=请输入用户名")

```

### 多实例必须用 auto\_port

同时启动多个 ChromiumPage 时，不指定 `auto_port()` 会端口冲突：

```python
options = ChromiumOptions().auto_port()
page = ChromiumPage(options)

```

---

## 最佳实践

**优先用 `ele()` \+ `eles()` 取元素，而非 XPath 字符串拼接**：DrissionPage 支持 `@属性名=值`、`text:文字` 等简洁定位语法，比长串 XPath 更易维护。

```python
# 推荐：简洁语法
btn = page.ele('@class=submit-btn')
inputs = page.eles('tag:input@type=text')
link = page.ele('text:立即登录')

# 低效：长 XPath
btn = page.ele('xpath://div[@class="form"]/button[@class="submit-btn"]')

```

**接管已有浏览器调试现有页面**：DrissionPage 可以接管用调试模式打开的浏览器，无需重新登录。

```python
# 启动 Chrome 时加 --remote-debugging-port=9222
# chrome --remote-debugging-port=9222

options = ChromiumOptions().set_local_port(9222)
page = ChromiumPage(options)  # 接管已有浏览器

```

**等待元素用 `wait()` 而非 `time.sleep()`**：固定 sleep 导致不必要的等待或在慢网络下不够等。`wait.ele_loaded()` 等待元素出现后立即继续。

```python
# 正确：等待元素出现
page.wait.ele_loaded('#content', timeout=10)
ele = page.ele('#content')

# 低效：固定等待
import time
time.sleep(3)
ele = page.ele('#content')

```

**用 `SessionPage` 处理纯 HTTP 请求以节省资源**：不需要 JS 渲染的页面（静态 HTML、接口）用 `SessionPage` 比 `ChromiumPage` 快 10 倍以上，且不消耗浏览器资源。

**Chromium 无头模式加 `--no-sandbox`**：Docker 容器中运行必须加 `--no-sandbox`，否则启动失败。

```python
options = ChromiumOptions().headless(True).set_argument('--no-sandbox')

```

---

## 常见陷阱

### 陷阱：ChromiumPage 多实例端口冲突

**现象：** 同时创建多个 `ChromiumPage` 时，第二个实例报端口被占用的错误。

**原因：** DrissionPage 默认使用固定端口（9222）连接 Chromium，多实例时端口冲突。

**解决：** 创建每个实例时调用 `options.auto_port()` 让系统自动分配空闲端口。

```python
def make_page():
    opts = ChromiumOptions().auto_port()
    return ChromiumPage(opts)

page1, page2 = make_page(), make_page()

```

---

### 陷阱：`ele()` 找不到元素时返回 NoneType 而非抛异常

**现象：** 代码中 `page.ele('#btn').click()` 偶发 `AttributeError: 'NoneType' object has no attribute 'click'`。

**原因：** 元素不存在时 `ele()` 默认返回 `None`，不抛异常，直接调用方法会 AttributeError。

**解决：** 先检查返回值是否为 `None`，或使用 `wait.ele_loaded()` 确保元素已加载。

```python
btn = page.ele('#btn', timeout=5)
if btn:
    btn.click()
# 或
page.wait.ele_loaded('#btn', timeout=5).click()

```

---

### 陷阱：文件上传不能用 `.click()` \+ 文件对话框

**现象：** 点击上传按钮后弹出系统文件选择对话框，DrissionPage 无法操控该对话框。

**原因：** 系统原生文件对话框不是网页元素，无法通过 DOM 操控。

**解决：** 直接对 `<input type="file">` 元素调用 `.input()` 传入文件路径，或使用 `set_file_input()` 方法。

```python
# 正确：直接设置 input[type=file] 的值
file_input = page.ele('tag:input@type=file')
file_input.input('C:/path/to/file.jpg')

```

---

## 参见

- [Selenium完全指南](https://blog.vercanti.com/selenium-wan-quan-zhi-nan/)
- [Playwright完全指南](https://blog.vercanti.com/playwright-wan-quan-zhi-nan/)
- [Scrapy分布式采集](https://blog.vercanti.com/scrapy-fen-bu-shi-cai-ji-wan-quan-zhi-nan/)
- [httpx完全指南](https://blog.vercanti.com/httpx-wan-quan-zhi-nan/)