一种辅助整理知网论文题录文档的方法(Excel、Word)

知网导出的题录文件通常用于NoteExpress、EndNote等文献管理软件,想要做成表格一览无余或是Word文档怎么操作呢?

继之前写过的一篇WoS英文题录翻译整理之后,本次尝试将知网导出的题录文件整理为可读性较高的Excel和Word,可用于研究态势总览和文献筛选。

一种辅助整理WoS英文论文题录文档的方法(python-docx)https://blog.csdn.net/u014111377/article/details/126016414

目录

一、知网导出题录文件

二、Excel题录处理

三、Word题录处理

四、完整实现代码

五、使用方法


一、知网导出题录文件

选中所需论文,选择导出文献“自定义”

选择所需字段,下载为xls格式(建议选中“摘要”“年”“发表时间”等)

二、Excel题录处理

导出的题录文件打开时提示文件格式和扩展名不匹配,且浏览不便。这是由于知网导出的xls文件内部并不是Excel格式,而是html代码。

处理函数参数如下(完整代码在最后)

def cnki_processing(filenames, input_dir, output_dir, sort_by=None, ascending=True, union=False):
    # (文件名,输入文件夹,输出文件夹,排序列,正序True/倒序False,是否合为一个文件)

read_file()、process_excel()、process_word()为其子函数。

首先读入文件,使用BeautifulSoup进行解析html,转换为DataFrame格式。此处主要查看期刊、硕博和会议论文,排除“科技成果”类型。

def read_file(filename):  # 读入知网题录xls文件,将文件转为DataFrame
    # 知网导出题录的Excel文件并不是Excel格式,而是html代码,需要从中提取表格内容
    with open(input_dir + '\\' + filename, 'r', encoding='utf-8') as f:
        content = f.read()
    
    soup = BeautifulSoup(content, 'html.parser')
    table = soup.find('table')  # 定位到表格
    columns = [td.text.split('-')[-1] for td in table.find('tr')]  # 表格列名(只保留中文部分)
    # 将表格信息通过列表推导式形成二维列表,然后转为DataFrame
    df = pd.DataFrame([[td.text for td in tr] for tr in table.find_all('tr')[1:]], columns=columns)
    df = df[(df['来源库']!='SrcDatabase-来源库') & (df['来源库']!='科技成果')].dropna(subset='来源库')  # 去除重复表头和空行
    return df

处理生成Excel题录并调整格式提高可读性。此处由于经多种方法尝试,pandas输出的表头难以调整格式(可能由于版本原因,网上的方法不起作用),将表头转变为普通行以调整格式。具体步骤可见代码注释。

def process_excel(df, filenamep):  # 处理Excel函数
    # (上一步处理后的DataFrame,将要保存的文件名)
    
    if sort_by in df.columns:  # 指定的排序列若存在
        df.sort_values(by=sort_by, ascending=ascending, inplace=True)
    elif type(sort_by) == str:  # 列名不存在
        print('Warning: \'' + sort_by + '\' 不在题录文件中,未进行排序。')
    elif sort_by:  # 不为None
        print('Warning: sort_by参数应为str类型,未进行排序。')
    
    df = df.reset_index(drop=True).reset_index()  # 生成序号
    df['index'] = df['index'] + 1  # 序号从1开始
    df['摘要'] = df['摘要'].map(lambda x: re.sub('^\n', '', re.sub('\n+\t*', '\n', x)))  # 摘要文本清洗,去除多余换行符和Tab
    columns = ['序号'] + df.columns.tolist()[1:]  # 整理列名,“index”替换为“序号”
    # 经多种方法尝试,pandas输出的表头难以调整格式,将表头转变为普通行
    df = pd.DataFrame([columns] + list(df.values), columns=columns)
    # 使用xlsxwriter输出自定义格式Excel
    writer = pd.ExcelWriter(output_dir + '\\' + filenamep + '.xlsx', engine='xlsxwriter')
    df.to_excel(writer, sheet_name='CNKI题录', index=False, header=False)  # 由于表内已包含序号和列名,不输出DataFrame的index和表头
    
    workbook  = writer.book
    worksheet = writer.sheets['CNKI题录']
    worksheet.set_default_row(18)  # 设置默认行高
    
    header_format = workbook.add_format({'align': 'center', 'bold': True, 'font_size': 11, 'font_name': u'微软雅黑'})  # 标题格式
    text_center_format = workbook.add_format({'align': 'center', 'font_size': 11, 'font_name': u'微软雅黑'})  # 文本居中格式
    text_format = workbook.add_format({'font_size': 11, 'font_name': u'微软雅黑'})  # 文本左对齐格式
    
    # 指定相应列的列宽和默认列宽
    width_dict = {'序号': 8, '来源库':8, '题名': 45, '关键词': 30, '摘要':30, '年': 8, 'default': 20}
    
    # 设置内容格式
    for idx, column in enumerate(columns):  # 遍历列名,idx下标用于转换Excel列索引
        # 列宽如有定义,使用定义数值,如无定义使用default
        width = width_dict[column] if column in width_dict.keys() else width_dict['default']
        if column in ['序号', '来源库', '发表时间', '年']:  # 这几列内容较短,居中显示
            worksheet.set_column(chr(65 + idx) + ':' + chr(65 + idx), width, text_center_format)  # chr将ASCII数值转换为字母列索引
        else:  # 其他左对齐
            worksheet.set_column(chr(65 + idx) + ':' + chr(65 + idx), width, text_format)
    
    worksheet.set_row(0, 18, header_format)  # 设置标题格式
    writer.save()  # 保存
    return df

整理后的效果如下(可选择是否排序、按什么字段排序)。

三、Word题录处理

如果想逐篇阅读摘要,Excel显得有些局限,因此另整理Word题录,并排版输出。

def process_word(df, filenamep):
    document = Document()
    document.styles['Normal'].font.size = Pt(12)  # 字体大小
    document.styles['Normal'].font.name = 'Times New Roman'  # 西文字体
    document.styles['Normal']._element.rPr.rFonts.set(qn('w:eastAsia'), '宋体')  # 中文字体
    document.styles['Normal'].paragraph_format.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY  # 两端对齐
    document.styles['Normal'].paragraph_format.line_spacing = 1.15  # 行距
    document.styles['Normal'].paragraph_format.space_before = Pt(3)  # 段前
    document.styles['Normal'].paragraph_format.space_after = Pt(3)  # 断后
    document.styles['Normal'].paragraph_format.first_line_indent = document.styles['Normal'].font.size * 2  # 首行缩进
    
    def add_heading_func(text, level, font_size, font_color=RGBColor(0, 0, 0), font_bold=True, line_spacing=1.15, first_line_indent=0, space_before=6, space_after=6, en_font='Times New Roman', cn_font='宋体'):
        # 增加标题函数,可能由于版本问题直接改样式不起作用,这里使用h、r2个变量来调整标题格式,分别是paragraph和run格式
        h = document.add_heading(level=level)
        r = h.add_run(text)
        r.font.size = Pt(font_size)  # 字体大小
        r.font.color.rgb = font_color  # 字体颜色
        r.font.bold = font_bold  # 加粗
        r.font.name = en_font  # 西文字体
        r._element.rPr.rFonts.set(qn('w:eastAsia'), cn_font)  # 中文字体
        
        if level == 0:  # 如果为大标题,居中,西文字体同中文字体
            h.paragraph_format.alignment = WD_ALIGN_PARAGRAPH.CENTER
            r.font.name = cn_font
        else:  # 其他标题两端对齐
            h.paragraph_format.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY
     
        h.paragraph_format.first_line_indent = r.font.size * first_line_indent  # 首行缩进
        h.paragraph_format.line_spacing = line_spacing  # 行距
        h.paragraph_format.space_before = Pt(space_before)  # 段前
        h.paragraph_format.space_after = Pt(space_after)  # 段后
     
    add_heading_func(filenamep, 0, 16, cn_font='微软雅黑')
     
    for i in df.loc[1:, ['序号', '来源库', '题名', '作者', '文献来源', '摘要', '年']].values:  # 循环遍历题录表格
        add_heading_func(str(i[0]) + '. '+ i[2] + '(' + re.sub(';$', '', i[3]) + ',' + (str(i[6]) if i[6] else '网络首发') + ')', 1, 12, font_color=RGBColor(0x4f, 0x81, 0xbd))
        document.add_paragraph('来源:' + i[4] + '('+ i[1] + ')')
        for j in i[5].split('\n'):
            document.add_paragraph(re.sub('^ *', '', j))
        document.add_paragraph()
     
    document.save(output_dir + '\\' + filenamep + '.docx')  # 保存文件

效果如下。

四、完整实现代码

# -*- coding: utf-8 -*-
import os
import re
import time
import pandas as pd
from bs4 import BeautifulSoup
from docx import Document
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.shared import Pt, RGBColor
from docx.oxml.ns import qn

def now():
    return time.strftime('%H:%M:%S', time.localtime())


def cnki_processing(filenames, input_dir, output_dir, sort_by=None, ascending=True, union=False):
    # (文件名,输入文件夹,输出文件夹,排序列,正序True/倒序False,是否合为一个文件)
    
    def read_file(filename):  # 读入知网题录xls文件,将文件转为DataFrame
        # 知网导出题录的Excel文件并不是Excel格式,而是html代码,需要从中提取表格内容
        with open(input_dir + '\\' + filename, 'r', encoding='utf-8') as f:
            content = f.read()
        
        soup = BeautifulSoup(content, 'html.parser')
        table = soup.find('table')  # 定位到表格
        columns = [td.text.split('-')[-1] for td in table.find('tr')]  # 表格列名(只保留中文部分)
        # 将表格信息通过列表推导式形成二维列表,然后转为DataFrame
        df = pd.DataFrame([[td.text for td in tr] for tr in table.find_all('tr')[1:]], columns=columns)
        df = df[(df['来源库']!='SrcDatabase-来源库') & (df['来源库']!='科技成果')].dropna(subset='来源库')  # 去除重复表头和空行
        return df
    
    def process_excel(df, filenamep):  # 处理Excel函数
        # (上一步处理后的DataFrame,将要保存的文件名)
        
        if sort_by in df.columns:  # 指定的排序列若存在
            df.sort_values(by=sort_by, ascending=ascending, inplace=True)
        elif type(sort_by) == str:  # 列名不存在
            print('Warning: \'' + sort_by + '\' 不在题录文件中,未进行排序。')
        elif sort_by:  # 不为None
            print('Warning: sort_by参数应为str类型,未进行排序。')
        
        df = df.reset_index(drop=True).reset_index()  # 生成序号
        df['index'] = df['index'] + 1  # 序号从1开始
        df['摘要'] = df['摘要'].map(lambda x: re.sub('^\n', '', re.sub('\n+\t*', '\n', x)))  # 摘要文本清洗,去除多余换行符和Tab
        columns = ['序号'] + df.columns.tolist()[1:]  # 整理列名,“index”替换为“序号”
        # 经多种方法尝试,pandas输出的表头难以调整格式,将表头转变为普通行
        df = pd.DataFrame([columns] + list(df.values), columns=columns)
        # 使用xlsxwriter输出自定义格式Excel
        writer = pd.ExcelWriter(output_dir + '\\' + filenamep + '.xlsx', engine='xlsxwriter')
        df.to_excel(writer, sheet_name='CNKI题录', index=False, header=False)  # 由于表内已包含序号和列名,不输出DataFrame的index和表头
        
        workbook  = writer.book
        worksheet = writer.sheets['CNKI题录']
        worksheet.set_default_row(18)  # 设置默认行高
        
        header_format = workbook.add_format({'align': 'center', 'bold': True, 'font_size': 11, 'font_name': u'微软雅黑'})  # 标题格式
        text_center_format = workbook.add_format({'align': 'center', 'font_size': 11, 'font_name': u'微软雅黑'})  # 文本居中格式
        text_format = workbook.add_format({'font_size': 11, 'font_name': u'微软雅黑'})  # 文本左对齐格式
        
        # 指定相应列的列宽和默认列宽
        width_dict = {'序号': 8, '来源库':8, '题名': 45, '关键词': 30, '摘要':30, '年': 8, 'default': 20}
        
        # 设置内容格式
        for idx, column in enumerate(columns):  # 遍历列名,idx下标用于转换Excel列索引
            # 列宽如有定义,使用定义数值,如无定义使用default
            width = width_dict[column] if column in width_dict.keys() else width_dict['default']
            if column in ['序号', '来源库', '发表时间', '年']:  # 这几列内容较短,居中显示
                worksheet.set_column(chr(65 + idx) + ':' + chr(65 + idx), width, text_center_format)  # chr将ASCII数值转换为字母列索引
            else:  # 其他左对齐
                worksheet.set_column(chr(65 + idx) + ':' + chr(65 + idx), width, text_format)
        
        worksheet.set_row(0, 18, header_format)  # 设置标题格式
        writer.save()  # 保存
        return df
    
    def process_word(df, filenamep):
        document = Document()
        document.styles['Normal'].font.size = Pt(12)  # 字体大小
        document.styles['Normal'].font.name = 'Times New Roman'  # 西文字体
        document.styles['Normal']._element.rPr.rFonts.set(qn('w:eastAsia'), '宋体')  # 中文字体
        document.styles['Normal'].paragraph_format.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY  # 两端对齐
        document.styles['Normal'].paragraph_format.line_spacing = 1.15  # 行距
        document.styles['Normal'].paragraph_format.space_before = Pt(3)  # 段前
        document.styles['Normal'].paragraph_format.space_after = Pt(3)  # 断后
        document.styles['Normal'].paragraph_format.first_line_indent = document.styles['Normal'].font.size * 2  # 首行缩进
        
        def add_heading_func(text, level, font_size, font_color=RGBColor(0, 0, 0), font_bold=True, line_spacing=1.15, first_line_indent=0, space_before=6, space_after=6, en_font='Times New Roman', cn_font='宋体'):
            # 增加标题函数,可能由于版本问题直接改样式不起作用,这里使用h、r2个变量来调整标题格式,分别是paragraph和run格式
            h = document.add_heading(level=level)
            r = h.add_run(text)
            r.font.size = Pt(font_size)  # 字体大小
            r.font.color.rgb = font_color  # 字体颜色
            r.font.bold = font_bold  # 加粗
            r.font.name = en_font  # 西文字体
            r._element.rPr.rFonts.set(qn('w:eastAsia'), cn_font)  # 中文字体
            
            if level == 0:  # 如果为大标题,居中,西文字体同中文字体
                h.paragraph_format.alignment = WD_ALIGN_PARAGRAPH.CENTER
                r.font.name = cn_font
            else:  # 其他标题两端对齐
                h.paragraph_format.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY
         
            h.paragraph_format.first_line_indent = r.font.size * first_line_indent  # 首行缩进
            h.paragraph_format.line_spacing = line_spacing  # 行距
            h.paragraph_format.space_before = Pt(space_before)  # 段前
            h.paragraph_format.space_after = Pt(space_after)  # 段后
         
        add_heading_func(filenamep, 0, 16, cn_font='微软雅黑')
         
        for i in df.loc[1:, ['序号', '来源库', '题名', '作者', '文献来源', '摘要', '年']].values:  # 循环遍历题录表格
            add_heading_func(str(i[0]) + '. '+ i[2] + '(' + re.sub(';$', '', i[3]) + ',' + (str(i[6]) if i[6] else '网络首发') + ')', 1, 12, font_color=RGBColor(0x4f, 0x81, 0xbd))
            document.add_paragraph('来源:' + i[4] + '('+ i[1] + ')')
            for j in i[5].split('\n'):
                document.add_paragraph(re.sub('^ *', '', j))
            document.add_paragraph()
         
        document.save(output_dir + '\\' + filenamep + '.docx')  # 保存文件
    
    if union:  # 如需合并为一个文件
        dfs = [pd.concat([read_file(filename) for filename in filenames])]  # 读入文件转为DataFrame并合并
        filenameps = ['合并题录_' + time.strftime('%Y%m%d_%H%M%S', time.localtime())]  # 输出文件名
    else:  # 单独文件
        dfs = [read_file(filename) for filename in filenames]  # 读入文件转为DataFrame
        filenameps = ['.'.join(filename.split('.')[:-1]) for filename in filenames]  # 输出文件名(去除后缀)
        
    for df, filenamep in zip(dfs, filenameps):  # 遍历待处理DataFrame和输出文件名
        df = process_excel(df, filenamep)  # 运行处理Excel函数
        process_word(df, filenamep)
        print(now(), filenamep, '处理完成')

input_dir = '知网题录文件'  # 输入文件夹
output_dir = '输出文件夹'  # 输出文件夹

if not os.path.exists(output_dir):  # 输出文件夹如不存在
    os.mkdir(output_dir)  # 创建

filenames = [filename for filename in os.listdir(input_dir) if filename.split('.')[-1] == 'xls']  # 筛选xls文件
cnki_processing(filenames, input_dir, output_dir, sort_by='发表时间', ascending=True, union=False)  # 执行
# cnki_processing函数参数列表:(filenames文件名,input_dir输入文件夹,output_dir输出文件夹,sort_by排序列,ascending正序True/倒序False,union是否合为一个文件)

五、使用方法

将知网导出的xls题录文件放入程序同目录的输入文件夹运行。

cnki_processing函数参数列表:(filenames文件名,input_dir输入文件夹,output_dir输出文件夹,sort_by排序列,ascending正序True/倒序False,union是否合为一个文件)

filenames由程序遍历输入文件夹得到,input_dir和output_dir在上方变量中设置;sort_by为排序列,留空不排序;ascending为排序方式(正序True/倒序False);union为True时将输入文件夹内所有xls文件合并为一个Excel和Word题录,为False时每个文件单独生成一个Excel和Word。

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Pluto_Ct

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值