数据预处理入门学习教程,从入门到精通,数据获取 — 知识点详解与案例代码(4)

数据获取 --- 知识点详解与案例代码


一、从CSV和TXT文件读取数据

1.1 CSV文件概述

CSV(Comma-Separated Values)是一种以逗号分隔字段的纯文本文件格式,每行代表一条记录,每个字段之间用分隔符(通常为逗号)隔开。

1.2 使用pandas读取CSV文件

核心函数:pd.read_csv()

主要参数说明:

参数 说明
filepath_or_buffer 文件路径或URL
sep 分隔符,默认为逗号,
header 指定作为列名的行号,默认为0(第一行)
names 自定义列名列表
index_col 指定某列为行索引
usecols 指定读取的列
encoding 文件编码,如utf-8gbkgb2312
dtype 指定列的数据类型
skiprows 跳过前N行
nrows 只读取前N行数据
na_values 指定哪些值被视为缺失值
parse_dates 将指定列解析为日期类型
thousands 千位分隔符
skip_blank_lines 是否跳过空行,默认True
案例1:基本CSV读取
python 复制代码
# 导入pandas库,pandas是Python中最常用的数据分析库
import pandas as pd

# 读取CSV文件,返回一个DataFrame对象
# filepath_or_buffer参数指定文件路径
df = pd.read_csv('data/sales.csv')

# 查看DataFrame的前5行数据,了解数据的基本结构
print(df.head())

# 查看DataFrame的形状(行数, 列数)
print(df.shape)

# 查看DataFrame的基本信息,包括列名、数据类型、非空值数量等
print(df.info())

# 查看DataFrame的统计描述信息(仅数值列)
# 包括计数、均值、标准差、最小值、四分位数、最大值
print(df.describe())
案例2:指定分隔符和编码
python 复制代码
# 导入pandas库
import pandas as pd

# 读取以制表符分隔的TSV文件
# sep='\t'表示使用制表符作为字段分隔符
# encoding='utf-8'指定文件编码为UTF-8
df = pd.read_csv('data/info.tsv', sep='\t', encoding='utf-8')

# 打印读取的数据
print(df)

# 读取以分号分隔的CSV文件(常见于欧洲地区)
# sep=';'指定分号为分隔符
# encoding='gbk'指定GBK编码(常见于中文Windows系统导出的文件)
df2 = pd.read_csv('data/europe_data.csv', sep=';', encoding='gbk')

# 打印读取结果
print(df2)
案例3:自定义列名和选择列
python 复制代码
# 导入pandas库
import pandas as pd

# 读取CSV文件并自定义列名
# names参数传入一个列表,为每一列指定新的列名
# header=0表示原始文件第一行为列名(将被替换为names中的名称)
df = pd.read_csv('data/sales.csv',
                  header=0,
                  names=['日期', '产品', '数量', '单价', '总额'])

# 打印查看自定义列名后的数据
print(df.head())

# 只读取指定的列
# usecols参数传入列名列表,只加载需要的列,节省内存
df2 = pd.read_csv('data/sales.csv', usecols=['产品', '数量', '单价'])

# 打印只读取部分列的结果
print(df2.head())

# 也可以用列索引号来指定读取的列
# usecols=[0, 2] 表示只读取第1列和第3列
df3 = pd.read_csv('data/sales.csv', usecols=[0, 2])

# 打印结果
print(df3.head())
案例4:指定数据类型和缺失值处理
python 复制代码
# 导入pandas库
import pandas as pd

# 读取CSV文件并指定列的数据类型
# dtype参数用字典形式指定每列的数据类型
# 这在自动推断不准确时特别有用
df = pd.read_csv('data/employees.csv',
                  dtype={
                      'id': int,          # 将id列指定为整数类型
                      'name': str,        # 将name列指定为字符串类型
                      'salary': float     # 将salary列指定为浮点类型
                  })

# 指定哪些值应该被视为缺失值(NaN)
# na_values参数可以接受字符串、列表或字典
df2 = pd.read_csv('data/employees.csv',
                   na_values=['N/A', 'null', '--', '缺失', ''])

# 为不同的列指定不同的缺失值标记
# 使用字典形式,键为列名,值为该列的缺失值标记列表
df3 = pd.read_csv('data/employees.csv',
                   na_values={
                       'name': ['未知', 'N/A'],      # name列中"未知"和"N/A"视为缺失
                       'salary': ['-', '面议']        # salary列中"-"和"面议"视为缺失
                   })

# 打印缺失值统计信息
print(df3.isnull().sum())
案例5:跳过行和限制读取行数
python 复制代码
# 导入pandas库
import pandas as pd

# 跳过文件的前3行(比如跳过文件头部的说明文字)
# skiprows=3 表示跳过前3行
df = pd.read_csv('data/report.csv', skiprows=3)

# 打印结果
print(df.head())

# 也可以指定跳过哪些具体行(行号从0开始)
# skiprows=[0, 2, 5] 表示跳过第1行、第3行和第6行
df2 = pd.read_csv('data/report.csv', skiprows=[0, 2, 5])

# 只读取前100行数据,在数据量很大时用于快速预览
# nrows=100 表示只读取100行
df3 = pd.read_csv('data/bigdata.csv', nrows=100)

# 打印形状确认只读取了100行
print(f"读取的数据形状: {df3.shape}")
案例6:解析日期列
python 复制代码
# 导入pandas库
import pandas as pd

# 读取CSV文件并将指定列解析为日期类型
# parse_dates=['order_date'] 将order_date列自动转换为datetime类型
df = pd.read_csv('data/orders.csv', parse_dates=['order_date'])

# 查看数据类型,确认日期列已被正确解析
print(df.dtypes)

# 也可以传入多列名组合,将多列合并解析为一个日期列
# 例如文件中有year、month、day三列,合并为一个日期列
# parse_dates={'完整日期': ['年', '月', '日']}
df2 = pd.read_csv('data/orders.csv',
                   parse_dates={'完整日期': ['年', '月', '日']})

# 打印解析后的日期列
print(df2['完整日期'].head())

1.3 从TXT文件读取数据

案例7:读取纯文本文件
python 复制代码
# 导入pandas库
import pandas as pd

# 方法1:使用read_csv读取txt文件(txt文件实际上也可以用read_csv读取)
# 只要文件有结构化的分隔符即可
# sep='\\s+' 使用正则表达式,匹配一个或多个空白字符(空格、制表符等)
df = pd.read_csv('data/log.txt', sep='\\s+')

# 打印读取的数据
print(df)

# 方法2:使用Python内置的open函数逐行读取
# 'r' 表示以只读模式打开文件
# encoding='utf-8' 指定编码格式
with open('data/raw_data.txt', 'r', encoding='utf-8') as f:
    # readlines() 读取所有行,返回一个列表,每个元素是一行
    lines = f.readlines()

# 打印前5行内容
for i, line in enumerate(lines[:5]):
    # strip() 去除每行末尾的换行符和空白字符
    print(f"第{i+1}行: {line.strip()}")

# 方法3:使用read_table函数读取
# read_table默认分隔符是制表符\t
df2 = pd.read_table('data/tab_data.txt', sep='\t', encoding='utf-8')

# 打印结果
print(df2)
案例8:读取非结构化文本并构建DataFrame
python 复制代码
# 导入pandas库
import pandas as pd

# 初始化空列表,用于存储解析后的数据
records = []

# 打开文本文件逐行读取
with open('data/students.txt', 'r', encoding='utf-8') as f:
    # 遍历文件的每一行
    for line in f:
        # strip() 去除首尾空白字符和换行符
        line = line.strip()
        
        # 跳过空行
        if not line:
            continue
        
        # split(',') 以逗号为分隔符拆分每一行,得到字段列表
        fields = line.split(',')
        
        # 将解析后的字段组装成字典,添加到列表中
        record = {
            '姓名': fields[0],       # 第1个字段为姓名
            '年龄': int(fields[1]),   # 第2个字段为年龄,转为整数
            '成绩': float(fields[2])  # 第3个字段为成绩,转为浮点数
        }
        records.append(record)

# 使用列表中的字典创建DataFrame
df = pd.DataFrame(records)

# 打印结果
print(df)

1.4 写入CSV文件

案例9:将DataFrame保存为CSV文件
python 复制代码
# 导入pandas库
import pandas as pd

# 创建一个示例DataFrame
data = {
    '姓名': ['张三', '李四', '王五'],
    '年龄': [25, 30, 28],
    '城市': ['北京', '上海', '广州']
}
df = pd.DataFrame(data)

# 将DataFrame保存为CSV文件
# index=False 表示不将行索引写入文件
# encoding='utf-8-sig' 使用带BOM的UTF-8编码,确保Excel打开中文不乱码
df.to_csv('data/output.csv', index=False, encoding='utf-8-sig')

# 将DataFrame保存为以制表符分隔的文件
# sep='\t' 指定分隔符为制表符
df.to_csv('data/output.tsv', index=False, sep='\t', encoding='utf-8-sig')

# 只保存指定的列
# columns参数指定要保存的列名列表
df.to_csv('data/output_partial.csv',
          index=False,
          columns=['姓名', '城市'],
          encoding='utf-8-sig')

# 打印提示信息
print("文件保存成功!")

二、从Excel文件读取数据

2.1 Excel文件概述

Excel文件(.xlsx.xls)是Microsoft Office中的电子表格文件格式,支持多工作表(Sheet)、公式、格式等功能。Python中通常使用openpyxl(支持.xlsx)和xlrd(支持.xls)引擎来读取Excel文件。

2.2 核心函数:pd.read_excel()

主要参数说明:

参数 说明
io 文件路径或文件对象
sheet_name 工作表名称或索引,默认为0(第一个Sheet)
header 指定作为列名的行号
names 自定义列名列表
index_col 指定行索引列
usecols 指定读取的列
dtype 指定列的数据类型
skiprows 跳过的行数
nrows 读取的行数
engine 读取引擎,openpyxlxlrd
案例1:基本Excel读取
python 复制代码
# 导入pandas库
import pandas as pd

# 读取Excel文件的第一个工作表(默认读取sheet_name=0)
# pandas会自动调用openpyxl引擎来读取.xlsx文件
df = pd.read_excel('data/sales.xlsx')

# 打印前5行数据
print(df.head())

# 查看数据的基本信息
print(df.info())

# 查看数据形状(行数和列数)
print(f"数据形状: {df.shape}")
案例2:读取指定工作表
python 复制代码
# 导入pandas库
import pandas as pd

# 按名称读取指定的工作表
# sheet_name='销售记录' 指定读取名为"销售记录"的工作表
df = pd.read_excel('data/report.xlsx', sheet_name='销售记录')

# 打印数据
print(df)

# 按索引读取工作表(索引从0开始)
# sheet_name=1 表示读取第二个工作表
df2 = pd.read_excel('data/report.xlsx', sheet_name=1)

# 打印第二个工作表的数据
print(df2)

# 同时读取多个工作表
# 传入列表,返回一个字典,键为工作表名,值为DataFrame
# sheet_name=[0, 1, '汇总表'] 读取第1、2个工作表和名为"汇总表"的工作表
dfs = pd.read_excel('data/report.xlsx', sheet_name=[0, 1, '汇总表'])

# 遍历字典,打印每个工作表的名称和形状
for sheet_name, df_sheet in dfs.items():
    print(f"工作表 '{sheet_name}' 的形状: {df_sheet.shape}")

# 读取所有工作表
# sheet_name=None 表示读取所有工作表,返回字典
all_sheets = pd.read_excel('data/report.xlsx', sheet_name=None)

# 打印所有工作表名称
print(f"所有工作表: {list(all_sheets.keys())}")
案例3:选择列和跳过行
python 复制代码
# 导入pandas库
import pandas as pd

# 读取Excel文件并只选择特定的列
# usecols='A:C' 使用Excel列标识符,表示读取A到C列
df = pd.read_excel('data/employees.xlsx', usecols='A:C')

# 打印结果
print(df)

# 使用列名列表来选择列
# usecols=['姓名', '部门', '薪资'] 只读取这三列
df2 = pd.read_excel('data/employees.xlsx',
                     usecols=['姓名', '部门', '薪资'])

# 使用列索引来选择列
# usecols=[0, 2, 4] 只读取第1、3、5列
df3 = pd.read_excel('data/employees.xlsx', usecols=[0, 2, 4])

# 跳过前2行(例如跳过标题说明行)
# skiprows=2 跳过文件的前2行
df4 = pd.read_excel('data/employees.xlsx', skiprows=2)

# 自定义列名
# names=['编号', '姓名', '年龄', '职位', '薪资']
df5 = pd.read_excel('data/employees.xlsx',
                     skiprows=1,
                     names=['编号', '姓名', '年龄', '职位', '薪资'])

# 打印自定义列名后的结果
print(df5.head())
案例4:读取合并单元格的Excel
python 复制代码
# 导入pandas库
import pandas as pd

# 读取含有合并单元格的Excel文件
# 合并单元格在pandas中默认只会在第一行有值,其余为NaN
df = pd.read_excel('data/merged_cells.xlsx')

# 打印原始数据,观察合并单元格的情况
print("原始数据:")
print(df)

# 使用ffill(forward fill)方法填充NaN值
# ffill会用前一个非空值来填充当前的空值
# 这对于处理合并单元格非常有效
df_filled = df.fillna(method='ffill')

# 打印填充后的数据
print("填充合并单元格后的数据:")
print(df_filled)

2.3 写入Excel文件

案例5:将DataFrame保存为Excel文件
python 复制代码
# 导入pandas库
import pandas as pd

# 创建示例数据
data = {
    '产品': ['手机', '电脑', '平板'],
    '销量': [1000, 500, 800],
    '单价': [3999, 6999, 2999]
}
df = pd.DataFrame(data)

# 计算总销售额
df['总销售额'] = df['销量'] * df['单价']

# 将DataFrame保存为Excel文件
# index=False 表示不写入行索引
# sheet_name='销售汇总' 指定工作表名称
df.to_excel('data/sales_output.xlsx',
            index=False,
            sheet_name='销售汇总')

# 同时写入多个工作表
# 需要使用ExcelWriter对象作为上下文管理器
# engine='openpyxl' 指定使用openpyxl引擎
with pd.ExcelWriter('data/multi_sheet.xlsx', engine='openpyxl') as writer:
    # 将第一个DataFrame写入名为"第一季度"的工作表
    df.to_excel(writer, sheet_name='第一季度', index=False)
    
    # 将第二个DataFrame写入名为"第二季度"的工作表
    df2 = pd.DataFrame({
        '产品': ['手机', '电脑', '平板'],
        '销量': [1200, 600, 900],
        '单价': [3999, 6999, 2999]
    })
    df2.to_excel(writer, sheet_name='第二季度', index=False)

print("Excel文件保存成功!")

三、从JSON文件读取数据

3.1 JSON文件概述

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,采用键值对的方式组织数据。它广泛用于Web API的数据传输和配置文件。

JSON基本数据结构:

  • 对象 :用花括号 {} 包裹,包含键值对
  • 数组 :用方括号 [] 包裹,包含有序的值
  • :可以是字符串、数字、布尔值、null、对象或数组

3.2 使用Python内置json模块

案例1:使用json模块读取JSON文件
python 复制代码
# 导入Python内置的json模块
import json

# 方法1:使用json.load()从文件对象中读取JSON
# 'r' 表示以只读模式打开文件
# encoding='utf-8' 指定编码格式
with open('data/config.json', 'r', encoding='utf-8') as f:
    # load() 从文件对象中读取并解析JSON数据
    # 返回Python对象(字典、列表等)
    data = json.load(f)

# 打印读取的数据类型
print(f"数据类型: {type(data)}")

# 如果JSON顶层是对象(字典),可以直接访问键值
print(f"配置内容: {data}")

# 方法2:使用json.loads()从字符串中解析JSON
# 先读取文件内容为字符串
with open('data/config.json', 'r', encoding='utf-8') as f:
    # read() 读取文件的全部内容为字符串
    json_string = f.read()

# loads() 从JSON格式的字符串中解析数据
data2 = json.loads(json_string)

# 打印解析结果
print(data2)
案例2:解析嵌套的JSON数据
python 复制代码
# 导入json模块
import json

# 读取嵌套结构的JSON文件
with open('data/company.json', 'r', encoding='utf-8') as f:
    company = json.load(f)

# 打印整个JSON数据结构
print(f"公司名称: {company['name']}")

# 访问嵌套的字段(使用链式键访问)
# 假设结构为 {"name": "XX公司", "address": {"city": "北京", "district": "海淀"}}
print(f"所在城市: {company['address']['city']}")

# 遍历JSON数组
# 假设结构中有 employees: [{"name": "张三", "age": 30}, ...]
for employee in company['employees']:
    # 打印每个员工的姓名和年龄
    print(f"员工: {employee['姓名']}, 年龄: {employee['年龄']}")
案例3:处理复杂的嵌套JSON
python 复制代码
# 导入json模块
import json

# 定义一个复杂的嵌套JSON字符串(模拟从API获取的数据)
json_str = '''
{
    "status": "success",
    "data": {
        "total": 3,
        "records": [
            {
                "id": 1,
                "name": "张三",
                "scores": {
                    "math": 95,
                    "english": 88,
                    "science": 92
                },
                "hobbies": ["读书", "游泳", "编程"]
            },
            {
                "id": 2,
                "name": "李四",
                "scores": {
                    "math": 78,
                    "english": 95,
                    "science": 85
                },
                "hobbies": ["音乐", "旅行"]
            },
            {
                "id": 3,
                "name": "王五",
                "scores": {
                    "math": 90,
                    "english": 82,
                    "science": 88
                },
                "hobbies": ["运动"]
            }
        ]
    }
}
'''

# 使用json.loads()解析JSON字符串
result = json.loads(json_str)

# 获取状态信息
print(f"状态: {result['status']}")

# 获取总记录数
print(f"总记录数: {result['data']['total']}")

# 遍历记录列表
for record in result['data']['records']:
    # 计算平均成绩
    scores = record['scores']
    # sum() 计算所有成绩的总和
    # len() 计算科目数量
    avg_score = sum(scores.values()) / len(scores)
    
    # 将爱好列表用"、"连接成字符串
    # join() 方法将列表元素用指定字符串连接
    hobbies_str = '、'.join(record['hobbies'])
    
    # 格式化输出每个学生的详细信息
    print(f"姓名: {record['name']}, 平均分: {avg_score:.1f}, 爱好: {hobbies_str}")

3.3 使用pandas读取JSON文件

案例4:使用pd.read_json()读取JSON
python 复制代码
# 导入pandas库
import pandas as pd

# 使用pandas直接读取JSON文件
# read_json() 可以读取格式规范的JSON文件并转换为DataFrame
df = pd.read_json('data/employees.json')

# 打印数据
print(df.head())

# 打印数据类型信息
print(df.dtypes)

# 指定数据方向(orient参数)
# orient='records' 表示JSON是记录列表格式 [{"col1": val1, "col2": val2}, ...]
# orient='columns' 表示JSON是列格式 {"col1": {"row1": val1}, ...}
# orient='index' 表示JSON是索引格式 {"row1": {"col1": val1}, ...}
# orient='split' 表示JSON包含 columns、index、data 键
# orient='values' 表示JSON是纯数组 [[val1, val2], ...]
df2 = pd.read_json('data/employees.json', orient='records')

# 打印结果
print(df2)
案例5:使用pd.json_normalize()展平嵌套JSON
python 复制代码
# 导入pandas库
import pandas as pd
# 导入json模块
import json

# 读取嵌套的JSON文件
with open('data/nested_data.json', 'r', encoding='utf-8') as f:
    nested_data = json.load(f)

# 使用json_normalize()将嵌套JSON展平为扁平的DataFrame
# record_path 指定要展平的嵌套记录路径
# meta 指定要从父级携带的字段
df = pd.json_normalize(
    nested_data,                  # 嵌套的JSON数据
    record_path='orders',         # 展平orders数组中的记录
    meta=['customer_id', 'name']  # 同时保留父级的customer_id和name字段
)

# 打印展平后的DataFrame
print(df)

# 对于更深层的嵌套
# record_path 可以指定多层路径
# 例如 record_path=['orders', 'items'] 表示展平orders下的items
df2 = pd.json_normalize(
    nested_data,
    record_path=['orders', 'items'],    # 两级嵌套路径
    meta=[
        'customer_id',                   # 第一级字段
        ['orders', 'order_id']           # 第二级的字段,用列表指定路径
    ]
)

# 打印深层展平后的结果
print(df2)

3.4 写入JSON文件

案例6:将数据保存为JSON文件
python 复制代码
# 导入json模块
import json
# 导入pandas库
import pandas as pd

# ===== 方法1:使用json.dump()将Python对象保存为JSON =====

# 定义要保存的数据(字典和列表)
data = {
    'name': '产品销售数据',
    'version': '1.0',
    'records': [
        {'产品': '手机', '销量': 1000, '单价': 3999},
        {'产品': '电脑', '销量': 500, '单价': 6999},
        {'产品': '平板', '销量': 800, '单价': 2999}
    ]
}

# 'w' 表示以写入模式打开文件
# ensure_ascii=False 确保中文字符正常显示,不被转义为Unicode编码
# indent=4 指定缩进为4个空格,使输出的JSON格式化、易读
with open('data/output.json', 'w', encoding='utf-8') as f:
    json.dump(data, f, ensure_ascii=False, indent=4)

print("JSON文件保存成功(json.dump)!")

# ===== 方法2:使用pandas将DataFrame保存为JSON =====

# 创建DataFrame
df = pd.DataFrame(data['records'])

# 将DataFrame保存为JSON文件
# orient='records' 表示以记录列表格式保存 [{"col": val}, ...]
# force_ascii=False 确保中文正常显示
# indent=2 缩进2个空格
df.to_json('data/output_pandas.json',
           orient='records',
           force_ascii=False,
           indent=2)

print("JSON文件保存成功(pandas.to_json)!")

四、从HTML表格读取数据

4.1 HTML表格读取概述

pandas提供了read_html()函数,可以从HTML页面中自动提取所有<table>标签的内容,并将每个表格转换为DataFrame。该函数底层依赖lxmlhtml5lib等HTML解析库。

注意: 需要提前安装解析库:

bash 复制代码
pip install lxml html5lib

4.2 核心函数:pd.read_html()

主要参数说明:

参数 说明
io URL字符串、文件路径或HTML字符串
match 正则表达式,用于匹配表格中的文本内容
flavor 解析引擎,lxmlhtml5lib
header 指定表头行号
index_col 指定索引列
attrs HTML属性字典,用于定位特定表格
encoding 编码格式
thousands 千位分隔符
案例1:从HTML文件读取表格
python 复制代码
# 导入pandas库
import pandas as pd

# 从本地HTML文件中读取所有表格
# read_html() 返回一个列表,每个元素是一个DataFrame
# 每个DataFrame对应HTML中的一个<table>标签
tables = pd.read_html('data/table.html')

# 打印找到的表格数量
print(f"找到 {len(tables)} 个表格")

# 打印第一个表格
print("第一个表格:")
print(tables[0])

# 如果HTML中有多个表格,可以通过索引访问
if len(tables) > 1:
    print("第二个表格:")
    print(tables[1])
案例2:从网页URL读取表格
python 复制代码
# 导入pandas库
import pandas as pd

# 直接从网页URL读取表格
# read_html() 会自动下载网页内容并解析其中的<table>标签
# 注意:某些网站可能需要额外的请求头或代理设置
url = 'https://zh.wikipedia.org/wiki/%E4%B8%AD%E5%9B%BD%E5%9F%8E%E5%B8%82%E5%88%97%E8%A1%A8'

# 读取网页中的所有表格
tables = pd.read_html(url)

# 打印找到的表格数量
print(f"网页中共找到 {len(tables)} 个表格")

# 通常第一个表格就是页面中最重要的表格
# 打印第一个表格的前10行
print(tables[0].head(10))
案例3:使用match参数匹配特定表格
python 复制代码
# 导入pandas库
import pandas as pd

# 从HTML文件中读取表格
# match参数使用正则表达式匹配表格中的文本内容
# 只有包含匹配文本的表格才会被读取
tables = pd.read_html('data/multi_table.html', match='销售数据')

# 打印匹配到的表格
print(f"匹配到 {len(tables)} 个表格")
for i, table in enumerate(tables):
    print(f"\n表格 {i+1}:")
    print(table)

# 使用attrs参数定位具有特定HTML属性的表格
# attrs={'id': 'sales-table'} 匹配id为"sales-table"的<table>标签
tables2 = pd.read_html('data/multi_table.html', attrs={'id': 'sales-table'})

# 打印结果
print(tables2[0])
案例4:从HTML字符串读取表格
python 复制代码
# 导入pandas库
import pandas as pd

# 定义HTML字符串(模拟从网页获取的内容)
html_string = '''
<html>
<body>
    <h2>2024年季度销售报告</h2>
    <table border="1" class="dataframe">
        <thead>
            <tr>
                <th>季度</th>
                <th>销售额(万元)</th>
                <th>同比增长</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>第一季度</td>
                <td>1200</td>
                <td>15%</td>
            </tr>
            <tr>
                <td>第二季度</td>
                <td>1500</td>
                <td>20%</td>
            </tr>
            <tr>
                <td>第三季度</td>
                <td>1800</td>
                <td>18%</td>
            </tr>
            <tr>
                <td>第四季度</td>
                <td>2100</td>
                <td>25%</td>
            </tr>
        </tbody>
    </table>
</body>
</html>
'''

# 从HTML字符串中解析表格
# 直接将HTML字符串传入read_html()
tables = pd.read_html(html_string)

# 读取解析出的第一个表格
df = tables[0]

# 打印表格数据
print(df)

# 打印数据类型
print(df.dtypes)
案例5:结合requests获取网页表格
python 复制代码
# 导入pandas库
import pandas as pd
# 导入requests库,用于发送HTTP请求
import requests

# 设置请求头,模拟浏览器访问
# 某些网站会检查User-Agent,不设置可能被拒绝访问
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}

# 发送GET请求获取网页内容
# timeout=10 设置超时时间为10秒
response = requests.get('https://example.com/data', headers=headers, timeout=10)

# 检查请求是否成功(状态码200表示成功)
if response.status_code == 200:
    # response.text 获取网页的HTML文本内容
    # read_html() 从HTML文本中解析表格
    tables = pd.read_html(response.text)
    
    # 打印找到的表格
    for i, table in enumerate(tables):
        print(f"表格 {i+1}:")
        print(table.head())
        print()
else:
    # 请求失败,打印错误状态码
    print(f"请求失败,状态码: {response.status_code}")

4.3 写入HTML文件

案例6:将DataFrame保存为HTML表格
python 复制代码
# 导入pandas库
import pandas as pd

# 创建示例DataFrame
data = {
    '姓名': ['张三', '李四', '王五'],
    '部门': ['技术部', '市场部', '财务部'],
    '薪资': [15000, 12000, 13000]
}
df = pd.DataFrame(data)

# 将DataFrame保存为HTML表格
# index=False 表示不包含行索引
# 将自动生成包含<table>标签的HTML文件
df.to_html('data/output.html', index=False)

# 也可以生成格式化更好的HTML
# classes='table-class' 为<table>标签添加CSS类名
# border=1 设置表格边框
# justify='center' 文本居中对齐
html_output = df.to_html(
    index=False,             # 不包含行索引
    classes='styled-table',  # 添加CSS类名
    border=1,                # 边框宽度
    justify='center'         # 居中对齐
)

# 将HTML内容写入文件,并添加基本的HTML结构
with open('data/styled_output.html', 'w', encoding='utf-8') as f:
    f.write('<!DOCTYPE html>\n')
    f.write('<html><head><meta charset="utf-8">\n')
    f.write('<title>数据报告</title>\n')
    f.write('<style>\n')
    f.write('.styled-table { border-collapse: collapse; width: 80%; margin: auto; }\n')
    f.write('th, td { border: 1px solid #ddd; padding: 8px; text-align: center; }\n')
    f.write('th { background-color: #4CAF50; color: white; }\n')
    f.write('</style></head><body>\n')
    f.write('<h1 style="text-align:center">员工数据报告</h1>\n')
    f.write(html_output)
    f.write('\n</body></html>')

print("HTML文件保存成功!")

五、从Word文件读取数据

5.1 python-docx库概述

python-docx 是一个用于创建和读取Microsoft Word(.docx)文件的Python库。它可以操作文档中的段落、表格、图片、样式等元素。

安装方法:

bash 复制代码
pip install python-docx

5.2 python-docx库的基本使用

案例1:读取Word文档的基本信息
python 复制代码
# 从docx模块导入Document类
# Document类是操作Word文档的核心类
from docx import Document

# 打开Word文档
# 传入文件路径,返回一个Document对象
doc = Document('data/report.docx')

# 获取文档中的所有段落
# paragraphs属性返回一个段落列表
paragraphs = doc.paragraphs

# 打印段落总数
print(f"文档共有 {len(paragraphs)} 个段落")

# 遍历所有段落,打印段落内容
for i, para in enumerate(paragraphs):
    # text属性获取段落的文本内容
    # style.name 获取段落的样式名称(如"Heading 1"、"Normal"等)
    if para.text.strip():  # 只打印非空段落
        print(f"段落 {i+1} [{para.style.name}]: {para.text}")

# 获取文档中的所有表格
# tables属性返回一个表格列表
tables = doc.tables

# 打印表格总数
print(f"\n文档共有 {len(tables)} 个表格")
案例2:读取Word文档中的所有段落文本
python 复制代码
# 从docx模块导入Document类
from docx import Document

# 打开Word文档
doc = Document('data/article.docx')

# 初始化一个空列表,用于存储所有段落的文本
all_text = []

# 遍历文档的所有段落
for para in doc.paragraphs:
    # 获取段落文本,去除首尾空白
    text = para.text.strip()
    
    # 只保留非空段落
    if text:
        # 获取段落样式名称
        style_name = para.style.name
        
        # 根据样式类型分类处理
        if 'Heading' in style_name:
            # 如果是标题样式,在文本前添加标记
            level = style_name.replace('Heading ', '')
            all_text.append(f"{'#' * int(level)} {text}")
        else:
            # 普通段落直接添加
            all_text.append(text)

# 将所有段落用换行符连接成完整的文本
full_text = '\n'.join(all_text)

# 打印完整文本
print(full_text)
案例3:读取Word文档中的表格数据
python 复制代码
# 从docx模块导入Document类
from docx import Document
# 导入pandas库,用于将表格数据转换为DataFrame
import pandas as pd

# 打开Word文档
doc = Document('data/tables_report.docx')

# 遍历文档中的所有表格
for table_idx, table in enumerate(doc.tables):
    print(f"\n===== 表格 {table_idx + 1} =====")
    
    # 获取表格的行数
    # rows属性返回表格的所有行
    print(f"行数: {len(table.rows)}")
    
    # 获取表格的列数
    # columns属性返回表格的所有列
    print(f"列数: {len(table.columns)}")
    
    # 方法1:逐行逐列读取单元格内容
    # 初始化一个空列表,用于存储表格数据
    table_data = []
    
    # 遍历表格的每一行
    for row in table.rows:
        # 初始化行数据列表
        row_data = []
        
        # 遍历行中的每个单元格
        for cell in row.cells:
            # text属性获取单元格的文本内容
            # strip() 去除首尾空白字符和换行符
            cell_text = cell.text.strip()
            row_data.append(cell_text)
        
        # 将行数据添加到表格数据中
        table_data.append(row_data)
    
    # 第一行作为列名,其余行作为数据
    # table_data[0] 是表头行
    # table_data[1:] 是数据行
    if len(table_data) > 1:
        df = pd.DataFrame(table_data[1:], columns=table_data[0])
        print(df)
    else:
        print(table_data)
案例4:读取Word文档中的段落格式信息
python 复制代码
# 从docx模块导入Document类
from docx import Document

# 打开Word文档
doc = Document('data/formatted_doc.docx')

# 遍历文档的所有段落
for i, para in enumerate(doc.paragraphs):
    # 跳过空段落
    if not para.text.strip():
        continue
    
    # 打印段落编号和内容
    print(f"\n--- 段落 {i+1} ---")
    print(f"内容: {para.text}")
    print(f"样式: {para.style.name}")
    
    # 获取段落的对齐方式
    # alignment属性返回对齐方式的枚举值
    # 0=左对齐, 1=居中, 2=右对齐, 3=两端对齐
    alignment = para.paragraph_format.alignment
    alignment_map = {0: '左对齐', 1: '居中', 2: '右对齐', 3: '两端对齐', None: '默认'}
    print(f"对齐方式: {alignment_map.get(alignment, '未知')}")
    
    # 遍历段落中的每个run(具有相同样式的文本片段)
    for j, run in enumerate(para.runs):
        # 打印run的文本和格式信息
        print(f"  Run {j+1}: '{run.text}'")
        print(f"    粗体: {run.bold}")         # 是否粗体
        print(f"    斜体: {run.italic}")       # 是否斜体
        print(f"    下划线: {run.underline}")  # 是否下划线
        
        # 获取字体信息
        if run.font.size:
            # font.size 返回字体大小(单位为EMUs,需转换为磅值)
            # 1英寸 = 914400 EMUs = 72磅
            size_pt = run.font.size.pt
            print(f"    字体大小: {size_pt}磅")
        
        if run.font.color and run.font.color.rgb:
            # 获取字体颜色的RGB值
            print(f"    字体颜色: {run.font.color.rgb}")
案例5:提取Word文档中的所有文本并保存为TXT
python 复制代码
# 从docx模块导入Document类
from docx import Document

# 打开Word文档
doc = Document('data/long_report.docx')

# 初始化空列表存储所有文本内容
content_lines = []

# 遍历文档元素(按文档顺序,包括段落和表格)
# doc.element.body 获取文档的XML主体元素
from docx.oxml.ns import qn

# 遍历文档主体中的所有子元素
for element in doc.element.body:
    # 判断元素类型
    # w:p 是段落标签,w:tbl 是表格标签
    if element.tag == qn('w:p'):
        # 是段落元素,提取文本
        # 通过xpath查找所有文本节点
        text_nodes = element.xpath('.//w:t/text()')
        if text_nodes:
            # 将所有文本节点连接
            paragraph_text = ''.join(text_nodes)
            content_lines.append(paragraph_text)
            content_lines.append('')  # 段落之间添加空行
    
    elif element.tag == qn('w:tbl'):
        # 是表格元素,提取表格数据
        content_lines.append('--- 表格 ---')
        
        # 遍历表格的所有行
        for row in element.xpath('.//w:tr'):
            # 提取行中每个单元格的文本
            cells = row.xpath('.//w:tc//w:t/text()')
            if cells:
                # 用制表符分隔各列
                row_text = '\t'.join(cells)
                content_lines.append(row_text)
        
        content_lines.append('--- 表格结束 ---')
        content_lines.append('')

# 将所有内容连接为完整文本
full_text = '\n'.join(content_lines)

# 保存为TXT文件
with open('data/extracted_text.txt', 'w', encoding='utf-8') as f:
    f.write(full_text)

# 打印提取的文本长度
print(f"共提取 {len(full_text)} 个字符")
print("文本已保存为TXT文件!")
案例6:将Word表格数据转换为DataFrame并保存
python 复制代码
# 从docx模块导入Document类
from docx import Document
# 导入pandas库
import pandas as pd

# 打开Word文档
doc = Document('data/sales_report.docx')

# 初始化一个字典,用于存储所有表格
# 键为表格标题,值为对应的DataFrame
all_tables = {}

# 获取上一个段落的文本,作为表格的标题
prev_para_text = ''

# 遍历文档的所有元素
for element in doc.element.body:
    # 如果是段落,记录其文本作为可能的表格标题
    if element.tag == qn('w:p'):
        from docx.oxml.ns import qn
        text_nodes = element.xpath('.//w:t/text()')
        if text_nodes:
            prev_para_text = ''.join(text_nodes).strip()
    
    # 如果是表格,提取数据
    elif element.tag == qn('w:tbl'):
        # 提取表格数据
        rows_data = []
        for row in element.xpath('.//w:tr'):
            cells = row.xpath('.//w:tc//w:t/text()')
            row_data = [cell.strip() for cell in cells]
            if row_data:
                rows_data.append(row_data)
        
        # 将提取的数据转换为DataFrame
        if len(rows_data) > 1:
            # 第一行作为列名
            df = pd.DataFrame(rows_data[1:], columns=rows_data[0])
            
            # 使用前一个段落文本作为表格标题
            # 如果标题为空或已存在,添加编号
            table_title = prev_para_text if prev_para_text else f"表格_{len(all_tables)+1}"
            if table_title in all_tables:
                table_title = f"{table_title}_{len(all_tables)+1}"
            
            # 存储DataFrame
            all_tables[table_title] = df
            print(f"已提取表格: {table_title}")
            print(df)
            print()

# 将所有表格保存到一个Excel文件的不同工作表中
with pd.ExcelWriter('data/word_tables.xlsx', engine='openpyxl') as writer:
    for title, df in all_tables.items():
        # 截取标题前31个字符(Excel工作表名最长31个字符)
        sheet_name = title[:31]
        df.to_excel(writer, sheet_name=sheet_name, index=False)

print("所有表格已保存到Excel文件!")

六、从PDF文件读取数据

6.1 pdfplumber库概述

pdfplumber 是一个功能强大的PDF解析库,能够精确提取PDF中的文本、表格和元数据信息。相比其他PDF库(如PyPDF2),pdfplumber在表格提取方面表现更优秀。

安装方法:

bash 复制代码
pip install pdfplumber

主要特点:

  • 支持文本提取,包括位置信息
  • 支持表格提取,自动识别表格结构
  • 支持可视化调试(可以将PDF页面渲染为图片)
  • 支持提取PDF元数据

6.2 pdfplumber库的基本使用

案例1:基本PDF文本提取
python 复制代码
# 导入pdfplumber库
import pdfplumber

# 打开PDF文件
# 使用with语句确保文件被正确关闭
with pdfplumber.open('data/document.pdf') as pdf:
    # 获取PDF的总页数
    # pdf.pages 是一个页面列表
    total_pages = len(pdf.pages)
    print(f"PDF共有 {total_pages} 页")
    
    # 获取PDF的元数据信息
    # pdf.metadata 返回一个字典,包含标题、作者、创建日期等信息
    metadata = pdf.metadata
    print(f"元数据: {metadata}")
    
    # 读取第一页的内容
    # pages[0] 获取第一页的Page对象(索引从0开始)
    first_page = pdf.pages[0]
    
    # extract_text() 方法提取页面上的所有文本
    text = first_page.extract_text()
    
    # 打印提取的文本
    print(f"\n第1页文本内容:\n{text}")
    
    # 获取页面的尺寸信息
    # width 和 height 属性返回页面的宽高(单位:磅)
    print(f"\n页面尺寸: 宽={first_page.width}, 高={first_page.height}")
案例2:提取PDF所有页面的文本
python 复制代码
# 导入pdfplumber库
import pdfplumber

# 打开PDF文件
with pdfplumber.open('data/report.pdf') as pdf:
    # 初始化空列表,存储每页的文本
    all_pages_text = []
    
    # 遍历PDF的每一页
    for i, page in enumerate(pdf.pages):
        # 提取当前页面的文本
        text = page.extract_text()
        
        # 检查是否成功提取到文本
        if text:
            # 添加页码标记和文本内容
            all_pages_text.append(f"===== 第 {i+1} 页 =====")
            all_pages_text.append(text)
            all_pages_text.append('')  # 页面之间添加空行
        else:
            # 如果页面没有文本(可能是纯图片页面)
            all_pages_text.append(f"===== 第 {i+1} 页 (无可提取文本) =====")
            all_pages_text.append('')
    
    # 将所有页面文本合并为一个完整字符串
    full_text = '\n'.join(all_pages_text)
    
    # 保存提取的文本到TXT文件
    with open('data/extracted_pdf_text.txt', 'w', encoding='utf-8') as f:
        f.write(full_text)
    
    # 打印统计信息
    print(f"共提取 {len(all_pages_text)} 行文本")
    print(f"文本已保存到 extracted_pdf_text.txt")
案例3:提取PDF中的表格数据
python 复制代码
# 导入pdfplumber库
import pdfplumber
# 导入pandas库,用于表格数据处理
import pandas as pd

# 打开PDF文件
with pdfplumber.open('data/table_report.pdf') as pdf:
    # 初始化空列表,用于存储所有提取的表格
    all_tables = []
    
    # 遍历PDF的每一页
    for i, page in enumerate(pdf.pages):
        # extract_tables() 方法提取页面上的所有表格
        # 返回一个列表,每个元素是一个二维列表(行×列)
        tables = page.extract_tables()
        
        # 检查当前页面是否有表格
        if tables:
            print(f"第 {i+1} 页找到 {len(tables)} 个表格")
            
            # 遍历当前页面的每个表格
            for j, table in enumerate(tables):
                # table 是一个二维列表
                # table[0] 是第一行(通常是表头)
                # table[1:] 是数据行
                
                print(f"\n表格 {j+1} (第{i+1}页):")
                print(f"行数: {len(table)}, 列数: {len(table[0]) if table else 0}")
                
                # 清洗表格数据
                # 某些单元格可能包含换行符,需要替换
                cleaned_table = []
                for row in table:
                    # 对每个单元格进行清洗
                    cleaned_row = []
                    for cell in row:
                        if cell is None:
                            # 将None替换为空字符串
                            cleaned_row.append('')
                        else:
                            # 替换换行符为空格,并去除首尾空白
                            cleaned_row.append(cell.replace('\n', ' ').strip())
                    cleaned_table.append(cleaned_row)
                
                # 转换为DataFrame
                if len(cleaned_table) > 1:
                    # 第一行作为列名
                    df = pd.DataFrame(cleaned_table[1:], columns=cleaned_table[0])
                    all_tables.append(df)
                    print(df)
    
    # 打印总计提取的表格数
    print(f"\n共提取 {len(all_tables)} 个表格")
案例4:高级表格提取 --- 处理复杂PDF表格
python 复制代码
# 导入pdfplumber库
import pdfplumber
# 导入pandas库
import pandas as pd

# 打开PDF文件
with pdfplumber.open('data/complex_table.pdf') as pdf:
    # 选择要处理的页面(例如第2页,索引为1)
    page = pdf.pages[1]
    
    # 使用自定义参数提取表格
    # extract_tables() 接受table_settings参数来调整表格检测行为
    tables = page.extract_tables(
        table_settings={
            # "vertical_strategy": 设置垂直线检测策略
            # "lines" - 使用页面中的线条来检测列边界
            # "text" - 使用文本对齐来推断列边界
            # "explicit" - 使用明确指定的坐标
            "vertical_strategy": "lines",
            
            # "horizontal_strategy": 设置水平线检测策略
            "horizontal_strategy": "lines",
            
            # "snap_tolerance": 文本与线条的吸附容差(像素)
            # 当文本在某条线的容差范围内时,会吸附到该线
            "snap_tolerance": 5,
            
            # "join_tolerance": 相邻线条的合并容差
            # 两条线在容差范围内会被合并为一条
            "join_tolerance": 5,
            
            # "edge_min_length": 边缘的最小长度
            # 过短的边缘会被忽略
            "edge_min_length": 10,
            
            # "min_words_vertical": 垂直方向最少单词数
            "min_words_vertical": 1,
            
            # "min_words_horizontal": 水平方向最少单词数
            "min_words_horizontal": 1,
            
            # "intersection_tolerance": 交叉点容差
            "intersection_tolerance": 8
        }
    )
    
    # 处理提取到的表格
    for i, table in enumerate(tables):
        print(f"表格 {i+1}:")
        
        # 清洗并转换为DataFrame
        if table and len(table) > 1:
            # 处理合并单元格导致的None值
            # 用前一个非None值填充(向下填充)
            for col_idx in range(len(table[0])):
                prev_value = None
                for row_idx in range(len(table)):
                    if table[row_idx][col_idx] is not None:
                        prev_value = table[row_idx][col_idx]
                    else:
                        table[row_idx][col_idx] = prev_value if prev_value else ''
            
            # 创建DataFrame
            df = pd.DataFrame(table[1:], columns=table[0])
            print(df)
        print()
案例5:提取PDF中特定区域的文本
python 复制代码
# 导入pdfplumber库
import pdfplumber

# 打开PDF文件
with pdfplumber.open('data/invoice.pdf') as pdf:
    # 获取第一页
    page = pdf.pages[0]
    
    # 方法1:使用crop裁剪特定区域后提取文本
    # crop() 接受一个四元组 (x0, top, x1, bottom)
    # (x0, top) 是左上角坐标,(x1, bottom) 是右下角坐标
    # 坐标单位为磅(point),原点在左上角
    
    # 裁剪页面顶部区域(例如发票标题区域)
    top_area = page.crop((50, 30, 500, 100))
    # 在裁剪区域中提取文本
    header_text = top_area.extract_text()
    print(f"标题区域文本:\n{header_text}")
    
    # 裁剪页面中部区域(例如表格区域)
    middle_area = page.crop((50, 150, 550, 400))
    # 在裁剪区域中提取表格
    tables = middle_area.extract_tables()
    if tables:
        print(f"\n表格数据:")
        for row in tables[0]:
            print(row)
    
    # 裁剪页面底部区域(例如总计区域)
    bottom_area = page.crop((300, 600, 550, 700))
    bottom_text = bottom_area.extract_text()
    print(f"\n底部区域文本:\n{bottom_text}")
    
    # 方法2:提取特定位置的单词及其坐标
    # extract_words() 返回页面上所有单词及其位置信息
    words = page.extract_words(
        x_tolerance=3,       # 水平方向字符间距容差
        y_tolerance=3,       # 垂直方向行间距容差
        keep_blank_chars=False,  # 是否保留空白字符
        use_text_flow=False      # 是否使用文本流排序
    )
    
    # 打印前10个单词及其位置
    print("\n单词位置信息(前10个):")
    for word in words[:10]:
        # 每个word是一个字典,包含:
        # 'text' - 单词文本
        # 'x0', 'top', 'x1', 'bottom' - 单词的边界坐标
        print(f"  '{word['text']}' 位置: ({word['x0']:.1f}, {word['top']:.1f})")
案例6:提取PDF中的图片信息
python 复制代码
# 导入pdfplumber库
import pdfplumber

# 打开PDF文件
with pdfplumber.open('data/illustrated.pdf') as pdf:
    # 遍历每一页
    for i, page in enumerate(pdf.pages):
        # 获取页面上的图片信息
        # images属性返回页面中所有图片的信息列表
        images = page.images
        
        if images:
            print(f"第 {i+1} 页包含 {len(images)} 张图片")
            
            # 遍历每张图片,打印位置信息
            for j, img in enumerate(images):
                # 每个image是一个字典,包含:
                # 'x0', 'top', 'x1', 'bottom' - 图片的边界坐标
                # 'width', 'height' - 图片的宽高
                print(f"  图片 {j+1}:")
                print(f"    位置: ({img['x0']:.1f}, {img['top']:.1f})")
                print(f"    尺寸: {img['width']:.1f} x {img['height']:.1f}")
案例7:完整的PDF数据提取流程
python 复制代码
# 导入pdfplumber库
import pdfplumber
# 导入pandas库
import pandas as pd

def extract_pdf_data(pdf_path, output_excel_path):
    """
    从PDF文件中提取所有表格数据并保存到Excel文件
    
    参数:
        pdf_path (str): PDF文件路径
        output_excel_path (str): 输出Excel文件路径
    
    返回:
        dict: 包含所有提取数据的字典
    """
    # 初始化结果字典
    result = {
        'metadata': {},     # 元数据
        'page_count': 0,    # 页数
        'tables': [],       # 提取的表格列表
        'full_text': ''     # 完整文本
    }
    
    # 打开PDF文件
    with pdfplumber.open(pdf_path) as pdf:
        # 保存元数据信息
        result['metadata'] = pdf.metadata or {}
        result['page_count'] = len(pdf.pages)
        
        # 存储所有文本
        all_text = []
        
        # 遍历每一页
        for i, page in enumerate(pdf.pages):
            # 提取文本
            text = page.extract_text()
            if text:
                all_text.append(text)
            
            # 提取表格
            tables = page.extract_tables()
            for table in tables:
                if table and len(table) > 1:
                    # 清洗数据
                    cleaned = []
                    for row in table:
                        cleaned_row = [
                            cell.replace('\n', ' ').strip() if cell else ''
                            for cell in row
                        ]
                        cleaned.append(cleaned_row)
                    
                    # 转换为DataFrame并记录来源页码
                    try:
                        df = pd.DataFrame(cleaned[1:], columns=cleaned[0])
                        df.attrs['source_page'] = i + 1
                        result['tables'].append(df)
                    except Exception as e:
                        # 如果列数不匹配,跳过该表格
                        print(f"第{i+1}页表格解析失败: {e}")
        
        # 合并所有文本
        result['full_text'] = '\n\n'.join(all_text)
    
    # 将所有表格保存到Excel
    if result['tables']:
        with pd.ExcelWriter(output_excel_path, engine='openpyxl') as writer:
            for idx, df in enumerate(result['tables']):
                sheet_name = f"表格_{idx+1}"
                df.to_excel(writer, sheet_name=sheet_name, index=False)
        print(f"已将 {len(result['tables'])} 个表格保存到 {output_excel_path}")
    
    return result


# 调用函数执行完整的PDF数据提取
result = extract_pdf_data('data/annual_report.pdf', 'data/extracted_tables.xlsx')

# 打印提取结果统计
print(f"\nPDF信息:")
print(f"  页数: {result['page_count']}")
print(f"  元数据: {result['metadata']}")
print(f"  提取表格数: {len(result['tables'])}")
print(f"  文本长度: {len(result['full_text'])} 字符")
案例8:可视化PDF页面布局(调试用)
python 复制代码
# 导入pdfplumber库
import pdfplumber

# 打开PDF文件
with pdfplumber.open('data/debug_page.pdf') as pdf:
    # 获取第一页
    page = pdf.pages[0]
    
    # 方法1:将页面渲染为图片(用于调试表格检测)
    # to_image() 方法将页面转换为Image对象
    im = page.to_image(
        resolution=150  # 分辨率,单位为DPI
    )
    
    # 在页面上绘制检测到的线条(调试用)
    im.draw_lines(page.lines, stroke="red", stroke_width=2)
    
    # 在页面上绘制检测到的矩形
    im.draw_rects(page.rects, stroke="blue", stroke_width=1)
    
    # 保存调试图像
    im.save('data/debug_output.png')
    print("调试图像已保存到 debug_output.png")
    
    # 查看页面上的所有线条信息
    lines = page.lines
    print(f"\n页面包含 {len(lines)} 条线条")
    
    # 查看页面上的所有字符信息
    chars = page.chars
    print(f"页面包含 {len(chars)} 个字符")
    
    # 查看前5个字符的详细信息
    for char in chars[:5]:
        # 每个char包含:text, x0, top, x1, bottom, fontname, size等
        print(f"  字符 '{char['text']}' "
              f"字体: {char.get('fontname', '未知')} "
              f"大小: {char.get('size', '未知')}")

七、综合对比与总结

7.1 各格式读取方法对比

文件格式 推荐库/函数 安装命令 适用场景
CSV/TXT pd.read_csv() pandas自带 结构化表格数据
Excel pd.read_excel() pip install openpyxl 电子表格数据
JSON pd.read_json() / json.load() pandas自带 / 内置 API数据、配置文件
HTML pd.read_html() pip install lxml html5lib 网页表格数据
Word python-docx pip install python-docx 文档中的文本和表格
PDF pdfplumber pip install pdfplumber PDF中的文本和表格

7.2 综合案例:多格式数据读取与合并

python 复制代码
# 导入所需库
import pandas as pd        # 数据分析库
import json                # JSON处理模块
from docx import Document  # Word文档处理
import pdfplumber          # PDF处理库

def read_multi_format_data(file_path):
    """
    根据文件扩展名自动选择合适的方法读取数据
    
    参数:
        file_path (str): 文件路径
    
    返回:
        pandas.DataFrame 或 dict: 读取的数据
    """
    # 获取文件扩展名(转为小写)
    import os
    _, ext = os.path.splitext(file_path)
    ext = ext.lower()
    
    # 根据扩展名选择读取方法
    if ext == '.csv':
        # 读取CSV文件
        print(f"正在读取CSV文件: {file_path}")
        return pd.read_csv(file_path, encoding='utf-8')
    
    elif ext in ['.xlsx', '.xls']:
        # 读取Excel文件
        print(f"正在读取Excel文件: {file_path}")
        return pd.read_excel(file_path)
    
    elif ext == '.json':
        # 读取JSON文件
        print(f"正在读取JSON文件: {file_path}")
        with open(file_path, 'r', encoding='utf-8') as f:
            data = json.load(f)
        
        # 如果JSON是列表形式,直接转换为DataFrame
        if isinstance(data, list):
            return pd.DataFrame(data)
        # 如果JSON是字典形式
        elif isinstance(data, dict):
            # 尝试找到可转换为表格的数据
            for key, value in data.items():
                if isinstance(value, list) and len(value) > 0:
                    if isinstance(value[0], dict):
                        return pd.DataFrame(value)
            return data  # 无法转换为DataFrame时返回原始字典
    
    elif ext == '.html':
        # 读取HTML表格
        print(f"正在读取HTML文件: {file_path}")
        tables = pd.read_html(file_path)
        if tables:
            return tables[0]  # 返回第一个表格
    
    elif ext == '.docx':
        # 读取Word文档中的表格
        print(f"正在读取Word文件: {file_path}")
        doc = Document(file_path)
        if doc.tables:
            # 提取第一个表格
            table = doc.tables[0]
            data = []
            for row in table.rows:
                row_data = [cell.text.strip() for cell in row.cells]
                data.append(row_data)
            if len(data) > 1:
                return pd.DataFrame(data[1:], columns=data[0])
        return None
    
    elif ext == '.pdf':
        # 读取PDF中的表格
        print(f"正在读取PDF文件: {file_path}")
        with pdfplumber.open(file_path) as pdf:
            for page in pdf.pages:
                tables = page.extract_tables()
                if tables:
                    table = tables[0]
                    # 清洗数据
                    cleaned = []
                    for row in table:
                        cleaned_row = [
                            cell.replace('\n', ' ').strip() if cell else ''
                            for cell in row
                        ]
                        cleaned.append(cleaned_row)
                    if len(cleaned) > 1:
                        return pd.DataFrame(cleaned[1:], columns=cleaned[0])
        return None
    
    else:
        print(f"不支持的文件格式: {ext}")
        return None


# ===== 使用示例 =====

# 定义要读取的文件列表
files = [
    'data/sales.csv',
    'data/inventory.xlsx',
    'data/config.json',
    'data/web_table.html',
    'data/report.docx',
    'data/statement.pdf'
]

# 遍历文件列表并读取
for file_path in files:
    try:
        # 调用函数读取数据
        data = read_multi_format_data(file_path)
        
        # 判断返回数据类型并打印
        if isinstance(data, pd.DataFrame):
            print(f"  数据形状: {data.shape}")
            print(f"  列名: {list(data.columns)}")
            print(data.head(3))
        elif data is not None:
            print(f"  数据类型: {type(data)}")
            print(f"  内容预览: {str(data)[:200]}")
        else:
            print(f"  未能从文件中提取数据")
        
        print("-" * 50)
    
    except FileNotFoundError:
        print(f"  文件不存在: {file_path}")
        print("-" * 50)
    except Exception as e:
        print(f"  读取出错: {e}")
        print("-" * 50)

7.3 本章小结

  1. CSV/TXT文件 :使用pd.read_csv()读取,通过sep参数指定分隔符,encoding指定编码,names自定义列名,usecols选择列,parse_dates解析日期。

  2. Excel文件 :使用pd.read_excel()读取,通过sheet_name选择工作表,支持按名称、索引或同时读取多个工作表,需要openpyxl引擎支持。

  3. JSON文件 :使用json.load()读取原始JSON数据,使用pd.read_json()直接转换为DataFrame,使用pd.json_normalize()展平嵌套JSON结构。

  4. HTML表格 :使用pd.read_html()自动解析HTML中的<table>标签,支持本地文件和URL,通过match参数匹配特定表格,需要lxmlhtml5lib库支持。

  5. Word文件 :使用python-docx库,通过Document类打开文档,paragraphs获取段落列表,tables获取表格列表,可以提取文本、格式和表格数据。

  6. PDF文件 :使用pdfplumber库,通过open()打开PDF,extract_text()提取文本,extract_tables()提取表格,支持页面裁剪和区域提取,适合处理复杂的PDF文档。

相关推荐
吃好睡好便好42 分钟前
矩阵秩的计算
人工智能·学习·线性代数·算法·机器学习·matlab·矩阵
weixin_468466851 小时前
深度学习损失函数新手实战指南
人工智能·python·深度学习·算法·机器学习·ai
ZC跨境爬虫1 小时前
SQL学习日志 Day_1:初识SQL,开启数据之旅
数据库·sql·学习
biter down1 小时前
3.Python 接口自动化之 Pytest 测试框架
开发语言·python
浩风祭月1 小时前
如何用 AI 工具 10 倍速学习新技术栈:从零到生产级项目实战
人工智能·学习·chatgpt
天天爱吃肉82181 小时前
【汽车研发测试工程师|Python自动化实测全套脚本(CAN解析+数据处理+自动出报告)】
大数据·python·功能测试·嵌入式硬件·汽车
库奇噜啦呼1 小时前
【iOS】源码学习-KVC与KVO
学习·ios·cocoa
梅羽落1 小时前
WIFI破解
开发语言·python
xxxxxue1 小时前
Windows 通过 右键菜单 调用 Python 脚本
开发语言·windows·python·右键菜单