Python基础学习(二),读取文件数据,清洗数据,然后重新保存

第二阶段:进阶语法(数据采集与清洗场景)
目标:掌握列表推导、异常处理、文件读写、常用内置库。

场景:市场部需要收集竞品价格,但官网数据夹杂着空值、单位(“元/件”)和emoji符号。

具体例子:使用requests抓取HTML(模拟),用正则表达式提取数字,用try/except处理缺失值,最后清洗成纯浮点数保存。

练习:编写清洗管道,自动将“¥1,299.00”转换为1299.00。

 

业务涉及内容:

1)读取csv文件;

2)对读取的数据列表,进行特殊字符清洗;具体的特殊字符要根据文件,尽可能全面,防止缺少造成清洗不完整;

3)清洗后的数据,进行写操作,存为新文件;

4)统计清洗数据的情况;哪些有问题,具体数量等;

 

测试使用附件:https://files.cnblogs.com/files/violetlength/raw_prices.zip?t=1787886036&download=true

 

具体代码实现:myclean.py

  1 import os
  2 import csv
  3 import re
  4 import emoji
  5 
  6 def clean_pricestr(mystr):
  7     """清理价格里面的特殊数据,转为数字
  8     主要处理:
  9         空值或者None
 10         货币符号:¥、¥、$
 11         千位分割符:,
 12         单位后缀:元/件 元
 13         emoji符号
 14         括号等特殊字符
 15     入参:价格字符串,
 16     
 17     返回:float或者None(清理失败时,直接返回None)
 18     """
 19     if mystr is None:
 20         return None
 21         
 22     if not isinstance(mystr,str):
 23         return None
 24         
 25     cleaned = mystr.strip()
 26     
 27     if not cleaned or cleaned == "()":
 28         return None
 29     
 30     cleaned = cleaned.replace('¥','')
 31     cleaned = cleaned.replace('','')
 32     cleaned = cleaned.replace('$','')
 33     cleaned = cleaned.replace('','')
 34     cleaned = cleaned.replace('£','')
 35 
 36     cleaned = cleaned.replace('元/件','')
 37     cleaned = cleaned.replace('元件','')
 38     cleaned = cleaned.replace('','')
 39     cleaned = cleaned.replace('','')
 40 
 41     #处理emoji符号,需要py 3.10+版本,可以引用该第三方插件 import emoji
 42     cleaned = emoji.replace_emoji(cleaned, replace='')
 43     
 44     cleaned = cleaned.replace(',','')
 45     
 46     #相关的特殊字符替换后,再做一次首尾空格格式化
 47     cleaned = cleaned.strip()
 48 
 49     #再次判断格式化之后,是否有有效值,如果没有,则返回None
 50     if not cleaned:
 51         return None
 52     
 53     try:
 54         price = float(cleaned)
 55         if price < 0:  #处理负数情况
 56             return None
 57         return price
 58     except ValueError:
 59         return None
 60 
 61 def read_csv(file):
 62     """读原始文件数据
 63     入参:csv文件
 64     返回:行对象列表
 65     """
 66     records = []
 67     try:
 68         with open(file,"r",encoding="gbk") as ff:
 69             reader = csv.DictReader(ff)
 70             for row in reader:
 71                 records.append(row)
 72     except FileNotFoundError:
 73         print(f"错误:未找到文件{file}")
 74         return []
 75     except UnicodeDecodeError: #此时说明文档是UTF-8格式,再用UTF-8处理读取一下
 76         try:
 77             with open(file,"r",encoding="utf-8") as ff:
 78                 reader = csv.DictReader(ff)
 79                 for row in reader:
 80                     records.append(row)
 81         except Exception as e:
 82             print(f"读文件失败:{e}")
 83             return []
 84     return records
 85 
 86 def clean_price_list(records):
 87     """清洗价格列表数据
 88     入参:数据列表
 89     返回:清洗后的列表
 90     """
 91     cleaned_records = []
 92     for record in records:
 93         product_name = record.get("产品名称","未知名称")
 94         original_price = record.get("价格","")
 95         source = record.get("来源","未知来源")
 96         cleaned_price = clean_pricestr(original_price)
 97         
 98         cleaned_records.append({
 99             "产品名称":product_name,
100             "原始价格":original_price,
101             "清洗后价格":cleaned_price,
102             "来源":source,
103             "是否有效":cleaned_price is not None
104         })
105         
106     return cleaned_records
107 
108 def save_cleaned_data(records, output_file):
109     """把清洗后的数据,存到另外一个文档中
110     入参:清理的数据,要存储的文档
111     """
112     try:
113         with open(output_file,"w",encoding="utf-8", newline="") as ff:
114             fieldnames=["产品名称", "原始价格", "清洗后价格", "来源", "是否有效"]
115             writer=csv.DictWriter(ff,fieldnames= fieldnames)
116             writer.writeheader()
117             writer.writerows(records)
118         print(f"数据保存地址:{output_file}")
119     except Exception as e:
120         print(f"保存出差:{e}")
121 
122 def show_statistics(cleaned_records):
123     """显示统计数据
124     入参:清理的数据记录
125     """
126     total = len(cleaned_records)
127     valid = sum(1 for r in cleaned_records if r["是否有效"])
128     invalid = total - valid
129     
130     valid_prices = [r["清洗后价格"] for r in cleaned_records if r["是否有效"]]
131     
132     print(f"总数:{total}")
133     print(f"合规数:{valid}")
134     print(f"不合规数:{invalid}")
135     
136     if valid_prices:
137         print(f"价格范围:{min(valid_prices):.2f} -- {max(valid_prices):.2f}")
138         print(f"平均价格:{sum(valid_prices)/len(valid_prices):.2f}")
139 
140 def main():
141     pathdir = os.path.dirname(os.path.abspath(__file__))
142     inputfile = os.path.join(pathdir,"raw_prices.csv")
143     outputfile = os.path.join(pathdir,"cleaned_prices.csv")
144 
145     print("1、读原始文件数据")
146     rawrecords = read_csv(inputfile)
147     if not rawrecords:
148         print("没有读取到数据")
149         reuturn
150     
151     print(f"读取到{len(rawrecords)}条数据")
152 
153     print("2、清洗数据")
154     cleanedrecords = clean_price_list(rawrecords)
155     
156     invalidcount = sum(1 for r in cleanedrecords if not r["是否有效"])
157     print(f"清洗完成。{invalidcount}条数据失败")
158 
159     print("3、显示清洗结果")
160     for i, record in enumerate(cleanedrecords[:5]):
161         status = "" if record["是否有效"] else ""
162         price_display = f"{record['清洗后价格']:.2f}" if record["是否有效"] else "无效"
163         original_display = record["原始价格"].encode('ascii','replace').decode('ascii')
164         print(f"{status}{record['产品名称']}:{original_display} -> {price_display}")
165 
166     if len(cleanedrecords) > 5:
167         print(f"...还有{len(cleanedrecords) - 5}条")
168 
169     print("4、保存清洗结果")
170     save_cleaned_data(cleanedrecords, outputfile)
171 
172     print("5、显示统计信息")
173     show_statistics(cleanedrecords)
174 
175     print("\n6. 清洗规则说明:")
176     print("  - 移除货币符号:YEN, DOLLAR, EURO, POUND")
177     print("  - 移除千位分隔符:,")
178     print("  - 移除单位后缀:YUAN/PIECE, YUAN, PIECE")
179     print("  - 移除emoji符号")
180     print("  - 处理空值和异常值")
181 
182 if __name__ == "__main__":
183     main()
View Code
posted @ 2026-08-28 10:53  Purplerr  阅读(0)  评论(0)    收藏  举报