文件上传自动化的三种形态,以及一个让我误判三天的意外

举报
yd_255011313 发表于 2026/11/02 00:45:13 2026/11/02
【摘要】 华为云控制台自动化三层鉴权排障:MFA 提示页路由循环、SSO TGC 单次消耗、KooLabs 联邦登录与 auth-token 鉴权。

给平台做自动化,文件上传是绕不过去的一环。看起来都是"点一个按钮传个文件",实际在 DOM 里有三种完全不同的形态,每种的处理方式都不一样。我在第三种上栽了个大跟头。

## 形态一:可见的 input[type=file]

最简单的一种。元素就在 DOM 里,Playwright 直接写:

```python
page.locator('input[type="file"]').set_input_files(path)
```

如果元素是隐藏的(`display:none` 或者宽度 0),`set_input_files` 依然有效——它不要求元素可见。这点很多人不知道,会去点外层按钮触发文件框,反而多绕一步。

判断方式:

```python
if page.locator('input[type="file"]').count():
page.locator('input[type="file"]').first.set_input_files(path)
```

## 形态二:真·系统文件选择框

元素不在 DOM 里,点按钮会弹系统对话框。这时候必须用 `expect_file_chooser` 接住:

```python
with page.expect_file_chooser(timeout=15000) as fc_info:
page.locator('button:has-text("上传作品")').first.click()
fc_info.value.set_files(path)
```

关键点:**`expect_file_chooser` 必须在点击之前开**。写在点击之后永远等不到——因为事件已经发生过了,而且 Playwright 会一直挂在那里等下一个(永远不来的)事件,最后超时。

我第一次写反了顺序,超时 12 秒才报错,还以为是选择器不对。

## 形态三:上传后页面自动提交(我误判了三天的那种)

赛事作品提交那个页面,我按形态一的方式 `set_input_files` 之后,又去点"提交"按钮,一直点不到——因为**页面上根本没有"提交"按钮**。

当时的输出是这样的:

```
file set
请选择阶段组 -> value=大赛
请选择阶段 -> value=大赛
btns=["上传作品"] files=[null]
```

`files=[null]` 说明 input 的 files 已经被清空了,`btns` 里只有"上传作品",没有提交按钮。我判断"文件没挂上、提交失败",然后反复重试了两天。

第三天我截了张全页图才看见真相:

```
作品名称 阶段 提交时间 作品分数
2048-game_...zip 大赛 2026-10-25 01:05:51 评分中
```

**早已提交成功了。** `set_input_files` 之后页面自己就把提交做完了,input 被清空是提交成功的表现,不是失败。

这里有两个教训:

**一、`files=[null]` 可能是"已消费"而不是"没挂上"。** 单看这个状态无法区分,需要看页面上的结果列表。

**二、操作完先 dump 一次页面状态再决定下一步。** 我当时是"操作→立刻判断下一步该点哪",跳过了"先看看现在什么状态"这一步。加上这一步只需要一次 `page.inner_text("body")`,能省掉几天的误判。

修正后的写法:

```python
page.locator('input[type="file"]').first.set_input_files(ZIP)
page.wait_for_timeout(8000)
# 先看结果,别急着点下一步
body = page.inner_text("body")
if "提交时间" in body or "评分中" in body:
return "已提交"
# 只有在确实需要时,才去找提交按钮
```

## 一个配套的坑:文件名即业务规则

上传的文件名有时候参与业务校验。那个赛事的规则是:

> 所有参赛作品需打包为 zip,命名规范:作品名称+队伍名称+版本号+联系方式

我一开始随便起了个名字,虽然传上去了,但为了合规还是重新打了一个:

```
2048-game_hw2048team_v1.1_2756.zip
↑作品名 ↑队伍 ↑版本 ↑联系方式后四位
```

这类规范建议**在打包阶段就按规则命名**,别等上传后改。有些平台会在服务端校验文件名,不符合直接拒。

## 还有个细节:zip 的目录结构

详情包的校验通常要求特定结构:

```
README.md ← 必须在根
resources/ ← 资源目录
```

打 zip 时如果用 `Compress-Archive -Path "$stage\*"`,展开后是"根目录下直接是内容",正确。如果用 `-Path $stage`(不带 `\*`),会变成"根目录下多套一层父目录",服务端校验就会报结构非法。

```powershell
Compress-Archive -Path "$stage\*" -DestinationPath $out # 对
Compress-Archive -Path $stage -DestinationPath $out # 错(多一层)
```

这个差异在本地解压看不出来(都能解压),只有服务端校验才暴露。

## 小结

| 形态 | 识别方式 | 处理 |
|---|---|---|
| 可见/隐藏 input | `input[type=file]` 存在 | `set_input_files` 直接写 |
| 系统文件框 | DOM 里没有 file input | `expect_file_chooser` 包住点击 |
| 上传即提交 | 没有提交按钮,input 被清空 | 传完先 dump 页面看结果 |

第三条最值得记:**自动化的常见失误不是"点错了",而是"点完后没确认状态就继续点"。** 每步之间插一次状态 dump,成本几乎为零,收益是把"误判三天"变成"三秒发现"。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。