影刀RPA Excel数据清洗实战:空行、重复、乱码、格式混乱的处理
数据采集出来不等于能用。你从网页上扒下来的数据往往是脏的——有空行、有重复、有乱码、格式不统一、数字和文本混在一起。
这篇文章不讲Excel操作的基本语法,讲的是数据清洗的真实套路。用的工具是影刀自带的动作 + Python的openpyxl/pandas。
清洗前先看一眼数据长什么样
很多人一拿到数据就开始写清洗逻辑,结果写到一半发现有些脏数据是自己假设之外的。
第一件事:打开采集到的Excel,肉眼扫一遍。看什么?
- 有没有空行?在哪些位置?
- 有没有明显重复的数据?
- 数字格式对不对?(有没有千分位逗号、百分号、负号位置错误)
- 日期格式统一吗?(“2026-07-01” 和 “2026/7/1” 混在一起)
- 有没有乱码?特别是中文列
- 有没有明显不合理的数据?(价格负数、数量为零、日期在未来)
肉眼扫完大概心里有数了,再上代码批量处理。不要跳过这一步——有时候你以为是格式问题,实际上是采集时就采错了。
清洗1:删除空行
网页采集最容易出现的脏数据——空行。列表里有20个元素,某个元素内容为空,采回来就是一行空数据。
在影刀中处理
店群矩阵自动化突破运营极限!
用ForEach遍历每一行,判断是否全为空:
【读取Excel】→ 全部数据到 data_list clean_list = [] FOR EACH row IN data_list: # 判断这一行是否全空 is_empty = True FOR EACH cell IN row: IF cell 不为空: is_empty = False BREAK END FOR IF is_empty == False: 将 row 加入 clean_list END FOR 【写入Excel】→ clean_list 到新文件在Python中处理(更高效)
importopenpyxl wb=openpyxl.load_workbook('data.xlsx')ws=wb.active# 收集所有非空行clean_rows=[]forrowinws.iter_rows(values_only=True):# 检查整行是否全为None或空字符串ifany(cellisnotNoneandstr(cell).strip()!=''forcellinrow):clean_rows.append(row)# 写入新sheet或新文件ws_clean=wb.create_sheet('清洗后')forrowinclean_rows:ws_clean.append(row)wb.save('data_cleaned.xlsx')print(f'清洗前:{ws.max_row}行,清洗后:{len(clean_rows)}行')清洗2:删除重复行
判断"重复"的标准
不是每列都相同才算重复。有时候你只关心"订单号"这一列是否重复:
# 按订单号去重seen=set()unique_rows=[]header=True# 第一行是表头forrowinws.iter_rows(values_only=True):ifheader:unique_rows.append(row)header=Falsecontinueorder_no=row[0]# 假设订单号在第一列iforder_nonotinseen:seen.add(order_no)unique_rows.append(row)print(f'去重后:{len(unique_rows)}行')如果是多列组合判断重复(同一客户+同一天算重复):
seen=set()unique_rows=[]forrowinws.iter_rows(values_only=True):key=(row[1],row[2])# 客户名+日期 作为唯一键ifkeynotinseen:seen.add(key)unique_rows.append(row)清洗3:处理编码乱码
从网页上采集的中文,存到Excel打开变成乱码。这个问题在CSV文件里尤其常见。
原因:Excel打开CSV时默认用ANSI编码,而你的CSV是UTF-8编码的。
解决方法:
importpandasaspd# 读取时指定编码df=pd.read_csv('data.csv',encoding='utf-8')# 或自动检测编码importchardetwithopen('data.csv','rb')asf:raw=f.read()result=chardet.detect(raw)encoding=result['encoding']print(f'检测到编码:{encoding}')df=pd.read_csv('data.csv',encoding=encoding)df.to_excel('data.xlsx',index=False)# 转成xlsx就不会乱码了根本解决方案:采集下来直接存成.xlsx而不是.csv。.xlsx自带编码信息,不存在乱码问题。
清洗4:数字格式标准化
从网页上采集的数字,格式千奇百怪:
| 原始值 | 问题 | 目标值 |
|---|---|---|
| “¥1,234.56” | 带货币符号和逗号 | 1234.56 |
| “1 234,56” | 空格分隔+逗号小数(欧洲格式) | 1234.56 |
| “35%” | 百分比 | 0.35 |
| “-1,234” | 负号在逗号前面 | -1234 |
| “12K” / “1.2万” | 缩写 | 12000 |
数字清洗通用函数
importredefclean_number(raw_value):ifraw_valueisNone:returnNones=str(raw_value).strip()# 空字符串ifs==''ors=='-':returnNone# 处理"万"if'万'ins:s=s.replace('万','')try:returnfloat(s.replace(',',''))*10000except:returnNone# 处理"K"ifs.upper().endswith('K'):try:returnfloat(s[:-1].replace(',',''))*1000except:returnNone# 处理百分比ifs.endswith('%'):try:returnfloat(s[:-1])/100except:returnNone# 通用数字处理:去货币符号、去逗号、去空格s=re.sub(r'[¥$€¥\s]','',s)s=s.replace(',','')# 千分位逗号try:returnfloat(s)except:returnNone# 确实不是数字# 使用示例print(clean_number('¥1,234.56'))# 1234.56print(clean_number('35%'))# 0.35print(clean_number('1.2万'))# 12000.0print(clean_number('-1,234'))# -1234.0temu店群自动化报活动案例
清洗5:日期格式统一
日期格式是数据清洗里最容易翻车的环节。同一个Excel里可能出现:
2026-07-012026/7/17月1日2026年7月1日20260701
统一处理:
fromdatetimeimportdatetimeimportredefclean_date(raw_value):ifraw_valueisNone:returnNones=str(raw_value).strip()# 已经是标准格式的forfmtin['%Y-%m-%d','%Y/%m/%d','%Y%m%d']:try:returndatetime.strptime(s,fmt).strftime('%Y-%m-%d')except:pass# 中文格式s_clean=s.replace('年','-').replace('月','-').replace('日','')try:returndatetime.strptime(s_clean,'%Y-%m-%d').strftime('%Y-%m-%d')except:pass# 如果上面都不行,尝试解析try:fromdateutilimportparser dt=parser.parse(s)returndt.strftime('%Y-%m-%d')except:returnNone# 放弃,标记为无效日期清洗6:文本列的去噪
网页上采集的文本常常带HTML标签、多余的空白、特殊字符:
importredefclean_text(raw_value):ifraw_valueisNone:return''s=str(raw_value)# 移除HTML标签s=re.sub(r'<[^>]+>','',s)# 移除不可见字符(零宽空格等)s=re.sub(r'[\u200b\u200c\u200d\ufeff]','',s)# 移除开头结尾的空白s=s.strip()# 多个空格/换行合并成一个s=re.sub(r'\s+',' ',s)# 移除全角数字转半角(可选)# s = s.translate(str.maketrans('0123456789', '0123456789'))returns完整清洗流程组合
把上面的处理串起来,做成一个可复用的清洗流程:
# === 影刀采集 → Excel → Python清洗 → 干净Excel ===importopenpyxlfromdatetimeimportdatetimedeffull_clean(input_file,output_file,column_rules):""" column_rules: { 0: 'text', # 第0列做文本清洗 1: 'number', # 第1列做数字清洗 2: 'date', # 第2列做日期清洗 3: None, # 第3列原样保留 } """wb=openpyxl.load_workbook(input_file)ws=wb.active clean_data=[]forrow_idx,rowinenumerate(ws.iter_rows(values_only=True)):# 空行跳过ifall(cellisNoneorstr(cell).strip()==''forcellinrow):continuenew_row=list(row)forcol_idx,ruleincolumn_rules.items():ifrule=='number':new_row[col_idx]=clean_number(row[col_idx])elifrule=='date':new_row[col_idx]=clean_date(row[col_idx])elifrule=='text':new_row[col_idx]=clean_text(row[col_idx])# rule == None: 原样保留clean_data.append(new_row)# 去重(按第一列)seen=set()unique_data=[]forrowinclean_data:key=row[0]ifkeynotinseen:seen.add(key)unique_data.append(row)# 写回ws_out=wb.create_sheet('Cleaned')forrowinunique_data:ws_out.append(row)wb.save(output_file)print(f'清洗完成:原始{ws.max_row}行 → 清洗后{len(unique_data)}行')核心要点:数据清洗80%的工作量在"识别脏数据",只有20%在"写清洗代码"。先肉眼扫数据,确认脏数据的模式,再写代码。不要假设数据是干净的——采集回来的数据永远是脏的。
作者:林焱