知网导出的题录文件通常用于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。
EuphyTyplenkov: 博主您好,可以发一下数据集和代码吗?非常感谢! 邮箱:657272286@qq.com
weixin_48629974: 求数据和代码,2280409893@qq.com
2301_77179477: 求求分享数据集和代码,邮箱2840883821@qq.com 急急
危崖上的鱼: 收到啦,谢谢