Python 爬虫数据清洗与入库:汽车之家 5 万条参数数据去重与结构化实战

📅 2026/7/5 21:53:23
Python 爬虫数据清洗与入库:汽车之家 5 万条参数数据去重与结构化实战
Python 爬虫数据清洗与入库汽车之家 5 万条参数数据去重与结构化实战1. 数据清洗的核心挑战与解决方案爬虫获取的原始数据往往存在多种质量问题汽车参数数据尤为典型。以汽车之家为例我们常遇到以下三类问题重复数据问题通常表现为同一车型因分页抓取导致重复记录停售/在售状态切换产生的版本冗余参数更新时新旧数据同时存在缺失值问题的典型场景包括非标配参数显示为暂无或空字符串动态加载失败的字段厂商未公开的敏感参数格式不一致问题主要体现在排量单位混用1.5L vs 1498ml驱动方式表述差异前置前驱 vs 前驱布尔值多种表示是/否、有/无、✔/×# 典型的数据清洗流程示例 def clean_engine_capacity(text): 统一排量单位到毫升 if pd.isna(text): return np.nan if L in text: return float(text.replace(L,)) * 1000 return float(text)2. Pandas 高效清洗实战2.1 数据加载与初步观察使用 Pandas 的灵活 IO 能力处理多种数据源# 从不同数据源加载 sources { csv: pd.read_csv(raw_data.csv), json: pd.read_json(api_data.json), mysql: pd.read_sql(SELECT * FROM temp_table, conengine) } raw_df pd.concat(sources.values(), ignore_indexTrue) print(f初始数据量{len(raw_df):,}条)2.2 结构化字段提取技巧汽车参数常以键值对形式存储需转换为结构化字段原始数据示例发动机1.5T 180马力 L4 | 变速箱7挡双离合转换后结构| 发动机型号 | 排量(L) | 马力(Ps) | 气缸排列 | 变速箱类型 | |------------|---------|----------|----------|--------------| | 1.5T | 1.5 | 180 | L4 | 7挡双离合 |正则表达式提取模板engine_pattern r(?Pdisplacement\d\.?\d*)(?Pengine_type[T|L])\s*(?Php\d)马力\s*(?Pcylinder[V|L]\d) trans_pattern r(?Pgears\d)挡(?Ptrans_type.离合)2.3 高级去重策略多维度组合去重比单一主键更可靠# 构建复合去重键 dup_cols [brand, series, model_year, engine_code] df_dedup raw_df.drop_duplicates( subsetdup_cols, keeplast # 保留最新版本 ) # 相似度去重针对文本描述 from difflib import SequenceMatcher def is_similar(a, b, threshold0.9): return SequenceMatcher(None, a, b).ratio() threshold3. MySQL 数据库设计与优化3.1 表结构设计原则汽车参数数据库应遵循以下设计规范主表结构CREATE TABLE vehicles ( id INT AUTO_INCREMENT PRIMARY KEY, brand_id SMALLINT NOT NULL, series_id MEDIUMINT NOT NULL, model_name VARCHAR(60) NOT NULL, model_year SMALLINT NOT NULL, is_on_sale BOOLEAN DEFAULT TRUE, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX idx_brand (brand_id), INDEX idx_series (series_id), UNIQUE KEY uk_model (series_id, model_name, model_year) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;参数明细表CREATE TABLE vehicle_specs ( vehicle_id INT NOT NULL, spec_type ENUM(performance, dimension, feature) NOT NULL, spec_name VARCHAR(40) NOT NULL, spec_value TEXT, unit VARCHAR(10), PRIMARY KEY (vehicle_id, spec_type, spec_name), FOREIGN KEY (vehicle_id) REFERENCES vehicles(id) ON DELETE CASCADE ) ENGINEInnoDB;3.2 批量插入性能优化使用 executemany 事务提升写入效率from sqlalchemy import create_engine engine create_engine( mysqlpymysql://user:passlocalhost/cars?charsetutf8mb4, pool_recycle3600 ) def batch_insert(df, table_name, batch_size1000): with engine.begin() as conn: for i in range(0, len(df), batch_size): batch df.iloc[i:ibatch_size] batch.to_sql( table_name, conn, if_existsappend, indexFalse, methodmulti )4. 全流程自动化实现4.1 数据质量监控体系建立自动化数据校验机制# 数据质量检查函数 def validate_data(df): rules { price: lambda x: x 10000, length: lambda x: 2000 x 6000, engine: lambda x: x in [L4, V6, V8, W12] } errors {} for col, rule in rules.items(): mask ~df[col].apply(rule) errors[col] df[mask][[brand, series]].values.tolist() return errors4.2 自动化调度方案使用 Airflow 构建数据处理流水线from airflow import DAG from airflow.operators.python import PythonOperator default_args { retries: 3, retry_delay: timedelta(minutes5) } with DAG(car_data_pipeline, schedule_intervaldaily) as dag: scrape_task PythonOperator( task_idscrape_data, python_callablerun_spider ) clean_task PythonOperator( task_idclean_data, python_callableclean_raw_data ) load_task PythonOperator( task_idload_to_db, python_callableimport_to_mysql ) notify_task PythonOperator( task_idsend_report, python_callablesend_quality_report ) scrape_task clean_task load_task notify_task5. 实战经验与避坑指南字符集陷阱MySQL 的 utf8 实际是阉割版应始终使用 utf8mb4车辆名称中的特殊字符如Škoda需要特别注意性能优化技巧加载数据时临时禁用索引ALTER TABLE ... DISABLE KEYS使用 LOAD DATA INFILE 替代 INSERT 语句批量操作时调整 transaction_isolation异常处理模式from contextlib import contextmanager contextmanager def db_transaction(): conn engine.connect() trans conn.begin() try: yield conn trans.commit() except Exception as e: trans.rollback() logger.error(fDatabase error: {str(e)}) raise finally: conn.close() # 使用示例 with db_transaction() as conn: conn.execute(UPDATE inventory SET stock stock - 1 WHERE item_id 123)