数据获取 --- 知识点详解与案例代码
一、从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-8、gbk、gb2312 |
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 |
读取引擎,openpyxl或xlrd |
案例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。该函数底层依赖lxml和html5lib等HTML解析库。
注意: 需要提前安装解析库:
bash
pip install lxml html5lib
4.2 核心函数:pd.read_html()
主要参数说明:
| 参数 | 说明 |
|---|---|
io |
URL字符串、文件路径或HTML字符串 |
match |
正则表达式,用于匹配表格中的文本内容 |
flavor |
解析引擎,lxml或html5lib |
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 |
文档中的文本和表格 |
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 本章小结
-
CSV/TXT文件 :使用
pd.read_csv()读取,通过sep参数指定分隔符,encoding指定编码,names自定义列名,usecols选择列,parse_dates解析日期。 -
Excel文件 :使用
pd.read_excel()读取,通过sheet_name选择工作表,支持按名称、索引或同时读取多个工作表,需要openpyxl引擎支持。 -
JSON文件 :使用
json.load()读取原始JSON数据,使用pd.read_json()直接转换为DataFrame,使用pd.json_normalize()展平嵌套JSON结构。 -
HTML表格 :使用
pd.read_html()自动解析HTML中的<table>标签,支持本地文件和URL,通过match参数匹配特定表格,需要lxml和html5lib库支持。 -
Word文件 :使用
python-docx库,通过Document类打开文档,paragraphs获取段落列表,tables获取表格列表,可以提取文本、格式和表格数据。 -
PDF文件 :使用
pdfplumber库,通过open()打开PDF,extract_text()提取文本,extract_tables()提取表格,支持页面裁剪和区域提取,适合处理复杂的PDF文档。