WPS Python脚本合集(一):eval函数直接计算表达式
Excel表格中的EVALUATE函数可以将文本字符串当作公式,进行计算并返回结果,常用于动态公式生成或处理以文本形式存储的算式。
Python语言中的eval() 是一个危险的函数,如果使用不受信任的字符串作为表达式,则可能导致代码注入漏洞,因此,应谨慎使用 eval() 函数,并确保仅执行可信任的字符串表达式。
完整文章链接见微信公众号:https://mp.weixin.qq.com/s/KXSaC_VQcr5W-punySRUKg
一、多维表格结构
1、表名:evaluate方法
2、视图名:表格视图
3、字段设置:
◉ 字段名称:表达式 - 字段类型:文本 - 禁止录入重复值:否 - 默认值:无;
◉ 字段名称:计算结果 - 字段类型:文本 - 禁止录入重复值:否 - 默认值:无;
二、Python脚本批量计算【危险版】
前面有讲到eval() 是一个危险的函数,如果使用不受信任的字符串作为表达式,则可能导致代码注入漏洞,下面来做下对比演示
2.1 代码逻辑解释
首先使用dbt()函数读取名为'evaluate方法'的数据表数据,并输出变量类型和具体数据;
接着使用iterrows()遍历DataFrame,同时获取索引和行数据,如果空值或NaN会跳过,如果表达式格式不规范,会输出错误结构
最后打印最终的计算结果
import pandas as pd
expression = dbt(sheet_name='evaluate方法')
print("expression 变量类型:", type(expression))
print("expression 变量值:")
print(expression)
# 直接使用iterrows()遍历DataFrame,同时获取索引和行数据
for index, row in expression.iterrows():
expr = row['表达式']
# 跳过空值或NaN
if pd.isna(expr):
print(f"索引 {index}: 跳过空表达式")
continue
try:
# 安全地计算表达式
result = eval(expr)
update_dbt({"_rid": index, "计算结果": result})
print(f"索引 {index}: 表达式 '{expr}' 计算结果: {result}")
except Exception as e:
print(f"索引 {index}: 计算表达式 '{expr}' 时出错: {str(e)}")
print("\n最终结果:")
print(dbt(sheet_name='evaluate方法'))
2.2 正常数据演示
以图中数据进行演示
控制台输出情况
动图演示
2.3 恶意代码数据演示
假设存在一个名为'待删除数据表'的数据表内存在数据
此时数据表'evaluate方法'表达式列中存在如下数据
update_dbt({"_rid": "DVR", "计算结果": "测试代码注入"}),这行代码代表在索引值为DVR行中更新计算结果列的内容为"测试代码注入"
delete_dbt(sheet_name='待删除数据表'),这行代表删除名为'待删除数据表'的数据表全部内容
一不小心就删库跑路咯O(∩_∩)O
同样运行脚本,控制台输出情况
动图演示
三、Python脚本批量计算【输入校验版】
3.1 代码逻辑解释
如果真的需要使用eval函数,我们可以对函数输入的内容做校验或在受限制的环境下运行,如检查字符串是否仅包含安全的数学表达式字符,或只允许访问数学模块中的安全函数和常量,禁用内置函数等方法,具体代码如下:
import pandas as pd
import re
import ast
def is_math_expression(expr_str):
"""
使用正则表达式检查字符串是否仅包含安全的数学表达式字符。
允许数字、基本运算符、空格和常用数学常量及函数。
"""
if not isinstance(expr_str, str):
return False
# 正则表达式模式:允许数字、加减乘除、乘方、括号、小数点、空格、常用数学函数和常量
pattern = r'^[\d\s+\-*/().^eπsincoatanlogsqrtabs,]+$'
# 检查是否包含可能危险的关键字或函数调用(简易过滤)
blacklist = ['__', 'import', 'os', 'sys', 'exec', 'eval', 'open', 'file', 'lambda']
if any(keyword in expr_str for keyword in blacklist):
return False
return re.match(pattern, expr_str) is not None
def safe_eval(expr_str):
"""
相对安全地评估数学表达式。
首先尝试使用 ast.literal_eval,如果失败且表达式看似复杂但安全,则使用 eval 受限环境。
"""
try:
# 尝试直接解析字面量(最安全)
return ast.literal_eval(expr_str)
except (ValueError, SyntaxError):
# 如果 ast.literal_eval 失败,但表达式通过安全检查,则在受限环境中使用 eval
if is_math_expression(expr_str):
try:
# 创建受限的全局环境,只允许访问数学模块中的安全函数和常量
safe_globals = {
"__builtins__": None, # 禁用内置函数
"sin": __import__('math').sin,
"cos": __import__('math').cos,
"tan": __import__('math').tan,
"sqrt": __import__('math').sqrt,
"log": __import__('math').log,
"log10": __import__('math').log10,
"e": __import__('math').e,
"pi": __import__('math').pi,
"abs": abs,
"pow": pow,
"round": round,
}
return eval(expr_str, {"__builtins__": {}}, safe_globals)
except Exception as e:
raise ValueError(f"计算表达式时出错: {str(e)}")
else:
raise ValueError("表达式包含不安全字符或结构")
# 获取包含表达式的 DataFrame
expression_df = dbt(sheet_name='evaluate方法')
print("expression 变量类型:", type(expression_df))
print("expression 变量值:")
print(expression_df)
# 检查 DataFrame 是否包含 '表达式' 列
if '表达式' not in expression_df.columns:
raise ValueError("DataFrame 中未找到 '表达式' 列")
# 遍历 DataFrame 的每一行
for index, row in expression_df.iterrows():
expr = row['表达式']
# 跳过空值或 NaN
if pd.isna(expr):
print(f"索引 {index}: 跳过空表达式")
continue
# 检查表达式是否为字符串
if not isinstance(expr, str):
print(f"索引 {index}: 跳过非字符串表达式 '{expr}'")
continue
print(f"索引 {index}: 正在处理表达式 '{expr}'")
try:
# 检查是否为数学表达式
if is_math_expression(expr):
# 安全地计算表达式
result = safe_eval(expr)
# 更新数据库(假设 update_dbt 函数已定义)
update_dbt({"_rid": index, "计算结果": result})
print(f"索引 {index}: 表达式 '{expr}' 计算结果: {result}")
else:
print(f"索引 {index}: 表达式 '{expr}' 被拒绝,因为它不是安全的数学表达式")
except Exception as e:
print(f"索引 {index}: 计算表达式 '{expr}' 时出错: {str(e)}")
print("\n最终结果:")
result_df = dbt(sheet_name='evaluate方法')
print(result_df)
3.2 含恶意代码数据演示
以图中数据进行演示
控制台输出情况,可以看到不符合规范的异常数据会被拦截,输出报错结果
动图演示:
四、Python脚本+自动化流程【输入校验版】
4.1 代码逻辑解释
其实内容和前面的大差不差,主要是前面需要获取自动化流程传过来的值,
受文章字数限制,具体代码见微信公众号链接:https://mp.weixin.qq.com/s/KXSaC_VQcr5W-punySRUKg
4.2 自动化流程配置
直接上图