🔥本期内容已收录至专栏《Python爬虫实战》,持续完善知识体系与项目实战,建议先订阅收藏,后续查阅更方便~持续更新中!!

全文目录:
-
-
- 🌟开篇语
- [📌 上期回顾](#📌 上期回顾)
- [🎯 本节目标](#🎯 本节目标)
- 一、字符编码:解决乱码问题
-
- [1.1 为什么会出现乱码?](#1.1 为什么会出现乱码?)
- [1.2 常见编码格式](#1.2 常见编码格式)
- [1.3 正确获取网页内容](#1.3 正确获取网页内容)
- [1.4 实用的编码处理函数](#1.4 实用的编码处理函数)
- [1.5 保存文件时的编码问题](#1.5 保存文件时的编码问题)
- 二、时区与时间格式:让时间对得上
-
- [2.1 常见的时间坑](#2.1 常见的时间坑)
- [2.2 标准化时间处理](#2.2 标准化时间处理)
- [2.3 时区转换](#2.3 时区转换)
- 三、空值处理:避免程序崩溃
-
- [3.1 Python 中的"空"](#3.1 Python 中的"空")
- [3.2 安全提取字段的最佳实践](#3.2 安全提取字段的最佳实践)
- [3.3 空值清洗函数](#3.3 空值清洗函数)
- [3.4 pandas 中的空值处理](#3.4 pandas 中的空值处理)
- 四、脏数据识别与清洗
-
- [4.1 什么是脏数据?](#4.1 什么是脏数据?)
- [4.2 重复数据检测](#4.2 重复数据检测)
- [4.3 异常值检测](#4.3 异常值检测)
- [4.4 HTML 标签清洗](#4.4 HTML 标签清洗)
- [4.5 数据清洗工具包](#4.5 数据清洗工具包)
- 五、数据质量报告(工程化思维)
-
- [5.1 质量指标定义](#5.1 质量指标定义)
- [5.2 数据验证规则](#5.2 数据验证规则)
- 六、本节小结
- 📝后作业(必做,验收进入第二章)
- [🔮 下期预告](#🔮 下期预告)
- 🌟文末
-
- [📌 专栏持续更新中|建议收藏 + 订阅](#📌 专栏持续更新中|建议收藏 + 订阅)
- [✅ 互动征集](#✅ 互动征集)
-
🌟开篇语
哈喽,各位小伙伴们你们好呀~我是【喵手】。
运营社区: C站 / 掘金 / 腾讯云 / 阿里云 / 华为云 / 51CTO
欢迎大家常来逛逛,一起学习,一起进步~🌟
我长期专注 Python 爬虫工程化实战 ,主理专栏 👉 《Python爬虫实战》:从采集策略 到反爬对抗 ,从数据清洗 到分布式调度 ,持续输出可复用的方法论与可落地案例。内容主打一个"能跑、能用、能扩展 ",让数据价值真正做到------抓得到、洗得净、用得上。
📌 专栏食用指南(建议收藏)
- ✅ 入门基础:环境搭建 / 请求与解析 / 数据落库
- ✅ 进阶提升:登录鉴权 / 动态渲染 / 反爬对抗
- ✅ 工程实战:异步并发 / 分布式调度 / 监控与容错
- ✅ 项目落地:数据治理 / 可视化分析 / 场景化应用
📣 专栏推广时间 :如果你想系统学爬虫,而不是碎片化东拼西凑,欢迎订阅/关注专栏《Python爬虫实战》
订阅后更新会优先推送,按目录学习更高效~
📌 上期回顾
在上一节《接口数据基础:JSON 是什么?分页是什么?》中,我们学习了如何处理结构化的 JSON 数据和三种分页模式。你已经能够从接口获取数据并进行基本解析了。
但是,当你真正开始采集数据后,会遇到各种"意外状况":中文变成乱码、时间对不上、程序突然崩溃...这些都是新手最容易踩的坑!⚠️
这一节,我们将系统性地学习数据质量处理,让你的爬虫更加稳定可靠。从此告别"能跑就行",迈向工程化!💪
🎯 本节目标
通过本节学习,你将能够:
- 理解并解决字符编码问题(UTF-8/GBK/乱码)
- 正确处理时区转换和时间格式
- 优雅地处理空值、None、NaN
- 识别和清洗脏数据(异常值、重复数据)
- 建立"数据质量意识"的工程思维
- 交付验收:编写清洗函数工具包(日期/金额/空值处理)
一、字符编码:解决乱码问题
1.1 为什么会出现乱码?
常见场景:
python
# 你采集到的数据
"æ--°é--->>æ ‡é¢˜" # 😱 这是什么鬼?
原因:数据的编码方式与解码方式不匹配。
json
原始文本:新闻标题
↓ 用 UTF-8 编码
字节序列:\xe6\x96\xb0\xe9\x97\xbb...
↓ 错误地用 GBK 解码
乱码结果:æ--°é--->>...
1.2 常见编码格式
| 编码格式 | 特点 | 使用场景 |
|---|---|---|
| UTF-8 | 国际标准,支持所有语言 | 现代网站、API 接口 |
| GBK/GB2312 | 中文编码 | 老旧的中文网站 |
| ISO-8859-1 | 西欧编码 | 部分国外网站 |
| Big5 | 繁体中文 | 台湾、香港网站 |
1.3 正确获取网页内容
requests 的编码处理:
python
import requests
# ❌ 错误做法
response = requests.get(url)
html = response.text # 可能乱码
# ✅ 方法1:指定编码
response = requests.get(url)
response.encoding = 'utf-8' # 或 'gbk'
html = response.text
# ✅ 方法2:从响应头自动检测
response = requests.get(url)
# requests 会自动从 Content-Type 检测编码
# 如果检测错误,手动指定
if response.encoding == 'ISO-8859-1':
response.encoding = response.apparent_encoding # 智能检测
html = response.text
# ✅ 方法3:使用字节内容(最可靠)
response = requests.get(url)
# 从 HTML 的 <meta charset="..."> 标签检测编码
import chardet
encoding = chardet.detect(response.content)['encoding']
html = response.content.decode(encoding)
1.4 实用的编码处理函数
python
import chardet
def safe_decode(response):
"""
安全解码响应内容
Args:
response: requests.Response 对象
Returns:
str: 解码后的文本
"""
# 1. 尝试使用响应头中声明的编码
if response.encoding and response.encoding != 'ISO-8859-1':
try:
return response.text
except Exception:
pass
# 2. 使用 chardet 检测编码
detected = chardet.detect(response.content)
encoding = detected['encoding']
confidence = detected['confidence']
print(f"检测到编码: {encoding} (置信度: {confidence:.2f})")
# 3. 尝试解码
try:
return response.content.decode(encoding)
except Exception:
# 4. 降级处理:忽略错误字符
return response.content.decode(encoding, errors='ignore')
# 使用示例
response = requests.get(url)
html = safe_decode(response)
1.5 保存文件时的编码问题
python
# ❌ 可能出错
with open('data.txt', 'w') as f: # 默认编码因系统而异
f.write(text)
# ✅ 正确做法:明确指定 UTF-8
with open('data.txt', 'w', encoding='utf-8') as f:
f.write(text)
# ✅ 保存 CSV 时(Excel 兼容)
import pandas as pd
df.to_csv('data.csv', encoding='utf-8-sig', index=False)
# utf-8-sig 会添加 BOM,Excel 打开不乱码
二、时区与时间格式:让时间对得上
2.1 常见的时间坑
问题1:时区混乱
python
# 服务器返回的是 UTC 时间
server_time = "2025-01-21 02:00:00"
# 你在北京(UTC+8),实际时间应该是
correct_time = "2025-01-21 10:00:00"
问题2:格式不统一
python
# 各种奇葩格式
"2025-01-21 10:00:00"
"2025/01/21 10:00:00"
"01-21-2025 10:00 AM"
"2025年1月21日 10时00分"
"1705824000" # Unix 时间戳
"3小时前"
"昨天 15:30"
2.2 标准化时间处理
python
from datetime import datetime, timezone, timedelta
import time
class TimeParser:
"""时间解析工具类"""
@staticmethod
def parse_timestamp(ts, tz_offset=8):
"""
解析 Unix 时间戳
Args:
ts: 时间戳(秒或毫秒)
tz_offset: 时区偏移(东八区=8)
Returns:
datetime: 本地时间对象
"""
# 判断是秒还是毫秒
if ts > 10000000000: # 毫秒级时间戳
ts = ts / 1000
# 转换为 datetime
dt = datetime.fromtimestamp(ts)
return dt
@staticmethod
def parse_string(date_str):
"""
智能解析日期字符串
Args:
date_str: 日期字符串
Returns:
datetime: 时间对象
"""
# 尝试多种格式
formats = [
'%Y-%m-%d %H:%M:%S',
'%Y/%m/%d %H:%M:%S',
'%Y-%m-%d',
'%Y/%m/%d',
'%Y年%m月%d日 %H时%M分',
'%Y年%m月%d日',
]
for fmt in formats:
try:
return datetime.strptime(date_str, fmt)
except ValueError:
continue
# 都不匹配,返回 None
return None
@staticmethod
def parse_relative(relative_str):
"""
解析相对时间(如"3小时前")
Args:
relative_str: 相对时间描述
Returns:
datetime: 计算后的时间对象
"""
now = datetime.now()
if '分钟前' in relative_str:
minutes = int(relative_str.replace('分钟前', ''))
return now - timedelta(minutes=minutes)
if '小时前' in relative_str:
hours = int(relative_str.replace('小时前', ''))
return now - timedelta(hours=hours)
if '天前' in relative_str or '昨天' in relative_str:
days = 1 if '昨天' in relative_str else int(relative_str.replace('天前', ''))
return now - timedelta(days=days)
return None
@staticmethod
def to_standard(dt):
"""
转换为标准格式字符串
Args:
dt: datetime 对象
Returns:
str: 标准格式 "YYYY-MM-DD HH:MM:SS"
"""
if dt is None:
return None
return dt.strftime('%Y-%m-%d %H:%M:%S')
# 使用示例
parser = TimeParser()
# 示例1:Unix 时间戳
ts = 1705824000
dt1 = parser.parse_timestamp(ts)
print(parser.to_standard(dt1)) # "2025-01-21 10:00:00"
# 示例2:日期字符串
date_str = "2025年1月21日 10时00分"
dt2 = parser.parse_string(date_str)
print(parser.to_standard(dt2))
# 示例3:相对时间
relative = "3小时前"
dt3 = parser.parse_relative(relative)
print(parser.to_standard(dt3))
2.3 时区转换
python
from datetime import datetime, timezone, timedelta
# 创建带时区的时间对象
utc_time = datetime(2025, 1, 21, 2, 0, 0, tzinfo=timezone.utc)
# 转换到东八区(北京时间)
beijing_tz = timezone(timedelta(hours=8))
beijing_time = utc_time.astimezone(beijing_tz)
print(f"UTC时间: {utc_time}")
print(f"北京时间: {beijing_time}")
# 输出相差 8 小时
# 或者使用 pytz(更强大,支持夏令时)
import pytz
utc = pytz.UTC
beijing = pytz.timezone('Asia/Shanghai')
utc_time = datetime(2025, 1, 21, 2, 0, 0, tzinfo=utc)
beijing_time = utc_time.astimezone(beijing)
三、空值处理:避免程序崩溃
3.1 Python 中的"空"
python
# Python 中有多种"空"的表示
None # Python 的空对象
"" # 空字符串
[] # 空列表
{} # 空字典
0 # 数字零(有时也被当作"空")
False # 布尔假值
NaN # pandas 中的缺失值
3.2 安全提取字段的最佳实践
python
# ❌ 危险的做法
title = news['title'] # KeyError if 'title' not in news
author = news['meta']['author'] # KeyError if 'meta' not exist
# ✅ 方法1:使用 get() 方法
title = news.get('title', '无标题')
author = news.get('meta', {}).get('author', '佚名')
# ✅ 方法2:封装安全提取函数
def safe_get(data, *keys, default=None):
"""
安全地从嵌套字典提取值
Args:
data: 字典对象
*keys: 键的路径
default: 默认值
Returns:
提取的值或默认值
Example:
>>> safe_get(news, 'meta', 'author', default='佚名')
"""
for key in keys:
if isinstance(data, dict):
data = data.get(key)
if data is None:
return default
else:
return default
return data if data is not None else default
# 使用示例
author = safe_get(news, 'meta', 'author', default='佚名')
tags = safe_get(news, 'tags', default=[])
3.3 空值清洗函数
python
def clean_text(text):
"""
清洗文本字段
- 去除首尾空白
- 将 None 转为空字符串
- 压缩多余空白
"""
if text is None:
return ""
if not isinstance(text, str):
text = str(text)
# 去除首尾空白
text = text.strip()
# 压缩多余空白(多个空格/换行变成一个空格)
import re
text = re.sub(r'\s+', ' ', text)
# 去除零宽字符等特殊字符
text = text.replace('\u200b', '') # 零宽空格
text = text.replace('\ufeff', '') # BOM
return text
def clean_number(value):
"""
清洗数值字段
- 将 None 转为 0 或 None(根据需求)
- 处理带单位的数字(如 "1.2万")
"""
if value is None or value == "":
return 0 # 或返回 None
if isinstance(value, (int, float)):
return value
# 处理带单位的数字
if isinstance(value, str):
value = value.strip()
# "1.2万" -> 12000
if '万' in value:
num = float(value.replace('万', ''))
return int(num * 10000)
# "1.2k" -> 1200
if 'k' in value.lower():
num = float(value.lower().replace('k', ''))
return int(num * 1000)
# 去除逗号分隔符 "1,234" -> 1234
value = value.replace(',', '')
try:
return float(value)
except ValueError:
return 0
# 使用示例
print(clean_text(" 这是标题 \n\n ")) # "这是标题"
print(clean_number("1.2万")) # 12000
print(clean_number(None)) # 0
3.4 pandas 中的空值处理
python
import pandas as pd
import numpy as np
# 创建示例数据
data = {
'title': ['新闻A', None, '新闻C', ''],
'views': [1000, np.nan, 2000, None],
'author': ['张三', '李四', None, '王五']
}
df = pd.DataFrame(data)
# 检查空值
print("空值统计:")
print(df.isnull().sum())
# title 1
# views 2
# author 1
# 填充空值
df['title'] = df['title'].fillna('无标题')
df['views'] = df['views'].fillna(0)
df['author'] = df['author'].fillna('佚名')
# 删除包含空值的行
df_clean = df.dropna()
# 删除完全为空的行
df_clean = df.dropna(how='all')
# 只要某些列不为空就保留
df_clean = df.dropna(subset=['title', 'author'])
四、脏数据识别与清洗
4.1 什么是脏数据?
常见类型:
- 重复数据:同一条新闻采集多次
- 异常值:阅读量显示 999999999
- 格式错误:日期字段出现 "N/A"
- 逻辑错误:发布时间在未来
- **HTML标>正文内容`
4.2 重复数据检测
python
def detect_duplicates(data_list, key_field='id'):
"""
检测重复数据
Args:
data_list: 数据列表
key_field: 用于去重的字段
Returns:
tuple: (去重后数据, 重复记录)
"""
seen = set()
unique_data = []
duplicates = []
for item in data_list:
key_value = item.get(key_field)
if key_value in seen:
duplicates.append(item)
else:
seen.add(key_value)
unique_data.append(item)
print(f"总记录数: {len(data_list)}")
print(f"唯一记录: {len(unique_data)}")
print(f"重复记录: {len(duplicates)}")
print(f"重复率: {len(duplicates)/len(data_list)*100:.2f}%")
return unique_data, duplicates
# 使用 pandas 去重
df_unique = df.drop_duplicates(subset=['id'], keep='first')
# keep='first': 保留第一次出现的
# keep='last': 保留最后一次出现的
# keep=False: 删除所有重复项
4.3 异常值检测
python
def detect_outliers(df, column, method='iqr'):
"""
检测数值型字段的异常值
Args:
df: DataFrame
column: 列名
method: 检测方法 ('iqr' 或 'zscore')
Returns:
Series: 布尔值,True 表示异常
"""
if method == 'iqr':
# 四分位距法(IQR)
Q1 = df[column].quantile(0.25)
Q3 = df[column].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
outliers = (df[column] < lower_bound) | (df[column] > upper_bound)
elif method == 'zscore':
# Z-score 方法
from scipy import stats
z_scores = np.abs(stats.zscore(df[column].dropna()))
outliers = z_scores > 3
print(f"{column} 字段异常值:")
print(f" 下界: {lower_bound:.2f}")
print(f" 上界: {upper_bound:.2f}")
print(f" 异常数量: {outliers.sum()}")
return outliers
# 使用示例
outliers = detect_outliers(df, 'views')
print("异常数据:")
print(df[outliers])
4.4 HTML 标签清洗
python
from html import unescape
import re
def clean_html(text):
"""
清除 HTML 标签和实体
Args:
text: 包含 HTML 的文本
Returns:
str: 纯文本
"""
if not text:
return ""
# 1. 解码 HTML 实体
text = unescape(text)
# < -> <, > -> >, & -> &
# 2. 移除 script 和 style 标签及内容
text = re.sub(r'<script[^>]*>.*?</script>', '', text, flags=re.DOTALL)
text = re.sub(r'<style[^>]*>.*?</style>', '', text, flags=re.DOTALL)
# 3. 移除所有 HTML 标签
text = re.sub(r'<[^>]+>', '', text)
# 4. 清理多余空白
text = re.sub(r'\s+', ' ', text).strip()
return text
# 使用示例
html_text = "<p>这是<strong>重要</strong>内容 <test></p>"
clean = clean_html(html_text)
print(clean) # "这是重要内容 <test>"
4.5 数据清洗工具包
python
class DataCleaner:
"""数据清洗工具类"""
@staticmethod
def clean_title(title):
"""清洗标题字段"""
if not title:
return "无标题"
title = clean_html(title)
title = clean_text(title)
# 限制长度
if len(title) > 100:
title = title[:100] + "..."
return title
@staticmethod
def clean_amount(amount_str):
"""
清洗金额字段
Examples:
"¥1,234.56" -> 1234.56
"$1.2k" -> 1200
"1.5万元" -> 15000
"""
if not amount_str:
return 0.0
# 转字符串
amount_str = str(amount_str).strip()
# 去除货币符号
amount_str = re.sub(r'[¥$¥€£]', '', amount_str)
# 去除单位
amount_str = amount_str.replace('元', '').replace('美元', '')
# 处理 k/w 单位
return clean_number(amount_str)
@staticmethod
def validate_date(date_str):
"""
验证日期合理性
Returns:
bool: 是否合理
"""
try:
dt = TimeParser.parse_string(date_str)
if dt is None:
return False
# 检查是否在合理范围内
from datetime import datetime
now = datetime.now()
# 不能是未来时间
if dt > now:
return False
# 不能太久远(比如不早于 1990 年)
if dt.year < 1990:
return False
return True
except Exception:
return False
@staticmethod
def clean_record(record):
"""
清洗单条记录
Args:
record: 字典格式的原始记录
Returns:
dict: 清洗后的记录
"""
cleaned = {}
# 标题
cleaned['title'] = DataCleaner.clean_title(
record.get('title')
)
# 作者
cleaned['author'] = clean_text(
record.get('author', '佚名')
)
# 发布时间
publish_time = record.get('publish_time')
if DataCleaner.validate_date(publish_time):
cleaned['publish_time'] = publish_time
else:
cleaned['publish_time'] = None
# 阅读量
cleaned['views'] = clean_number(
record.get('views', 0)
)
# 正文
content = record.get('content', '')
cleaned['content'] = clean_html(content)
# URL
cleaned['url'] = record.get('url', '')
return cleaned
# 批量清洗
def batch_clean(records):
"""批量清洗数据"""
cleaner = DataCleaner()
cleaned_records = []
error_count = 0
for i, record in enumerate(records):
try:
cleaned = cleaner.clean_record(record)
cleaned_records.append(cleaned)
except Exception as e:
print(f"记录 {i} 清洗失败: {e}")
error_count += 1
print(f"\n清洗完成:")
print(f" 成功: {len(cleaned_records)}")
print(f" 失败: {error_count}")
return cleaned_records
五、数据质量报告(工程化思维)
5.1 质量指标定义
python
def generate_quality_report(df):
"""
生成数据质量报告
Args:
df: pandas DataFrame
Returns:
dict: 质量指标
"""
report = {
'total_records': len(df),
'fields': {}
}
for col in df.columns:
field_report = {
'missing_count': df[col].isnull().sum(),
'missing_rate': df[col].isnull().sum() / len(df) * 100,
'unique_count': df[col].nunique(),
'duplicate_rate': (len(df) - df[col].nunique()) / len(df) * 100
}
# 数值型字段的统计
if df[col].dtype in ['int64', 'float64']:
field_report.update({
'min': df[col].min(),
'max': df[col].max(),
'mean': df[col].mean(),
'median': df[col].median()
})
report['fields'][col] = field_report
return report
def print_quality_report(report):
"""打印质量报告"""
print("=" * 60)
print("数据质量报告")
print("=" * 60)
print(f"\n总记录数: {report['total_records']}")
for field, metrics in report['fields'].items():
print(f"\n【{field}】")
print(f" 缺失数量: {metrics['missing_count']}")
print(f" 缺失率: {metrics['missing_rate']:.2f}%")
print(f" 唯一值数: {metrics['unique_count']}")
print(f" 重复率: {metrics['duplicate_rate']:.2f}%")
if 'mean' in metrics:
print(f" 均值: {metrics['mean']:.2f}")
print(f" 中位数: {metrics['median']:.2f}")
print(f" 范围: [{metrics['min']}, {metrics['max']}]")
print("\n" + "=" * 60)
# 使用示例
report = generate_quality_report(df)
print_quality_report(report)
5.2 数据验证规则
python
class DataValidator:
"""数据验证器"""
@staticmethod
def validate_record(record, rules):
"""
验证单条记录
Args:
record: 记录字典
rules: 验证规则字典
Returns:
tuple: (is_valid, errors)
"""
errors = []
for field, rule in rules.items():
value = record.get(field)
# 必填项检查
if rule.get('required') and not value:
errors.append(f"{field} 为必填项")
continue
if value is None:
continue
# 类型检查
expected_type = rule.get('type')
if expected_type and not isinstance(value, expected_type):
errors.append(f"{field} 类型错误,期望 {expected_type}")
# 长度检查
if 'max_length' in rule:
if len(str(value)) > rule['max_length']:
errors.append(f"{field} 超过最大长度 {rule['max_length']}")
# 数值范围检查
if 'min_value' in rule:
if value < rule['min_value']:
errors.append(f"{field} 小于最小值 {rule['min_value']}")
if 'max_value' in rule:
if value > rule['max_value']:
errors.append(f"{field} 超过最大值 {rule['max_value']}")
# 正则检查
if 'pattern' in rule:
import re
if not re.match(rule['pattern'], str(value)):
errors.append(f"{field} 格式不符合规则")
return len(errors) == 0, errors
# 定义验证规则
validation_rules = {
'title': {
'required': True,
'type': str,
'max_length': 200
},
'author': {
'required': True,
'type': str
},
'views': {
'type': (int, float),
'min_value': 0,
'max_value': 10000000
},
'url': {
'required': True,
'pattern': r'^https?://.+'
}
}
# 使用示例
validator = DataValidator()
is_valid, errors = validator.validate_record(record, validation_rules)
if not is_valid:
print(f"验证失败: {errors}")
六、本节小结
本节我们系统学习了数据质量处理的核心技能:
✅ 字符编码 :解决乱码问题,正确处理 UTF-8/GBK 等编码
✅ 时间处理 :统一时区、标准化格式、解析相对时间
✅ 空值处理 :安全提取字段、优雅处理 None
✅ 脏数据清洗 :去重、异常值检测、HTML 标签清理
✅ 质量意识:生成质量报告、定义验证规则
核心原则:
- 先保证正确,再谈快------数据质量比速度更重要
- 失败要优雅------用 try-except 和默认值避免崩溃
- 留下原始数据------清洗前保存原文,便于问题追溯
- 建立验证机制------用质量报告发现潜在问题
📝后作业(必做,验收进入第二章)
任务1:编写清洗工具包
创建 cleaner_utils.py,实现以下函数:
python
def clean_text(text):
"""清洗文本:去空白、去HTML、统一格式"""
pass
def parse_date(date_input):
"""智能解析日期:支持多种格式和相对时间"""
pass
def clean_amount(amount_str):
"""清洗金额:处理单位、货币符号"""
pass
def validate_url(url):
"""验证 URL 格式是否正确"""
pass
测试用例:
python
# 测试文本清洗
assert clean_text(" 标题\n\n ") == "标题"
assert clean_text("<p>内容</p>") == "内容"
# 测试日期解析
assert parse_date("2025-01-21 10:00:00") is not None
assert parse_date("3小时前") is not None
# 测试金额清洗
assert clean_amount("1.2万") == 12000
assert clean_amount("$1,234.56") == 1234.56
print("✅ 所有测试通过!")
任务2:数据质量分析
选择你之前采集的数据(或使用提供的测试数据),完成:
- 生成数据质量报告(缺失率、重复率)
- 识别异常值并截图
- 编写清洗脚本,输出清洗前后对比
任务3:处理真实的脏数据
处理以下测试数据(故意包含问题):
python
dirty_data = [
{"title": " <p>新闻A</p> ", "views": "1.2万", "date": "2025-01-21"},
{"title": None, "views": "999999999", "date": "3小时前"},
{"title": "新闻C", "views": None, "date": "2030-01-01"}, # 未来时间
{"title": "新闻A", "views": "8500", "date": "2025/01/20"}, # 重复
]
要求清洗后输出标准格式的数据。
验收方式:在留言区提交:
- 清洗工具包代码和测试结果截图
- 数据质量报告截图
- 脏数据清洗前后对比
- 遇到的问题和解决方法
🔮 下期预告
恭喜完成第一章!🎉 下一章《Requests 静态爬取入门》,我们将进入实战阶段:
- 编写你的第一个完整爬虫
- 使用 Session 管理会话和 Cookie
- 实现超时、重试、退避策略
- 完成"列表页→详情页"两段式采集
- 设计限速器,礼貌爬取
预习建议 :
安装 requests 库,复习 HTTP 请求的基本概念。思考:如果一个请求失败了,应该立即重试还是等待一段时间?
💬 第一章完成了!数据质量是爬虫的生命线! 💪✨
记住:"垃圾进,垃圾出"(Garbage In, Garbage Out)。花时间做好数据清洗,后续的分析和应用才有价值。工程师要对数据质量负责!😊🔧
🌟文末
好啦~以上就是本期 《Python爬虫实战》的全部内容啦!如果你在实践过程中遇到任何疑问,欢迎在评论区留言交流,我看到都会尽量回复~咱们下期见!
小伙伴们在批阅的过程中,如果觉得文章不错,欢迎点赞、收藏、关注哦~
三连就是对我写作道路上最好的鼓励与支持! ❤️🔥
📌 专栏持续更新中|建议收藏 + 订阅
专栏 👉 《Python爬虫实战》,我会按照"入门 → 进阶 → 工程化 → 项目落地"的路线持续更新,争取让每一篇都做到:
✅ 讲得清楚(原理)|✅ 跑得起来(代码)|✅ 用得上(场景)|✅ 扛得住(工程化)
📣 想系统提升的小伙伴:强烈建议先订阅专栏,再按目录顺序学习,效率会高很多~

✅ 互动征集
想让我把【某站点/某反爬/某验证码/某分布式方案】写成专栏实战?
评论区留言告诉我你的需求,我会优先安排更新 ✅
⭐️ 若喜欢我,就请关注我叭~(更新不迷路)
⭐️ 若对你有用,就请点赞支持一下叭~(给我一点点动力)
⭐️ 若有疑问,就请评论留言告诉我叭~(我会补坑 & 更新迭代)
免责声明:本文仅用于学习与技术研究,请在合法合规、遵守站点规则与 Robots 协议的前提下使用相关技术。严禁将技术用于任何非法用途或侵害他人权益的行为。