如何使用Python的MechanicalSoup向ASP.NET站点的表单内上传文件
问题根源
- 核心错误为文件上传字段名不匹配:你两次提交都未使用表单实际定义的文件上传字段名
ctl00$ctl00$MainContent$RPBVContent$ucPriceUploader$FileUpload1:- 第一次提交时
files参数的键自定义为prices.csv,和服务端预期的字段名不符 - 第二次提交误将文件内容赋值给了提交按钮对应的字段
ctl00$ctl00$MainContent$RPBVContent$ucPriceUploader$cmdUpload1
服务端无法找到对应字段的上传内容,自然不会识别到文件。
- 第一次提交时
- 两处请求头差异均为正常现象:不同客户端生成的
multipart/form-data边界值(boundary)本来就不统一,Content-Length的差异是字段名错误导致请求体描述部分长度不同,均不是问题诱因。
可行解决方案
如果你当前使用的是mechanize库(从submit_selected方法判断)
直接通过正确的字段名找到文件上传控件,调用add_file方法上传即可,无需手动读取文件内容:
# 定位文件上传控件,添加待上传文件 browser.form.find_control( name="ctl00$ctl00$MainContent$RPBVContent$ucPriceUploader$FileUpload1", type="file" ).add_file( open("pricestoy.csv", "rb"), "text/csv", "pricestoy.csv" ) # 提交表单 pp = browser.submit_selected()
如果你使用requests库直接发送请求
需要先从页面源码提取ASP.NET WebForms必备的动态隐藏字段,再和文件一起提交:
import requests from bs4 import BeautifulSoup # 先请求上传页面,获取动态隐藏字段值 page_resp = requests.get("上传页面地址") soup = BeautifulSoup(page_resp.text, "html.parser") viewstate = soup.find("input", {"name": "__VIEWSTATE"})["value"] event_validation = soup.find("input", {"name": "__EVENTVALIDATION"})["value"] # 构造提交参数 submit_url = "表单提交目标地址" form_data = { "__VIEWSTATE": viewstate, "__EVENTVALIDATION": event_validation, "ctl00$ctl00$MainContent$RPBVContent$ucPriceUploader$cmdUpload1": "上传" # 对应提交按钮的参数值,可从页面源码确认 } files = { # 键必须为表单定义的文件上传字段名 "ctl00$ctl00$MainContent$RPBVContent$ucPriceUploader$FileUpload1": ("pricestoy.csv", open("pricestoy.csv", "rb"), "text/csv") } resp = requests.post(submit_url, data=form_data, files=files)
注意事项
- 不要手动修改
Content-Type请求头, mechanize/requests会自动生成带正确边界值的请求头,手动设置反而会导致请求解析失败。 - ASP.NET WebForms站点的动态隐藏字段
__VIEWSTATE、__EVENTVALIDATION每次访问页面都会更新,提交请求前必须从当前页面提取最新值,否则服务端会判定请求非法。
内容的提问来源于stack exchange,提问作者Dean MacGregor
相关产品推荐
相关产品推荐

