法律和经济科学

法学实证 | 海量司法裁判文书关键信息快速提取完整版教程(含源文件)

130
发表时间:2025-04-12 14:16作者:阳李

司法裁判文书通常具有固定的结构,不同案件类型(民事、刑事、行政)的文书格式略有差异,但核心部分基本一致。因此,根据具体结构,可以实现快速提取关键信息的目标。

以下是根据文书结构逐层提取关键信息的方法及注意事项。

提取软件:Python(可到官网免费下载https://www.python.org/

常用的安装库:openpyxl等。

一、解读原始文档

我们提供的原始文档的名称为:202012月裁判文书数据(上传公众号)。其中,第15列(也就是第O列)为裁判文书的全文,也就是后文要分析的原始文本,一共有18466份裁判文书。

、提取年份

从该文件的第15列(也就是第O列)中提取年份,年份只能是数字,范围为1987至2022,从第15列每一行文本中第一次出现符号“(”或者“(”时,从这个符号后面的四个数字中提取,随后将提取的年份放置在第17列(也就是第Q列),若没有提取到年份,则在第17列对应位置赋值为0.5(主要是考虑一些例外情况,便于后期处理)。若该文件没有第17列,则补足,并将第17列的标题确定为“年份”。最后,将匹配后的原excel文件名加上后缀“_2”,以便区分。(也就是不产生新的excel文件)

import re

from openpyxl import load_workbook

import os

# 定义文件名

original_file = "202012月裁判文书数据(上传公众号).xlsx"

base, ext = os.path.splitext(original_file)

new_file = f"{base}_2{ext}"

# 加载工作簿和工作表

wb = load_workbook(original_file)

ws = wb.active

# 确保第17列存在并设置标题

ws.cell(row=1, column=17, value="年份")

# 处理每一行数据

for row in range(2, ws.max_row + 1):

    cell_value = str(ws.cell(row=row, column=15).value or "")

    year = 0.5   # 默认值

    # 使用正则表达式匹配年份

    match = re.search(r'[(](\d{4})', cell_value)

    if match:

        year_str = match.group(1)

        if year_str.isdigit():

            year_num = int(year_str)

            if 1987 <= year_num <= 2022:

                year = year_num

    # 写入结果到Q

    ws.cell(row=row, column=17, value=year)

# 保存修改后的文件

wb.save(new_file)

print(f"处理完成,文件已保存为:{new_file}")

三、提取地区

15列(也就是第O列)中提取地区,地区是从第15列每一行文本中第一个字开始,到第一次出现关键字之前的文字(提取的地区不包含等关键字);同时,只要出现了中的任何一个关键字,则不再往后搜寻;将提取后的地区放置在第18列(也就是第R列);(3)若全文没有提取到地区,则在第18列对应位置赋值为0.5(主要是考虑一些例外情况,便于后期处理)。若该文件没有第18列,则补足,并将第18列的标题确定为地区。最后,将匹配后的原excel文件名加上后缀“_3”,以便区分。

import re

from openpyxl import load_workbook

def extract_region(text):

    """从文本中提取地区信息"""

    match = re.search(r'^.*?(?=[省市区县])', str(text))

    if match:

        region = match.group().strip()

        return region if region else 0.5

    return 0.5

# 加载Excel文件

file_name = '202012月裁判文书数据(上传公众号)_2.xlsx'

wb = load_workbook(file_name)

ws = wb.active

# 确保第18列标题正确

if ws.cell(row=1, column=18).value != '地区':

    ws.cell(row=1, column=18, value='地区')

# 处理每一行数据

for row in range(2, ws.max_row + 1):

    # 获取第15列内容

    cell_value = ws.cell(row=row, column=15).value

    # 提取地区信息

    region = extract_region(cell_value)

    # 写入第18

    ws.cell(row=row, column=18, value=region)

# 保存新文件

new_file_name = file_name.replace('.xlsx', '_3.xlsx')

wb.save(new_file_name)

print("处理完成,文件已保存为:", new_file_name)

即得到如下结果。

四、提取犯罪人信息

15列(也就是第O列)中提取犯罪人信息,犯罪人信息是从第15列的每一行文本中第一次出现关键词被告人上诉人罪犯开始,直到第一个句号时结束,并将提取后的犯罪人信息放置在第19列(也就是第S列)。若全文没有出现关键词被告人上诉人罪犯,则在第19列对应位置赋值为0.5(主要是考虑一些例外情况,便于后期处理)。若该文件没有第19列,则补足,并将第19列的标题确定为犯罪人信息。最后,将匹配后的原excel文件名加上后缀“_4”,以便区分。

import openpyxl

from openpyxl import load_workbook

def extract_info(text):

    """从文本中提取犯罪人信息"""

    if not isinstance(text, str):   # 确保处理的是字符串

        return 0.5

   

    keywords = ['被告人', '上诉人', '罪犯']

    start_pos = -1

   

    # 查找所有关键词的首次出现位置

    for keyword in keywords:

        pos = text.find(keyword)

        if pos != -1:

            if start_pos == -1 or pos < start_pos:

                start_pos = pos

   

    if start_pos == -1:   # 没有找到关键词

        return 0.5

   

    # 查找结束位置(第一个句号)

    end_pos = text.find('', start_pos)

   

    if end_pos == -1:    # 没有句号则取到末尾

        return text[start_pos:]

    else:                # 包含句号

        return text[start_pos:end_pos+1]

# 加载工作簿

original_file = "202012月裁判文书数据(上传公众号)_2_3.xlsx"

wb = load_workbook(original_file)

ws = wb.active

# 设置S列标题(如果不存在)

ws.cell(row=1, column=19, value="犯罪人信息")

# 遍历所有数据行(从第二行开始)

for row in ws.iter_rows(min_row=2):

    # 获取O列内容(第15列)

    o_cell = row[14]   # 索引从0开始

   

    # 提取信息并写入S

    extracted = extract_info(o_cell.value)

    ws.cell(row=o_cell.row, column=19, value=extracted)

# 保存新文件

new_file = original_file.replace(".xlsx", "_4.xlsx")

wb.save(new_file)

print(f"处理完成,已保存为:{new_file}")

即得到如下结果。

五、提取法院认定情节

15列(也就是第O列)中提取法院认定情节,法院认定情节是从第15列的每一行文本中第一次出现关键词本院认为时开始,直至出现关键词判决如下裁定如下时结束,并将提取后的法院认定情节放置在第20列(也就是第T列),提取后的法院认定情节应当包含关键词本院认为”“判决如下裁定如下。若全文没有出现关键词本院认为,则在第20列对应位置赋值为0.5(主要是考虑一些例外情况,便于后期处理)。若该文件没有第20列,则补足,并将第20列的标题确定为法院认定情节。最后,将匹配后的原excel文件名加上前缀“5-”,以便区分。

import openpyxl

from openpyxl import load_workbook

def extract_judgment_info(text):

    """提取包含起止关键词的法院认定情节"""

    if not isinstance(text, str):

        return 0.5

    start_keyword = "本院认为"

    end_keywords = ["判决如下", "裁定如下"]

    # 查找起始关键词

    start_pos = text.find(start_keyword)

    if start_pos == -1:

        return 0.5   # 未找到起始关键词

    # 查找最近的结束关键词(必须出现在起始关键词之后)

    end_pos = None

    for keyword in end_keywords:

        pos = text.find(keyword, start_pos)

        if pos != -1:

            # 计算结束位置时要包含整个结束关键词

            current_end = pos + len(keyword)

            end_pos = min(end_pos, current_end) if end_pos else current_end

    # 确定截取范围

    if end_pos:

        extracted = text[start_pos:end_pos]

    else:

        extracted = text[start_pos:]   # 无结束关键词时取到末尾

    # 清理空白并验证有效性

    extracted = extracted.strip()

    return extracted if extracted else 0.5

# 文件配置

original_file = "202012月裁判文书数据(上传公众号)_2_3_4.xlsx"

new_file = "5-" + original_file

# 处理Excel文件

wb = load_workbook(original_file)

ws = wb.active

# 创建/更新第20

header = "法院认定情节"

ws.cell(row=1, column=20, value=header)

# 处理数据行

for row in ws.iter_rows(min_row=2):

    original_text = row[14].value   # O列内容

    result = extract_judgment_info(original_text)

    ws.cell(row=row[0].row, column=20, value=result)

# 保存结果

wb.save(new_file)

print(f"处理完成,生成文件:{new_file}")

六、提取判决信息

15列(也就是第O列)中提取判决信息,判决信息是从第15列的每一行文本中第一次出现关键词判决如下裁定如下开始,直到第一个句号时结束,并将提取后的判决信息放置在第21列(也就是第U列),提取后的判决信息应当包含关键词判决如下裁定如下,也包括第一个句号。若全文没有出现关键词判决如下裁定如下,则在第21列对应位置赋值为0.5(主要是考虑一些例外情况,便于后期处理)。若该文件没有第21列,则补足,并将第21列的标题确定为判决信息。最后,将匹配后的原excel文件名加上前缀“6-”,以便区分。

import openpyxl

import os

# 输入文件名

filename = "5-202012月裁判文书数据(上传公众号)_2_3_4.xlsx"

# 加载工作簿

wb = openpyxl.load_workbook(filename)

ws = wb.active

# 确保第21列存在并设置标题

ws.cell(row=1, column=21, value="判决信息")

# 遍历处理每一行数据

for row in range(2, ws.max_row + 1):

    # 获取第15列(O列)单元格内容

    o_cell = ws.cell(row=row, column=15)

    text = str(o_cell.value) if o_cell.value is not None else ""

   

    # 初始化提取结果

    extracted = 0.5

   

    # 查找关键词位置

    positions = []

    for keyword in ["判决如下", "裁定如下"]:

        idx = text.find(keyword)

        if idx != -1:

            positions.append(idx)

   

    if positions:

        start = min(positions)

        end = text.find("", start)

       

        if end != -1:

            extracted = text[start:end+1]

   

    # 写入第21列(U列)

    ws.cell(row=row, column=21, value=extracted)

# 保存新文件

new_filename = f"6-{filename}"

# 处理文件名冲突

counter = 1

while os.path.exists(new_filename):

    new_filename = f"6-{filename[:-5]}({counter}).xlsx"

    counter += 1

wb.save(new_filename)

print(f"处理完成,新文件已保存为:{new_filename}")

七、提取犯罪人出生年份

19列(也就是第S列)中提取犯罪人的出生年份。判断规则如下:从第19列(也就是第S列)的文本中,在关键词出生所在的这句话(这句话的范围以关键词出生前后第一次出现”“,”或者”“.”为准)中提取年份,并将这个年份复制在第23列(也就是第W列)对应位置,例如,19691224日出生,则提取1969;若全文中都没有出现关键字出生,则在第23列(也就是第W列)对应位置赋值为0.5(主要是考虑一些例外情况,便于后期处理)。若该文件没有第23列,则补足,并将第23列的标题确定为犯罪人出生年份。最后,将匹配后的原excel文件名加上前缀“8-”,以便区分。

import openpyxl

import re

def extract_birthyear(text):

    """从包含关键词的句子中提取出生年份"""

    text = str(text)

    keywords = ['出生', '']

    punctuations = ['', ',', '', '.']   # 中英文标点

   

    for keyword in keywords:

        start_idx = 0

        while True:

            # 查找关键词位置

            kw_pos = text.find(keyword, start_idx)

            if kw_pos == -1:

                break

           

            # 向前查找最近的标点

            prev_punct = -1

            for i in range(kw_pos-1, -1, -1):

                if text[i] in punctuations:

                    prev_punct = i

                    break

           

            # 向后查找最近的标点

            next_punct = len(text)

            for i in range(kw_pos, len(text)):

                if text[i] in punctuations:

                    next_punct = i

                    break

           

            # 截取完整句子

            sentence = text[prev_punct+1 : next_punct]

           

            # 在句子中匹配年份(1900-2010

            year_match = re.search(r'(19[0-9]{2}|200[0-9]|2010)', sentence)

            if year_match:

                return int(year_match.group())

           

            start_idx = kw_pos + len(keyword)   # 继续查找下一个关键词

   

    return 0.5   # 未找到符合条件的情况

# 文件处理

file_name = '6-5-202012月裁判文书数据(上传公众号)_2_3_4.xlsx'

new_file_name = '8-' + file_name

# 加载工作簿

wb = openpyxl.load_workbook(file_name)

ws = wb.active

# 创建/验证第23列标题

header = ws.cell(row=1, column=23)

if header.value != '犯罪人出生年份':

    header.value = '犯罪人出生年份'

# 处理数据行

for row in range(2, ws.max_row + 1):

    source_cell = ws.cell(row=row, column=19)   # S

    target_cell = ws.cell(row=row, column=23)   # W

   

    # 执行提取逻辑

    target_cell.value = extract_birthyear(source_cell.value)

# 保存新文件

wb.save(new_file_name)

print(f'处理完成,新文件已保存为:{new_file_name}')

八、是否判处罚金

从第15列(也就是第O列)判断是否判处罚金,从第15列的每一行文本中第一次出现关键词“判决如下”或“裁定如下”时开始,直到文末,若没有出现关键词“罚金”,则在第26列(第Z列)相应位置赋值为0,若出现关键词“罚金”,则在第26列(第Z列)相应位置赋值为1。若该文件没有第26列,则补足,并将第26(第Z列)列的标题确定为“罚金”。最后,将匹配后的原excel文件名加上后缀“11_”,以便区分。

import openpyxl

import os

def check_penalty(text):

    """检查文本中是否包含'罚金',从第一次出现'判决如下'或'裁定如下'开始"""

    if not isinstance(text, str):

        return 0

    keywords = ["判决如下", "裁定如下"]

    positions = [text.find(kw) for kw in keywords]

    valid_positions = [p for p in positions if p != -1]

   

    if not valid_positions:

        return 0   # 无关键词则直接返回0

   

    start_pos = min(valid_positions)

    substring = text[start_pos:]

    return 1 if "罚金" in substring else 0

def process_excel(file_path):

    """处理Excel文件"""

    wb = openpyxl.load_workbook(file_path)

    ws = wb.active

    # 确保第26列存在且标题正确

    z_col = 26

    if ws.cell(row=1, column=z_col).value != "罚金":

        ws.cell(row=1, column=z_col, value="罚金")

    # 遍历处理每一行

    for row in ws.iter_rows(min_row=2):   # 跳过标题行

        o_cell = row[14]   # 第15列是索引14

        result = check_penalty(o_cell.value)

        ws.cell(row=o_cell.row, column=z_col, value=result)

    # 保存新文件

    new_path = f"11_{os.path.basename(file_path)}"

    wb.save(new_path)

    print(f"处理完成,新文件已保存为: {new_path}")

# 使用示例(替换为实际路径)

process_excel("8-6-5-2020年12月裁判文书数据(上传公众号)_2_3_4.xlsx")

最后,司法裁判文书关键信息提取是一项繁琐且可能有诸多例外信息需要考量的工作,上述方法并未穷尽一些例外情况,读者可结合具体情况具体分析。