数据清洗与预处理完全指南

正则表达式、数据验证、格式转换实战

一、为什么数据清洗很重要

做爬虫这几年,最大的体会是:采集数据只占 20% 的工作量,处理数据占 80%。原始数据往往是脏的、乱的、不完整的,如果不做清洗,后续分析根本没法做。

数据清洗的目标很简单:让数据变得干净、规范、可用。这篇文章把我常用的清洗技巧整理出来,希望能帮你少走弯路。

常见的数据问题
  • HTML 标签残留
  • 多余空格和换行
  • 编码不一致
  • 格式不统一
  • 缺失值
  • 重复数据

二、正则表达式基础

正则表达式是数据清洗的利器。学会它,处理文本数据效率提升十倍。

2.1 常用元字符

元字符 含义 示例
. 任意字符 a.c 匹配 abc、acc
* 0 次或多次 ab* 匹配 a、ab、abb
+ 1 次或多次 ab+ 匹配 ab、abb
? 0 次或 1 次 ab? 匹配 a、ab
\d 数字 \d+ 匹配 123
\w 字母、数字、下划线 \w+ 匹配 abc_123
\s 空白字符 \s+ 匹配空格、换行

2.2 实战示例

import re # 提取手机号 text = '联系电话:138-1234-5678' phone = re.search(r'1[3-9]\d{9}', text.replace('-', '')) print(phone.group()) # 13812345678 # 提取邮箱 text = '邮箱:zhangsan@example.com' email = re.search(r'\w+@\w+\.\w+', text) print(email.group()) # zhangsan@example.com # 提取 URL text = '访问 https://example.com/page 获取更多信息' url = re.search(r'https?://[^\s]+', text) print(url.group()) # https://example.com/page

三、常见清洗操作

3.1 去除 HTML 标签

import re from html import unescape def clean_html(html): """去除 HTML 标签""" # 去除 script 和 style html = re.sub(r'<(script|style)[^>]*>[^<]*', '', html, flags=re.I) # 去除 HTML 标签 text = re.sub(r'<[^>]+>', '', html) # 解码 HTML 实体 text = unescape(text) # 去除多余空白 text = re.sub(r'\s+', ' ', text).strip() return text # 使用 html = '

Hello <World>!

' text = clean_html(html) print(text) # Hello !

3.2 去除特殊字符

import re def clean_text(text): """清洗文本""" # 去除不可见字符 text = re.sub(r'[\x00-\x08\x0b-\x0c\x0e-\x1f]', '', text) # 去除零宽字符 text = re.sub(r'[\u200b-\u200f\ufeff]', '', text) # 去除多余空格 text = re.sub(r'\s+', ' ', text).strip() return text # 使用 text = 'Hello\x00World\u200b!' cleaned = clean_text(text) print(cleaned) # Hello World!

3.3 处理缺失值

def clean_data(data, default=''): """清洗数据,处理缺失值""" if data is None: return default if isinstance(data, str): data = data.strip() if data in ('', 'null', 'None', 'NULL'): return default return data # 使用 data = { 'name': ' 张三 ', 'age': None, 'email': 'null' } cleaned = {k: clean_data(v) for k, v in data.items()} print(cleaned) # {'name': '张三', 'age': '', 'email': ''}

四、数据验证

4.1 验证手机号

import re def validate_phone(phone): """验证手机号""" pattern = r'^1[3-9]\d{9}$' return bool(re.match(pattern, phone)) # 使用 print(validate_phone('13812345678')) # True print(validate_phone('1381234567')) # False

4.2 验证邮箱

import re def validate_email(email): """验证邮箱""" pattern = r'^[\w.-]+@[\w.-]+\.\w+$' return bool(re.match(pattern, email)) # 使用 print(validate_email('zhangsan@example.com')) # True print(validate_email('invalid.email')) # False

4.3 验证身份证号

import re def validate_id_card(id_card): """验证身份证号""" pattern = r'^\d{17}[\dXx]$' return bool(re.match(pattern, id_card)) # 使用 print(validate_id_card('110101199001011234')) # True print(validate_id_card('11010119900101123X')) # True

五、格式转换

5.1 价格格式化

import re def parse_price(text): """解析价格""" # 提取数字 match = re.search(r'\d+\.?\d*', text) if match: return float(match.group()) return None # 使用 print(parse_price('¥199.99')) # 199.99 print(parse_price('价格:100元')) # 100.0

5.2 日期格式化

from datetime import datetime import re def parse_date(text): """解析日期""" formats = [ '%Y-%m-%d', '%Y/%m/%d', '%d/%m/%Y', '%Y年%m月%d日' ] for fmt in formats: try: return datetime.strptime(text, fmt) except ValueError: continue return None # 使用 print(parse_date('2024-01-15')) print(parse_date('2024年01月15日'))

六、总结

数据清洗是爬虫开发中不可或缺的环节。记住这几个核心要点:

  • 正则表达式是处理文本的利器,值得花时间学习
  • 清洗流程要标准化,写成可复用的函数
  • 数据验证要在入库前做,避免脏数据
  • 处理异常要优雅,不要因一条数据失败而中断整个流程