Metadata-Version: 2.4
Name: pd_to_sheet
Version: 2.2.0
Summary: 一个将pandas数据框输出到Excel并美化表格的工具。
Author: sgg
Author-email: police@foxmail.com
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.6
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pandas
Requires-Dist: xlsxwriter
Requires-Dist: openpyxl
Requires-Dist: py-ip2region
Requires-Dist: requests
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: license-file
Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary

# pd_to_sheet 使用手册

一个将 pandas DataFrame 数据富化并导出为格式化 Excel 的工具库。支持身份证号解析、手机号归属地查询、IPv4/IPv6 地址定位，以及多 Sheet 格式化 Excel 导出。

## 安装

```bash
pip install pd_to_sheet
```

依赖：pandas、openpyxl、xlsxwriter、py-ip2region

## 模块一览

| 模块 | 功能 | 核心方法 |
|------|------|----------|
| `admin_area_code` | 身份证号 → 省/市/区县 + 年龄 | `get_admin_area()`, `admin_code_search()` |
| `phone` | 手机号 → 归属省区/城市/运营商 | `get_mobile_area()` |
| `ip_area` | IP地址 → 国家/省份/地市/运营商 | `get_ip_area()`, `ip_area_search()` |
| `ipv6` | IPv6地址 → 国家/省份/地市/区县/运营商 | `get_ip_info()` |
| `check_idcard_num` | 身份证号校验位验证 | `is_valid_id_card()` |
| `to_excel` | DataFrame → 格式化 Excel | `save_df_to_sheet()`, `set_column_width_and_merge_header()`, `format_excel_file()` |

---

## 1. 身份证行政区划解析 — `admin_area_code`

### `get_admin_area(df, admin_column, res_column_prefix=None)`

从 DataFrame 中的身份证号列提取前6位行政区划代码，查询对应的省份、地市、区县，并根据身份证中的出生日期计算年龄。行政区划名称中的民族自治后缀（如"壮族"、"回族"等）会自动去除。

**参数：**

| 参数 | 类型 | 说明 |
|------|------|------|
| `df` | DataFrame | 源数据 |
| `admin_column` | str | 身份证号所在列名 |
| `res_column_prefix` | str, 可选 | 结果列名前缀，默认与 `admin_column` 相同 |

**返回值：** DataFrame，新增 `{prefix}省份`、`{prefix}地市`、`{prefix}区县`、`{prefix}年龄` 四列。

**示例：**

```python
import pandas
from pd_to_sheet.admin_area_code import get_admin_area

df = pandas.DataFrame({
    "id_card": ["422802199001011234", "110105198512151234"],
    "name": ["张三", "李四"],
})

result = get_admin_area(df, "id_card", "id_")
print(result)
#   id_card              name  id_省份  id_地市    id_区县  id_年龄
# 0  422802199001011234   张三   湖北省   恩施州    利川市     36
# 1  110105198512151234   李四   北京市   北京市   朝阳区     40
```

### `admin_code_search(id_card_num_list)`

批量查询一组身份证号对应的行政区划信息（不计算年龄，不附加到原 DataFrame）。

**参数：**

| 参数 | 类型 | 说明 |
|------|------|------|
| `id_card_num_list` | list/tuple/set | 身份证号列表 |

**返回值：** DataFrame，包含 `行政区划代码`、`省份`、`地市`、`区县` 四列。

**示例：**

```python
from pd_to_sheet.admin_area_code import admin_code_search

result = admin_code_search(["422802199001011234", "110105198512151234"])
print(result)
#   行政区划代码   省份    地市     区县
# 0     422802   湖北省  恩施州   利川市
# 1     110105   北京市  北京市  朝阳区
```

---

## 2. 手机号归属地查询 — `phone`

### `get_mobile_area(df, mobile_column)`

取手机号前7位，从本地数据库查询归属省区、城市和运营商。

**参数：**

| 参数 | 类型 | 说明 |
|------|------|------|
| `df` | DataFrame | 源数据 |
| `mobile_column` | str | 手机号所在列名 |

**返回值：** DataFrame，新增 `{mobile_column}归属省区`、`{mobile_column}归属城市`、`{mobile_column}归属运营商` 三列。

**示例：**

```python
import pandas
from pd_to_sheet.phone import get_mobile_area

df = pandas.DataFrame({
    "name": ["张三", "李四"],
    "mobile": ["13812345678", "15912345678"],
})

result = get_mobile_area(df, "mobile")
print(result)
#   name     mobile  mobile归属省区  mobile归属城市  mobile归属运营商
# 0  张三  13812345678        江苏        连云港        中国移动
# 1  李四  15912345678        云南         文山        中国移动
```

---

## 3. IP 地址归属地查询 — `ip_area`

### `get_ip_area(df, ip_column, res_column_prefix=None)`

查询 DataFrame 中 IP 地址列的归属地。自动识别 IPv4 和 IPv6：IPv4 通过 ip2region v4 数据库查询（精度到地市），IPv6 通过 ipdata.db 查询（精度到区县）。

**参数：**

| 参数 | 类型 | 说明 |
|------|------|------|
| `df` | DataFrame | 源数据 |
| `ip_column` | str | IP 地址所在列名 |
| `res_column_prefix` | str, 可选 | 结果列名前缀，默认与 `ip_column` 相同 |

**返回值：** DataFrame，新增 `{prefix}国家`、`{prefix}省份`、`{prefix}地市`、`{prefix}区县`、`{prefix}运营商` 五列。

**示例：**

```python
import pandas
from pd_to_sheet.ip_area import get_ip_area

df = pandas.DataFrame({
    "ip": ["182.239.93.16", "2409:8a34:9646:44b1:c828:c973:6d49:0b17"],
    "user": ["user_a", "user_b"],
})

result = get_ip_area(df, "ip")
print(result)
#                                      ip    user  ip国家    ip省份   ip地市  ip区县        ip运营商
# 0                          182.239.93.16  user_a   中国  香港特别行政区              移动
# 1  2409:8a34:9646:44b1:c828:c973:6d49:0b17  user_b   中国     福建省   南平市  延平区  中国移动公众宽带
```

### `ip_area_search(ip_list)`

底层批量查询函数，接受 IP 地址列表，返回包含归属地信息的 DataFrame。自动区分 IPv4 和 IPv6。

**参数：**

| 参数 | 类型 | 说明 |
|------|------|------|
| `ip_list` | list | IP 地址列表 |

**返回值：** DataFrame，包含 `ip`、`country`、`province`、`city`、`isp` 列（IPv6 还包含 `county` 列）。

**示例：**

```python
from pd_to_sheet.ip_area import ip_area_search

result = ip_area_search(["114.114.114.114", "8.8.8.8"])
print(result)
#              ip country province  city     isp
# 0  114.114.114.114     中国     江苏省   南京市
# 1      8.8.8.8    美国                          
```

---

## 4. IPv6 归属地查询 — `ipv6`

### `get_ip_info(ip_list)`

直接查询 IPv6 地址归属地，精度到区县一级。通常不需要直接调用，`get_ip_area()` 会自动分流 IPv6 地址到此函数。

**参数：**

| 参数 | 类型 | 说明 |
|------|------|------|
| `ip_list` | list | IPv6 地址列表 |

**返回值：** DataFrame，包含 `ip`、`country`、`province`、`city`、`county`、`isp` 列。

**示例：**

```python
from pd_to_sheet.ipv6 import get_ip_info

result = get_ip_info([
    "2409:8a34:9646:44b1:c828:c973:6d49:0b17",
    "2409:8a4c:b212:83c0:90ea:f964:25fa:b51f",
])
print(result)
#                                     ip country province city county              isp
# 0  2409:8a34:9646:44b1:c828:c973:6d49:0b17     中国     福建省  南平市  延平区   中国移动公众宽带
# 1  2409:8a4c:b212:83c0:90ea:f964:25fa:b51f     中国     湖北省  恩施州  利川市   中国移动公众宽带
```

---

## 5. 身份证号校验 — `check_idcard_num`

### `is_valid_id_card(id_card)`

验证18位身份证号的校验码是否正确（加权求和模11校验）。

**参数：**

| 参数 | 类型 | 说明 |
|------|------|------|
| `id_card` | str | 18位身份证号 |

**返回值：** bool

**示例：**

```python
from pd_to_sheet.check_idcard_num import is_valid_id_card

print(is_valid_id_card("422802198608125471"))  # True
print(is_valid_id_card("123456789012345678"))  # False
```

---

## 6. Excel 格式化导出 — `to_excel`

### `save_df_to_sheet(excel_writer, sheet_name, pandas_df, wrap_columns=None)`

将一个 DataFrame 写入 ExcelWriter 的指定 Sheet，并应用完整的格式化样式：自动添加序号列、表头加粗+绿色背景、蓝色边框、自适应列宽（支持中文字符宽度计算）、冻结首行、自动换行、A4 纸张、页脚页码。

**参数：**

| 参数 | 类型 | 说明 |
|------|------|------|
| `excel_writer` | ExcelWriter | pandas ExcelWriter 实例 |
| `sheet_name` | str | Sheet 名称 |
| `pandas_df` | DataFrame | 要写入的数据 |
| `wrap_columns` | list, 可选 | 需要根据换行符自动调整行高的列名列表 |

**返回值：** excel_writer（支持链式调用）。

**示例：**

```python
import pandas
from pd_to_sheet.to_excel import save_df_to_sheet

df = pandas.DataFrame({
    "姓名": ["张三", "李四"],
    "年龄": [25, 30],
    "备注": ["正常\n无异常", "需要关注"],
})

with pandas.ExcelWriter("output.xlsx") as writer:
    save_df_to_sheet(writer, "人员信息", df, wrap_columns=["备注"])
```

### `set_column_width_and_merge_header(file_path, output_path, sheet_params)`

对已生成的 Excel 文件进行二次加工：在顶部插入合并标题行（方正小标宋简体 18pt），在底部追加说明行，并根据列数自动选择横向/纵向打印布局。

**参数：**

| 参数 | 类型 | 说明 |
|------|------|------|
| `file_path` | str | 输入 Excel 文件路径 |
| `output_path` | str | 输出 Excel 文件路径 |
| `sheet_params` | dict | 每个 Sheet 的自定义参数，格式见下方示例 |

**`sheet_params` 格式：**

```python
sheet_params = {
    "Sheet名称": {
        "title": "合并标题行显示的文本",
        "description": "底部说明行显示的文本（需包含'说明'关键字触发）",
    }
}
```

**示例：**

```python
from pd_to_sheet.to_excel import set_column_width_and_merge_header

sheet_params = {
    "人员信息": {
        "title": "2024年度人员信息统计表",
        "description": "说明：本表数据来源于XX系统，统计截止时间为2024年12月。",
    }
}

set_column_width_and_merge_header("output.xlsx", "output_final.xlsx", sheet_params)
```

### `format_excel_file(file_path, output_path, header=0)`

便捷函数：读取一个已有的 Excel 文件（所有 Sheet），对每个 Sheet 应用 `save_df_to_sheet` 的格式化样式后输出到新文件。适合对非本库生成的 Excel 文件进行统一格式化。

**参数：**

| 参数 | 类型 | 说明 |
|------|------|------|
| `file_path` | str | 输入 Excel 文件路径 |
| `output_path` | str | 输出 Excel 文件路径 |
| `header` | int, 可选 | 表头行号，默认 0（第一行为表头） |

**示例：**

```python
from pd_to_sheet.to_excel import format_excel_file

format_excel_file("raw_data.xlsx", "formatted_data.xlsx")
```

---

## 完整工作流示例

将数据富化和 Excel 导出组合使用：

```python
import pandas
from pd_to_sheet.admin_area_code import get_admin_area
from pd_to_sheet.phone import get_mobile_area
from pd_to_sheet.ip_area import get_ip_area
from pd_to_sheet.to_excel import save_df_to_sheet, set_column_width_and_merge_header

# 1. 准备原始数据
df = pandas.DataFrame({
    "姓名": ["张三", "李四", "王五"],
    "身份证号": ["422802199001011234", "110105198512151234", "330106199203051234"],
    "手机号": ["13812345678", "15912345678", "18612345678"],
    "登录IP": ["182.239.93.16", "114.114.114.114", "2409:8a34:9646:44b1::"],
})

# 2. 逐步富化数据
df = get_admin_area(df, "身份证号", "身份证_")
df = get_mobile_area(df, "手机号")
df = get_ip_area(df, "登录IP", "IP_")

# 3. 导出为格式化 Excel
output_path = "result.xlsx"
with pandas.ExcelWriter(output_path) as writer:
    save_df_to_sheet(writer, "综合信息", df)

# 4. 二次加工：添加标题行和说明
sheet_params = {
    "综合信息": {
        "title": "人员综合信息统计表",
        "description": "说明：数据来源于XX系统。",
    }
}
set_column_width_and_merge_header(output_path, "result_final.xlsx", sheet_params)
```

---

## 内置数据库说明

| 文件 | 用途 | 精度 |
|------|------|------|
| `db/ip2region_v4.xdb` | IPv4 地址定位（ip2region v4） | 国家/省份/地市/运营商 |
| `db/ipdata.db` | IPv6 地址定位 | 国家/省份/地市/区县/运营商 |
| `db/MobileArea.db` | 手机号归属地 | 省区/城市/运营商 |
| `db/admin_area_code.db` | 行政区划代码 | 省份/地市/区县 |
