当前位置:首页>python>python+playwright权威指南-吐血整理

python+playwright权威指南-吐血整理

  • 2026-03-27 12:00:58
python+playwright权威指南-吐血整理
这部分我们介绍playwright的基础,理论先行;
文档的方向由作者本人拟定,内容由AI和作者一同校对和调整;
# Python + Playwright Web 前端自动化开发完全指南> 从零开始掌握 Playwright 自动化测试 - 元素定位、API 使用、实战场景、调试技巧一站式学习---## 文档版本信息- **版本**: 1.0- **创建日期**: 2024-03-26- **适用版本**: Playwright for Python 1.40+- **目标读者**: 前端自动化测试工程师、测试开发人员---## 目录### 第一部分:基础篇1. [Playwright 简介与环境搭建](#1-playwright-简介与环境搭建)2. [DOM 树与元素定位基础](#2-dom-树与元素定位基础)3. [Playwright 定位 API 总览](#3-playwright-定位-api-总览)### 第二部分:CSS 选择器篇4. [CSS 选择器基础语法](#4-css-选择器基础语法)5. [CSS 属性选择器详解](#5-css-属性选择器详解)6. [CSS 关系选择器与伪类](#6-css-关系选择器与伪类)### 第三部分:XPath 篇7. [XPath 定位法完全指南](#7-xpath-定位法完全指南)8. [XPath 轴定位详解](#8-xpath-轴定位详解)### 第四部分:Playwright API 篇9. [locator() - 通用选择器](#9-locator---通用选择器)10. [get_by_role() - ARIA 角色定位](#10-get_by_role---aria-角色定位)11. [get_by_text() - 文本内容定位](#11-get_by_text---文本内容定位)12. [get_by_label() - Label 关联定位](#12-get_by_label---label-关联定位)13. [get_by_placeholder() - 占位符定位](#13-get_by_placeholder---占位符定位)14. [get_by_alt_text() - 图片 Alt 定位](#14-get_by_alt_text---图片-alt-定位)15. [get_by_title() - Title 定位](#15-get_by_title---title-定位)16. [get_by_test_id() - 测试 ID 定位](#16-get_by_test_id---测试-id-定位)17. [frame_locator() - Iframe 定位](#17-frame_locator---iframe-定位)### 第五部分:高级篇18. [正则表达式与模糊匹配](#18-正则表达式与模糊匹配)19. [filter() 过滤方法高级用法](#19-filter-过滤方法高级用法)20. [动态值定位实战](#20-动态值定位实战)21. [JavaScript 表达式定位](#21-javascript-表达式定位)### 第六部分:实战篇22. [登录页面元素定位](#22-登录页面元素定位)23. [数据表格元素定位](#23-数据表格元素定位)24. [导航菜单元素定位](#24-导航菜单元素定位)25. [模态框/对话框元素定位](#25-模态框对话框元素定位)26. [表单验证错误定位](#26-表单验证错误定位)27. [动态加载内容处理](#27-动态加载内容处理)### 第七部分:技巧篇28. [API 选择决策树](#28-api-选择决策树)29. [元素定位调试技巧](#29-元素定位调试技巧)30. [常见问题与解决方案](#30-常见问题与解决方案)31. [最佳实践与性能优化](#31-最佳实践与性能优化)### 附录- [附录 A: CSS 选择器速查表](#附录-a-css-选择器速查表)- [附录 B: XPath 速查表](#附录-b-xpath-速查表)- [附录 C: Playwright API 速查表](#附录-c-playwright-api-速查表)- [附录 D: 正则表达式速查表](#附录-d-正则表达式速查表)---## 第一部分:基础篇### 1. Playwright 简介与环境搭建#### 1.1 什么是 PlaywrightPlaywright 是由微软开发的开源 Web 自动化测试框架,支持 Chromium、Firefox、WebKit 三大浏览器引擎。**核心特性:**- 🚀 快速、稳定、功能强大- 🌐 跨浏览器、跨平台- 🔧 自动等待、智能重试- 📱 支持移动端模拟- 🎭 支持无头模式和有头模式#### 1.2 环境搭建```bash# 1. 安装 Python 3.8+# 2. 安装 Playwrightpip install playwright# 3. 安装浏览器playwright install# 4. 安装浏览器依赖(Linux)playwright install-deps# 5. 验证安装python -c "from playwright.sync_api import sync_playwright; print('安装成功!')"```#### 1.3 第一个 Playwright 脚本```pythonfrom playwright.sync_api import sync_playwrightwith sync_playwright() as p:    # 启动浏览器    browser = p.chromium.launch(headless=False)    # 创建新页面    page = browser.new_page()    # 访问网页    page.goto('https://example.com')    # 元素定位与操作    page.get_by_role('button', name='More information').click()    # 截图    page.screenshot(path='example.png')    # 关闭浏览器    browser.close()```---### 2. DOM 树与元素定位基础#### 2.1 什么是 DOM 树**DOM(Document Object Model)** 是浏览器解析 HTML 文档后生成的树形数据结构。```HTML 源码                          DOM 树结构─────────────────────────────────────────────────────────<html>                            Document  <head>                          └── html    <title>页面</title>               ├── head  </head>                           │   └── title  <body>                            └── body    <div id="app">                      ├── div#app      <h1>标题</h1>                     │   ├── h1      <p class="text">内容</p>          │   └── p.text    </div>                              └── ...  </body></html>```#### 2.2 HTML、CSS、DOM 的关系| 概念 | 角色 | 作用 ||------|------|------|| **HTML** | 骨架/结构 | 定义网页有什么内容 || **CSS** | 皮肤/样式 | 定义内容长什么样 || **DOM** | 内存对象 | 浏览器解析后的可操作对象 || **选择器** | 地址 | 用来在 DOM 树中定位节点 |#### 2.3 可用于定位的 DOM 属性| 属性类型 | 属性名 | 示例 | 选择器语法 ||----------|--------|------|-----------|| 标签名 | tagName | div, button | `div`, `button` || ID | id | id="submit" | `#submit` || 类名 | class | class="btn" | `.btn` || 任意属性 | data-*, name, type | data-testid="login" | `[data-testid="login"]` || href/src | 链接地址 | href="/home" | `[href="/home"]` || 文本内容 | textContent | 按钮文本 | `:has-text("按钮")` || ARIA 属性 | role, aria-label | role="button" | `[role="button"]` |---### 3. Playwright 定位 API 总览#### 3.1 八大定位 API```┌─────────────────────────────────────────────────────────────────┐│                    Playwright 定位 API                           │├─────────────────────────────────────────────────────────────────┤│  1. locator()              - 通用选择器(CSS/XPath)            ││  2. get_by_role()          - ARIA 角色定位                      ││  3. get_by_text()          - 文本内容定位                       ││  4. get_by_label()         - Label 关联定位                     ││  5. get_by_placeholder()   - 占位符定位                         ││  6. get_by_alt_text()      - 图片 Alt 文本定位                  ││  7. get_by_title()         - Title 属性定位                     ││  8. get_by_test_id()       - 测试 ID 定位                       ││  9. frame_locator()        - Iframe 内元素定位                  │└─────────────────────────────────────────────────────────────────┘```#### 3.2 API 选择优先级```推荐优先级(从高到低):第 1 梯队(最推荐)★★★★★┌─────────────────────────────────────────────────────────────┐│ get_by_test_id()    - 开发配合添加 data-testid 属性          ││ get_by_label()      - 表单元素首选,语义化最好               ││ get_by_role()       - 语义化定位,无障碍友好                 │└─────────────────────────────────────────────────────────────┘第 2 梯队(推荐)★★★★┌─────────────────────────────────────────────────────────────┐│ get_by_placeholder() - 输入框专用,简单直接                 ││ locator(#id)        - 唯一 ID 定位,稳定可靠                │└─────────────────────────────────────────────────────────────┘第 3 梯队(可用)★★★┌─────────────────────────────────────────────────────────────┐│ get_by_alt_text()   - 图片元素专用                           ││ get_by_title()      - 有 title 属性的元素                    ││ get_by_text()       - 文本稳定时可用                         │└─────────────────────────────────────────────────────────────┘第 4 梯队(备选)★★┌─────────────────────────────────────────────────────────────┐│ locator(.class)     - 类名稳定时可用                         ││ locator([attr])     - 属性定位                               │└─────────────────────────────────────────────────────────────┘```#### 3.3 从 HTML 中提取定位参数```python# ===== 示例 HTML ====="""<input    id="username"                    ← 提取:'#username' 或 get_by_label()    class="form-input required"      ← 提取:'.form-input'    name="username"                  ← 提取:'[name="username"]'    type="text"                      ← 提取:'input[type="text"]'    placeholder="请输入用户名"        ← 提取:get_by_placeholder('请输入用户名')    aria-label="用户名"              ← 提取:get_by_role('textbox', name='用户名')    data-testid="username-input"     ← 提取:get_by_test_id('username-input')><label for="username">用户名</label>  ← 提取:get_by_label('用户名')"""```---## 第二部分:CSS 选择器篇### 4. CSS 选择器基础语法#### 4.1 标签选择器```python# 语法:tagname# 匹配所有指定标签的元素page.locator('div')           # 所有 div 元素page.locator('button')        # 所有 button 元素page.locator('input')         # 所有 input 元素page.locator('a')             # 所有 a 链接page.locator('span')          # 所有 span 元素page.locator('table')         # 所有 table 元素page.locator('li')            # 所有 li 元素```#### 4.2 ID 选择器```python# 语法:#id_value# 匹配 id 属性等于指定值的元素(ID 应该唯一)page.locator('#submit-btn')           # id="submit-btn"page.locator('#username')             # id="username"page.locator('button#submit-btn')     # button 标签且 id="submit-btn"```#### 4.3 类选择器```python# 语法:.class_value# 匹配 class 属性包含指定值的元素page.locator('.btn')                    # 所有 class 包含 btn 的元素page.locator('.btn.primary')            # 同时包含 btn 和 primary 类page.locator('button.btn')              # button 标签且有 btn 类page.locator('div.container')           # div 标签且有 container 类```#### 4.4 属性选择器```python# 语法:[attribute]# 匹配具有指定属性的元素page.locator('[type]')                  # 有 type 属性的元素page.locator('[type="text"]')           # type 属性值为 textpage.locator('[name="username"]')       # name 属性值为 usernamepage.locator('[data-testid="login"]')   # data-testid 属性值为 loginpage.locator('[href="/home"]')          # href 属性值为 /homepage.locator('[role="button"]')         # role 属性值为 button```---### 5. CSS 属性选择器详解#### 5.1 精确匹配```python# 语法:[attribute=value]page.locator('[type="text"]')           # type="text"page.locator('[type="password"]')       # type="password"page.locator('[name="username"]')       # name="username"page.locator('[value="提交"]')          # value="提交"page.locator('[href="/home"]')          # href="/home"page.locator('[data-status="active"]')  # data-status="active"```#### 5.2 模糊匹配```python# ===== 包含匹配 [*] =====page.locator('[href*="example"]')       # href 包含 "example"page.locator('[class*="btn"]')          # class 包含 "btn"page.locator('[name*="user"]')          # name 包含 "user"# ===== 开头匹配 [^] =====page.locator('[href^="https"]')         # href 以 "https" 开头page.locator('[href^="/"]')             # href 以 "/" 开头page.locator('[name^="user"]')          # name 以 "user" 开头# ===== 结尾匹配 [$] =====page.locator('[href$=".pdf"]')          # href 以 ".pdf" 结尾page.locator('[class$="-primary"]')     # class 以 "-primary" 结尾page.locator('[id$="-btn"]')            # id 以 "-btn" 结尾```#### 5.3 多属性组合```python# 语法:[attr1=val1][attr2=val2]page.locator('[type="text"][name="username"]')  # type=text 且 name=usernamepage.locator('[type="submit"][class="btn"]')    # type=submit 且 class=btnpage.locator('[type="text"][required]')         # type=text 且有 required```---### 6. CSS 关系选择器与伪类#### 6.1 关系选择器```python# ===== 后代选择器(空格) =====page.locator('.container .btn')         # container 内的所有.btn# ===== 子元素选择器(>) =====page.locator('.menu > .item')           # menu 的直接子元素 item# ===== 相邻兄弟选择器(+) =====page.locator('h2 + p')                  # 紧跟 h2 的 p 元素# ===== 通用兄弟选择器(~) =====page.locator('h2 ~ p')                  # h2 后的所有 p 兄弟```#### 6.2 状态伪类```pythonpage.locator('button:hover')            # 鼠标悬停的按钮page.locator('button:focus')            # 获得焦点的按钮page.locator('input:disabled')          # 禁用的输入框page.locator('input:enabled')           # 启用的输入框page.locator('input:checked')           # 被选中的复选框page.locator('input:required')          # 必填字段page.locator('input:valid')             # 验证通过的字段page.locator('input:invalid')           # 验证失败的字段的```#### 6.3 结构伪类```pythonpage.locator('li:first-child')          # 第一个 lipage.locator('li:last-child')           # 最后一个 lipage.locator('li:nth-child(2)')         # 第 2 个 lipage.locator('li:nth-child(odd)')       # 奇数位置的 lipage.locator('li:nth-child(even)')      # 偶数位置的 lipage.locator('li:not(:first-child)')    # 非第一个 lipage.locator('li:not(.active)')         # 不包含 active 类的 lipage.locator('li:empty')                # 空的 li 元素```#### 6.4 高级伪类```python# :is() - 多选一page.locator(':is(h1, h2, h3)')         # h1、h2 或 h3# :has() - 包含指定子元素page.locator('.card:has(img)')          # 包含 img 的.cardpage.locator('div:has(> .btn)')         # 包含直接子元素.btn 的 div# :not() - 否定page.locator('.btn:not(.disabled)')     # 不包含.disabled 类的.btnpage.locator('button:not([disabled])')  # 不禁用的按钮# :has-text() - 包含文本(Playwright 扩展)page.locator(':has-text("提交")')       # 包含"提交"文本的元素page.locator('button:has-text("取消")'# 包含"取消"文本的 button```---## 第三部分:XPath 篇### 7. XPath 定位法完全指南#### 7.1 XPath 基础语法```python# 在 Playwright 中使用 XPath 需要加 'xpath=' 前缀# ===== 基础 XPath =====page.locator('xpath=//button')                # 所有 button 元素page.locator('xpath=//*[@id="submit"]')       # id="submit" 的元素page.locator('xpath=//*[@class="btn"]')       # class="btn" 的元素# ===== 属性匹配 =====page.locator('xpath=//input[@type="text"]')       # type="text"的 inputpage.locator('xpath=//input[@name="username"]')   # name="username"的 inputpage.locator('xpath=//button[@type="submit"]')    # type="submit"的 button# ===== 文本匹配 =====page.locator('xpath=//button[text()="提交"]')         # 文本精确匹配page.locator('xpath=//button[contains(text(), "提")]')  # 文本包含匹配```#### 7.2 属性模糊匹配```python# ===== contains() - 包含匹配 =====page.locator('xpath=//div[contains(@class, "btn")]')    # class 包含 btnpage.locator('xpath=//a[contains(@href, "home")]')      # href 包含 homepage.locator('xpath=//input[contains(@name, "user")]')  # name 包含 user# ===== starts-with() - 开头匹配 =====page.locator('xpath=//a[starts-with(@href, "/")]')    # href 以/开头page.locator('xpath=//input[starts-with(@name, "user")]')  # name 以 user 开头```#### 7.3 位置索引```pythonpage.locator('xpath=//li[1]')                    # 第 1 个 lipage.locator('xpath=//li[2]')                    # 第 2 个 lipage.locator('xpath=//li[last()]')               # 最后 1 个 lipage.locator('xpath=//li[position()=3]')         # 第 3 个 li```---### 8. XPath 轴定位详解#### 8.1 parent 轴(父元素)```pythonpage.locator('xpath=//input[@id="username"]/parent::*')  # username 的父元素page.locator('xpath=//input[@id="username"]/..')         # username 的父元素(简写)page.locator('xpath=//input[@id="username"]/parent::div')# username 的父 div```#### 8.2 child 轴(子元素)```pythonpage.locator('xpath=//div[@class="container"]/child::button')  # container 的子 buttonpage.locator('xpath=//div[@class="container"]/child::*')       # container 的所有子元素```#### 8.3 ancestor 轴(祖先元素)```pythonpage.locator('xpath=//input[@id="username"]/ancestor::form')   # username 的祖先 formpage.locator('xpath=//input[@id="username"]/ancestor::div')    # username 的祖先 div```#### 8.4 descendant 轴(后代元素)```pythonpage.locator('xpath=//div[@id="app"]/descendant::button')      # app 的后代 buttonpage.locator('xpath=//div[@id="app"]/descendant::*')           # app 的所有后代```#### 8.5 following 轴(之后的元素)```pythonpage.locator('xpath=//label[text()="用户名"]/following::input')    # label 后的 inputpage.locator('xpath=//label[text()="用户名"]/following::input[1]'# label 后的第 1 个 input```#### 8.6 following-sibling 轴(之后的兄弟)```pythonpage.locator('xpath=//h2/following-sibling::p')        # h2 后的所有 p 兄弟page.locator('xpath=//h2/following-sibling::p[1]')     # h2 后的第 1 个 p 兄弟```#### 8.7 preceding-sibling 轴(之前的兄弟)```pythonpage.locator('xpath=//input/preceding-sibling::label')     # input 前的 labelpage.locator('xpath=//input/preceding-sibling::label[1]')  # input 前的第 1 个 label```---## 第四部分:Playwright API 篇### 9. locator() - 通用选择器#### 9.1 API 签名```pythonpage.locator(selector, has=None, has_text=None)```**参数说明:**- `selector` (必需): CSS 选择器或 XPath 表达式- `has` (可选): 必须包含的子元素定位器- `has_text` (可选): 必须包含的文本内容#### 9.2 基础用法```python# CSS 选择器page.locator('#submit-btn')page.locator('.btn-primary')page.locator('button[type="submit"]')# XPath 选择器page.locator('xpath=//button[@type="submit"]')# 组合使用page.locator('form#login button[type="submit"]')```#### 9.3 has 和 has_text 参数```python# has - 必须包含指定子元素card_with_edit = page.locator('.card', has=page.locator('.edit'))# has_text - 必须包含指定文本home_menu = page.locator('.menu-item', has_text='首页')# 组合使用card = page.locator('.card', has=page.locator('.edit'), has_text='卡片')```---### 10. get_by_role() - ARIA 角色定位#### 10.1 API 签名```pythonpage.get_by_role(role, name=None, exact=False)```**参数说明:**- `role` (必需): ARIA 角色名称- `name` (可选): 元素的 Accessible Name- `exact` (可选): 是否精确匹配#### 10.2 常用角色```python# 按钮page.get_by_role('button')page.get_by_role('button', name='提交')# 链接page.get_by_role('link')page.get_by_role('link', name='首页')# 输入框page.get_by_role('textbox')page.get_by_role('textbox', name='用户名')# 复选框page.get_by_role('checkbox')page.get_by_role('checkbox', name='记住我')# 下拉框page.get_by_role('combobox')page.get_by_role('combobox', name='选择城市')# 标题page.get_by_role('heading', level=1)  # h1page.get_by_role('heading', level=2)  # h2# 其他角色page.get_by_role('dialog')            # 对话框page.get_by_role('alert')             # 警告框page.get_by_role('tab')               # 标签页page.get_by_role('menu')              # 菜单page.get_by_role('menuitem')          # 菜单项page.get_by_role('listitem')          # 列表项page.get_by_role('table')             # 表格page.get_by_role('row')               # 表格行page.get_by_role('cell')              # 表格单元格page.get_by_role('navigation')        # 导航page.get_by_role('banner')            # 页眉page.get_by_role('main')              # 主内容page.get_by_role('form')              # 表单page.get_by_role('searchbox')         # 搜索框page.get_by_role('img')               # 图片```---### 11. get_by_text() - 文本内容定位#### 11.1 API 签名```pythonpage.get_by_text(text, exact=False)```**参数说明:**- `text` (必需): 要匹配的文本内容- `exact` (可选): 是否精确匹配,默认 False#### 11.2 用法示例```python# 模糊匹配(默认)page.get_by_text('提交')           # 包含"提交"即可page.get_by_text('登录')           # 包含"登录"即可# 精确匹配page.get_by_text('提交表单', exact=True)    # 必须完全匹配# 链式调用page.get_by_role('button').filter(has_text='提交')```---### 12. get_by_label() - Label 关联定位#### 12.1 API 签名```pythonpage.get_by_label(label_text, exact=False)```**参数说明:**- `label_text` (必需): Label 元素的文本内容- `exact` (可选): 是否精确匹配#### 12.2 用法示例```python# HTML: <label for="username">用户名</label>#       <input id="username" type="text">page.get_by_label('用户名')              # 模糊匹配page.get_by_label('用户名', exact=True)  # 精确匹配# 嵌套 label# HTML: <label>密码<input type="password"></label>page.get_by_label('密码')```---### 13. get_by_placeholder() - 占位符定位#### 13.1 API 签名```pythonpage.get_by_placeholder(placeholder, exact=False)```**参数说明:**- `placeholder` (必需): input 元素的 placeholder 属性值- `exact` (可选): 是否精确匹配#### 13.2 用法示例```python# HTML: <input type="text" placeholder="请输入用户名">page.get_by_placeholder('用户名')              # 模糊匹配page.get_by_placeholder('请输入用户名', exact=True)  # 精确匹配```---### 14. get_by_alt_text() - 图片 Alt 定位#### 14.1 API 签名```pythonpage.get_by_alt_text(alt, exact=False)```**参数说明:**- `alt` (必需): img 元素的 alt 属性值- `exact` (可选): 是否精确匹配#### 14.2 用法示例```python# HTML: <img src="logo.png" alt="公司 Logo">page.get_by_alt_text('Logo')           # 模糊匹配page.get_by_alt_text('公司 Logo', exact=True)  # 精确匹配```---### 15. get_by_title() - Title 定位#### 15.1 API 签名```pythonpage.get_by_title(title, exact=False)```**参数说明:**- `title` (必需): 元素的 title 属性值- `exact` (可选): 是否精确匹配#### 15.2 用法示例```python# HTML: <img src="logo.png" title="公司 Logo">page.get_by_title('Logo')           # 模糊匹配page.get_by_title('公司 Logo', exact=True)  # 精确匹配```---### 16. get_by_test_id() - 测试 ID 定位#### 16.1 API 签名```pythonpage.get_by_test_id(test_id)```**参数说明:**- `test_id` (必需): 元素的 data-testid 属性值#### 16.2 用法示例```python# HTML: <button data-testid="login-btn">登录</button>page.get_by_test_id('login-btn')# 自定义测试 ID 属性名page.selectors.set_test_id_attribute('data-test-id')page.get_by_test_id('my-button')  # 匹配 data-test-id="my-button"```---### 17. frame_locator() - Iframe 定位#### 17.1 API 签名```pythonpage.frame_locator(selector)```**参数说明:**- `selector` (必需): 定位 iframe 的选择器#### 17.2 用法示例```python# 基本用法frame = page.frame_locator('iframe[name="content"]')frame.locator('.save').click()# 嵌套 iframeouter_frame = page.frame_locator('iframe.outer')inner_frame = outer_frame.frame_locator('iframe.inner')inner_frame.locator('.deep').click()```---## 第五部分:高级篇### 18. 正则表达式与模糊匹配#### 18.1 为什么需要模糊匹配```python# 动态值问题示例:# id="btn-abc123"      # 每次变化# class="_container_oq067_1"  # React/Vue 哈希类名# 订单号:SO-202401150001  # 动态生成```#### 18.2 CSS 模糊匹配```python# 包含匹配 [*]page.locator('[id*="btn-"]')page.locator('[class*="container"]')# 开头匹配 [^]page.locator('[id^="btn-"]')page.locator('[class^="_container_"]')# 结尾匹配 [$]page.locator('[class$="-primary"]')page.locator('[id$="-btn"]')```#### 18.3 正则表达式 + filter()```pythonimport re# 匹配动态订单号page.locator('.order-item').filter(    has_text=re.compile(r'SO-20240115\d{4}'))# 匹配特定 ID 范围page.locator('.user-card').filter(    has_text=re.compile(r'ID:1000\d')  # ID:10000-10009)# 匹配日志级别page.locator('.log').filter(    has_text=re.compile(r'^(ERROR|WARNING):'))```#### 18.4 常用正则模式```pythonimport rere.compile(r'\d+')              # 匹配数字re.compile(r'\d{4}-\d{2}-\d{2}')# 匹配日期:2024-01-15re.compile(r'SO-\d{8}')         # 匹配订单号:SO-20240115re.compile(r'[A-Z]{2}\d{4}')    # 匹配代码:AB1234re.compile(r'1[3-9]\d{9}')      # 匹配手机号re.compile(r'¥[\d,]+\.?\d*')    # 匹配价格```---### 19. filter() 过滤方法高级用法#### 19.1 API 签名```pythonlocator.filter(has=None, has_text=None, has_not=None, has_not_text=None)```#### 19.2 基础用法```python# has_text - 包含指定文本page.locator('.item').filter(has_text='产品 A').click()# has - 包含指定子元素page.locator('.item').filter(    has=page.locator('.stock:has-text("有货")')).all()# has_not_text - 不包含指定文本page.locator('.item').filter(has_not_text='下架').all()# has_not - 不包含指定子元素page.locator('.item').filter(    has_not=page.locator('.out-of-stock')).all()```#### 19.3 链式过滤```python# 多重条件过滤page.locator('.product').filter(    has_text='电子产品').filter(    has_text=re.compile(r'销量:[1-9]')).all()```---### 20. 动态值定位实战#### 20.1 动态 ID```python# HTML: <button id="btn-abc123">提交</button># CSS 开头匹配page.locator('[id^="btn-"]')# CSS 包含匹配page.locator('[id*="btn"]')# XPath containspage.locator('xpath=//button[contains(@id, "btn")]')```#### 20.2 React/Vue 动态类名```python# HTML: <div class="_container_oq067_1">内容</div>page.locator('[class*="_container"]')page.locator('[class^="_container_"]')```#### 20.3 动态文本```python# HTML: <span>欢迎,张三 (2024-01-15)</span># 模糊匹配page.get_by_text('欢迎')# 正则 + filterimport repage.locator('span').filter(    has_text=re.compile(r'欢迎,.+'))```#### 20.4 动态属性```python# HTML: <input name="email_abc123">page.locator('[name^="email_"]')page.locator('[name*="email"]')```---### 21. JavaScript 表达式定位#### 21.1 evaluate 直接查询```python# querySelectorelement = page.evaluate('''() => {    return document.querySelector('.btn-primary')}''')# querySelectorAllelements = page.evaluate('''() => {    return Array.from(document.querySelectorAll('.btn'))}''')# XPath 查询element = page.evaluate('''() => {    const xpath = '//button[@type="submit"]';    return document.evaluate(xpath, document, null,           XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;}''')```#### 21.2 $eval 和 $$eval```python# $eval - 查询单个元素并执行函数text = page.eval_on_selector('.btn''el => el.textContent')# $$eval - 查询所有元素并执行函数texts = page.eval_on_selector_all('.btn''els => els.map(el => el.textContent)')# 复杂操作count = page.eval_on_selector_all('.btn''els => els.filter(el => el.disabled).length')```---## 第六部分:实战篇### 22. 登录页面元素定位```python# ===== 典型登录页面 HTML ====="""<form id="login-form">    <label for="username">用户名</label>    <input id="username" name="username" placeholder="请输入用户名">    <label for="password">密码</label>    <input id="password" name="password" type="password">    <button id="submit-btn" type="submit">登录</button></form>"""# 用户名输入框page.get_by_test_id('username-input')page.get_by_label('用户名')page.locator('#username')page.locator('[name="username"]')page.get_by_placeholder('请输入用户名')# 密码输入框page.get_by_test_id('password-input')page.get_by_label('密码')page.locator('#password')page.locator('input[type="password"]')# 登录按钮page.get_by_test_id('login-submit')page.locator('#submit-btn')page.get_by_role('button', name='登录')page.locator('button[type="submit"]')```---### 23. 数据表格元素定位```python# ===== 典型数据表格 ====="""<table class="data-table" data-testid="user-table">    <tr data-row-id="1">        <td class="username">zhangsan</td>        <td class="action">            <button data-action="edit">编辑</button>            <button data-action="delete">删除</button>        </td>    </tr></table>"""# 表格page.get_by_test_id('user-table')# 数据行page.locator('[data-row-id="1"]')page.locator('tbody tr:first-child')# 按单元格内容定位行page.locator('tr:has-text("zhangsan")')# 操作按钮page.locator('[data-row-id="1"] .btn-edit')page.locator('tr:has-text("zhangsan") .btn-edit')```---### 24. 导航菜单元素定位```python# ===== 典型导航菜单 ====="""<nav class="main-nav" role="navigation">    <a href="/home" class="menu-link active">首页</a>    <a href="/agent" class="menu-link">智能体</a>    <a href="/qa" class="menu-link">问答</a></nav>"""# 导航容器page.locator('nav[role="navigation"]')page.locator('.main-nav')page.get_by_role('navigation')# 菜单项page.locator('.menu-link')page.locator('a[href="/home"]')page.get_by_text('首页')page.locator('.menu-link.active')  # 当前激活项```---### 25. 模态框/对话框元素定位```python# ===== 典型模态框 ====="""<div class="modal" role="dialog">    <div class="modal-header">        <h3>确认删除</h3>        <button class="btn-close" aria-label="关闭">&times;</button>    </div>    <div class="modal-body">        <p>确定要删除吗?</p>    </div>    <div class="modal-footer">        <button class="btn-cancel">取消</button>        <button class="btn-danger" data-testid="confirm-delete">确认删除</button>    </div></div>"""# 模态框容器page.get_by_role('dialog')page.locator('.modal')# 关闭按钮page.locator('.btn-close')page.locator('[aria-label="关闭"]')# 操作按钮page.locator('.btn-cancel')page.get_by_test_id('confirm-delete')```---### 26. 表单验证错误定位```python# ===== 带验证的表单 ====="""<div class="form-group has-error">    <input class="form-input error" aria-invalid="true">    <span class="error-message" role="alert">用户名已存在</span></div>"""# 错误状态容器page.locator('.has-error')# 错误输入框page.locator('input.error')page.locator('[aria-invalid="true"]')# 错误消息page.locator('.error-message')page.locator('[role="alert"]')```---### 27. 动态加载内容处理```pythonfrom playwright.sync_api import expect# 等待加载完成page.locator('.loading-overlay').wait_for(state='hidden'timeout=10000)# 等待数据行出现page.locator('tbody tr').first.wait_for(state='visible'timeout=10000)# 使用 expect 断言expect(page.locator('.loading-overlay')).to_be_hidden(timeout=10000)expect(page.locator('tbody tr')).to_have_count(10, timeout=10000)# 等待网络请求完成with page.expect_response('**/api/data'):    page.locator('.refresh-btn').click()```---## 第七部分:技巧篇### 28. API 选择决策树```                              开始定位元素                                   │                                   ▼                      ┌────────────────────────┐                      │ 有 data-testid 属性?   │                      └───────────┬────────────┘                                  │ Yes                                  ▼                      ┌────────────────────────┐                      │ get_by_test_id()      │                      └────────────────────────┘                                  │ No                                  ▼                      ┌────────────────────────┐                      │ 是表单元素?           │                      └───────────┬────────────┘                                  │ Yes                    ┌─────────────┼─────────────┐                    │             │             │                    ▼             ▼             ▼          ┌──────────────┐ ┌──────────────┐ ┌──────────────┐          │ 有 label?    │ │ 有 placeholder?│ │ 有 name?   │          └──────┬───────┘ └──────┬───────┘ └──────┬───────┘                 │ Yes           │ Yes           │ Yes                 ▼               ▼               ▼          ┌──────────────┐ ┌──────────────┐ ┌──────────────┐          │get_by_label()│ │get_by_place- │ │ locator()    │          │              │ │holder()      │ │ [name="xxx"] │          └──────────────┘ └──────────────┘ └──────────────┘                                  │ No                                  ▼                      ┌────────────────────────┐                      │ 有唯一 ID?            │                      └───────────┬────────────┘                                  │ Yes                                  ▼                      ┌────────────────────────┐                      │ locator('#id')         │                      └────────────────────────┘                                  │ No                                  ▼                      ┌────────────────────────┐                      │ 是按钮/链接/交互元素?  │                      └───────────┬────────────┘                                  │ Yes                                  ▼                      ┌────────────────────────┐                      │ get_by_role()          │                      └────────────────────────┘                                  │ No                                  ▼                      ┌────────────────────────┐                      │ locator(CSS/XPath)     │                      └────────────────────────┘```---### 29. 元素定位调试技巧#### 29.1 高亮元素```pythonlocator = page.locator('.btn-primary')locator.highlight()  # 在浏览器中高亮显示```#### 29.2 获取元素信息```pythonlocator = page.locator('.btn')# 获取元素数量count = locator.count()print(f"找到 {count} 个元素")# 获取元素属性value = locator.get_attribute('value')print(f"value 属性:{value}")# 获取元素文本text = locator.text_content()print(f"文本:{text}")```#### 29.3 元素截图```pythonlocator = page.locator('.modal')locator.screenshot(path='modal.png')```#### 29.4 使用 Codegen```bash# 录制操作并生成代码npx playwright codegen https://example.com```#### 29.5 Trace Viewer```bash# 查看 tracenpx playwright show-trace trace.zip```---### 30. 常见问题与解决方案#### 30.1 元素在 iframe 中```python# 先切换到 iframeframe = page.frame_locator('iframe#content')frame.locator('.btn').click()```#### 30.2 元素在 Shadow DOM 中```python# 使用穿透语法page.locator('host-element >> .shadow-content').click()```#### 30.3 元素被遮挡```python# 等待遮挡元素消失page.locator('.loading-mask').wait_for(state='hidden')# 滚动到元素位置page.locator('.btn').scroll_into_view_if_needed()# 强制点击(慎用)page.locator('.btn').click(force=True)```#### 30.4 元素未加载```python# 添加显式等待page.locator('.content').wait_for(state='visible'timeout=10000)# 使用 expect 等待expect(page.locator('.result')).to_contain_text('完成'timeout=10000)```#### 30.5 选择器不唯一```python# 缩小范围page.locator('.modal').locator('.btn')# 添加更多条件page.locator('.btn.btn-primary')# 使用索引page.locator('.btn').nth(0)page.locator('.btn').first```---### 31. 最佳实践与性能优化#### 31.1 最佳实践```python# 1. 优先使用语义化 APIpage.get_by_test_id('submit-btn')  # 最佳page.get_by_label('用户名')        # 优秀page.get_by_role('button', name='提交')  # 优秀# 2. 避免绝对路径# ❌ 不推荐page.locator('xpath=/html/body/div[2]/button')# ✓ 推荐page.locator('button:has-text("提交")')# 3. 使用模糊匹配处理动态值# ❌ 会失败page.locator('#btn-abc123')# ✓ 推荐page.locator('[id^="btn-"]')# 4. 添加显式等待page.locator('.dynamic-content').wait_for(state='visible'timeout=10000)# 5. 缓存定位器submit_btn = page.get_by_test_id('submit-btn')submit_btn.click()submit_btn.hover()```#### 31.2 性能优化```python# 1. 缩小搜索范围# ❌ 慢page.locator('[class*="btn"]')# ✓ 快page.locator('#form-container [class*="btn"]')# 2. 使用 CSS 而非 XPath# ✓ CSS(快)page.locator('[class*="btn"]')# XPath(稍慢)page.locator('xpath=//*[contains(@class, "btn")]')# 3. 避免过度使用正则# ✓ 简单快速page.locator('[id^="btn-"]')# 稍慢(但更灵活)page.locator('button').filter(has_text=re.compile(r'^btn-\d+'))```---## 附录### 附录 A: CSS 选择器速查表| 选择器 | 示例 | 说明 ||--------|------|------|| `*` | `*` | 所有元素 || `E` | `div` | 所有 div 元素 || `#id` | `#submit` | id="submit" || `.class` | `.btn` | class 包含 btn || `[attr]` | `[disabled]` | 有 disabled 属性 || `[attr=val]` | `[type="text"]` | type="text" || `[attr*=val]` | `[href*="http"]` | href 包含 http || `[attr^=val]` | `[href^="https"]` | href 以 https 开头 || `[attr$=val]` | `[href$=".pdf"]` | href 以.pdf 结尾 || `E F` | `div p` | div 内的 p(后代) || `E > F` | `div > p` | div 的直接子 p || `E + F` | `h2 + p` | 紧跟 h2 的 p || `E ~ F` | `h2 ~ p` | h2 后的所有 p || `:first-child` | `li:first-child` | 第一个 li || `:last-child` | `li:last-child` | 最后一个 li || `:nth-child(n)` | `li:nth-child(2)` | 第 2 个 li || `:not(.x)` | `button:not(.disabled)` | 非 disabled 的按钮 || `:has(selector)` | `div:has(> .btn)` | 包含.btn 子元素的 div |### 附录 B: XPath 速查表| 表达式 | 说明 ||--------|------|| `//tag` | 选择任意位置的 tag 元素 || `@attr` | 选择有 attr 属性的元素 || `@attr=val` | 选择 attr 属性值为 val 的元素 || `contains(@attr,val)` | 选择 attr 包含 val 的元素 || `starts-with(@attr,val)` | 选择 attr 以 val 开头的元素 || `text()=val` | 选择文本等于 val 的元素 || `contains(text(),val)` | 选择文本包含 val 的元素 || `[n]` | 选择第 n 个元素 || `[last()]` | 选择最后一个元素 || `parent::*` | 选择父元素 || `child::tag` | 选择子元素 || `ancestor::tag` | 选择祖先元素 || `descendant::tag` | 选择后代元素 || `following::tag` | 选择之后的元素 || `following-sibling::tag` | 选择之后的兄弟元素 |### 附录 C: Playwright API 速查表| 方法 | 参数 | 示例 ||------|------|------|| `locator()` | selector, has, has_text | `page.locator('.btn')` || `get_by_role()` | role, name, exact | `page.get_by_role('button')` || `get_by_text()` | text, exact | `page.get_by_text('提交')` || `get_by_label()` | label_text, exact | `page.get_by_label('用户名')` || `get_by_placeholder()` | placeholder, exact | `page.get_by_placeholder('请输入')` || `get_by_alt_text()` | alt, exact | `page.get_by_alt_text('logo')` || `get_by_title()` | title, exact | `page.get_by_title('提示')` || `get_by_test_id()` | test_id | `page.get_by_test_id('login')` || `frame_locator()` | selector | `page.frame_locator('iframe')` |### 附录 D: 正则表达式速查表| 模式 | 含义 | 示例 ||------|------|------|| `\d+` | 一个或多个数字 | `re.compile(r'\d+')` || `\d{4}` | 恰好 4 位数字 | `re.compile(r'\d{4}')` || `.*` | 任意字符任意次 | `re.compile(r'.*')` || `^abc` | 以 abc 开头 | `re.compile(r'^abc')` || `xyz$` | 以 xyz 结尾 | `re.compile(r'xyz$')` || `[abc]` | 字符集 | `re.compile(r'[a-z]+')` || `(a\|b)` | 或 | `re.compile(r'(ERROR\|WARNING)')` |---## 文档版本历史| 版本 | 日期 | 更新内容 ||------|------|----------|| 1.0 | 2024-03-26 | 初始版本,整合所有定位方法文档 |---**文档结束**

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-03-27 15:16:19 HTTP/2.0 GET : https://f.mffb.com.cn/a/483255.html
  2. 运行时间 : 0.232600s [ 吞吐率:4.30req/s ] 内存消耗:4,743.66kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=3cdae1bbf85321a20a5b2db3cce9e3a6
  1. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_static.php ( 4.90 KB )
  7. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  10. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  11. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  12. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  13. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  14. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  15. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  16. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  17. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  18. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  19. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  21. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  22. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/provider.php ( 0.19 KB )
  23. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  24. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  25. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  26. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/common.php ( 0.03 KB )
  27. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  28. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  29. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/app.php ( 0.95 KB )
  30. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cache.php ( 0.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/console.php ( 0.23 KB )
  32. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cookie.php ( 0.56 KB )
  33. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/database.php ( 2.48 KB )
  34. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  35. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/filesystem.php ( 0.61 KB )
  36. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/lang.php ( 0.91 KB )
  37. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/log.php ( 1.35 KB )
  38. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/middleware.php ( 0.19 KB )
  39. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/route.php ( 1.89 KB )
  40. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/session.php ( 0.57 KB )
  41. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/trace.php ( 0.34 KB )
  42. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/view.php ( 0.82 KB )
  43. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/event.php ( 0.25 KB )
  44. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  45. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/service.php ( 0.13 KB )
  46. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/AppService.php ( 0.26 KB )
  47. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  48. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  49. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  50. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  51. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  52. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/services.php ( 0.14 KB )
  53. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  54. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  55. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  56. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  57. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  58. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  59. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  60. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  61. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  62. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  63. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  64. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  65. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  66. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  67. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  68. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  69. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  70. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  71. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  72. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  73. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  74. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  75. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  76. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  77. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  78. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  79. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  80. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  81. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  82. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  83. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/Request.php ( 0.09 KB )
  84. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  85. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/middleware.php ( 0.25 KB )
  86. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  87. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  88. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  89. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  90. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  91. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  92. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  93. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  94. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  95. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  96. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  97. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  98. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  99. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/route/app.php ( 1.72 KB )
  100. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  101. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  102. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  103. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/controller/Index.php ( 4.81 KB )
  104. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/BaseController.php ( 2.05 KB )
  105. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  106. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  108. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  109. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  110. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  111. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  112. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  113. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  114. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  115. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  116. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  117. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  118. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  119. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  120. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  121. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  122. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  123. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  124. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  125. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  126. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  127. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  128. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  129. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  130. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  131. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  132. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  133. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  134. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  135. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  136. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  137. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  138. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  139. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/runtime/temp/067d451b9a0c665040f3f1bdd3293d68.php ( 11.98 KB )
  140. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.001105s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.001736s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000745s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000678s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.001293s ]
  6. SELECT * FROM `set` [ RunTime:0.000612s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.001488s ]
  8. SELECT * FROM `article` WHERE `id` = 483255 LIMIT 1 [ RunTime:0.001411s ]
  9. UPDATE `article` SET `lasttime` = 1774595780 WHERE `id` = 483255 [ RunTime:0.032900s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 66 LIMIT 1 [ RunTime:0.002404s ]
  11. SELECT * FROM `article` WHERE `id` < 483255 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.005644s ]
  12. SELECT * FROM `article` WHERE `id` > 483255 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.002517s ]
  13. SELECT * FROM `article` WHERE `id` < 483255 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.003583s ]
  14. SELECT * FROM `article` WHERE `id` < 483255 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.002614s ]
  15. SELECT * FROM `article` WHERE `id` < 483255 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.001929s ]
0.237030s