这个学期如期开课了,虽然是在家里。这学期我导开了一门《高等教育管理专题研究》,一口气给了11个专题。为了对这11个专题的文献分布情况有一个粗略的印象,我觉得都得找相关的文献来看看,但是11个专题都要重新检索一遍,重复性工作让人头秃……于是,我写了个python脚本,自动生成各个主题的关键词和引文分布情况的报告,效果如下图。

用Python实现科研自动化_python

看到点击“运行”不到3秒钟就自动生成了6000字左右“像模像样”的报告,不禁流下激动的泪水。

用Python实现科研自动化_python_02

用Python实现科研自动化_python_03

要是有一天能写个程序能将我的想法整理成论文就好了[狗头]。为了留存这个美好的幻想,我把报告生成的思路记录下来,权当为以后积累点技术基础。编程思路包括:提取PDF内容、CSSCI文献题录数据的格式处理、关键词词频计算、引文数据统计、关键词共被引网络生成、word的自动编写与插入(包括样式、表格等)。

一、报告结构的拟定

写报告的思路比较固定,我个人的体会是:叙述要求、描述数据和展示结果。那么每个一级标题下,先附上老师的要求,然后描述数据在哪里下载的,最后将结果数据的图表展示出来。按照这个思路走下来了,将每个部分的模板编写为如下这样。

用Python实现科研自动化_python_04

确定了报告框架之后,下面的事情便变得简单,把内容填上去,在写个循环语句,报告就完成了,下面说的都是如何填空的事情。

二、PDF内容提取

我导给了一个PDF,需要把PDF的一级标题和二级标题的内容提取出来,填充themeName和themeKeyword部分。

用Python实现科研自动化_python_05

在python中,提取PDF内容的包有pdfminer、tabula、pdfplumber等(引自:Python:解析PDF文本及表格——pdfminer、tabula、pdfplumber 的用法及对比[1]),都大同小异。经过对比选择了pdfplumber,没安装的话需要先安装一下。

  •  
pip install pdfplumber

主要代码如下。

  •  
pdfPath = 'Auto_data/course_text/2019-2020春季学期《高等教育管理专题研究》拟研究专题.pdf'pdf = pdfplumber.open(pdfPath)for p in pdf.pages:    test = p.extract_text().split('\n')

通过上述代码就可以提取PDF的所有内容。但是想要正确提取内容还有其他的工作,使用正则表达式根据标题的特点提取一级和二级标题内容、编程将全角标点变成半角标点、去掉标题中的中文和英文标点等、将一级标题和二级标题内容建立对应关系等。非主干代码占了所有代码量的80%以上,真特么的符合“二八法则”。

三、文献题录数据下载与提取

在一个主题词下载之前,先确定该主题的文献检索方式。把下图的检索方式使用代码进行整理,便可以得到searchWord和searchWay。

用Python实现科研自动化_python_06

  •  
themeKeyword = '、'.join(themes_keypoints[ii])searchWord, searchWay = search_type(ii, searchWord_group)
def wordM(word): word = "“" + word + "”" return word
def search_type(i, searchWord_group): word_group = searchWord_group[i] slen = len(word_group) if (slen > 1): endLen = slen - 1 searchWay = ',检索方式为:'+ word_group[endLen] searchWord = '、'.join(word_group[:endLen]) else: searchWord = word_group[0] searchWay = '' return searchWord, searchWay

随后,在CSSCI官网,下载文献题录数据。

用Python实现科研自动化_python_07

下载下来的数据是这样的。

用Python实现科研自动化_python_08

对了,原来以为有数据规模会很大(并不大),所以使用如下代码生成了一个Windows批处理文件,可以达到一键生成文件夹目录的效果。

  •  
file_name = 'Auto_data/lite_data/themes_list.bat'with open(file_name, "w") as f:    index = 0    for i in range(len(themes_group)):        index = int(index) + 1        if index < 10: # 记得加0,不然不按顺序            index = '0' + str(index)        else:            index = str(index)        contant = 'md '+ index + '_' + themes_group[i] + ' '        f.writelines(contant)        f.writelines('\n')

用Python实现科研自动化_python_09

在下载得到数据后,需要对数据信息进行提取,提取的信息包括:标题、第一作者、关键词、发表时间、参考文献。标识符如下。

  •  
matching_columns = ['【来源篇名】','【第一作者】','【关 键 词】','【年代卷期】','【参考文献】']separator = '-----------------------------------------------------------------------'

使用正则表达式匹配相关信息,使用.replace函数去掉标识符,再进行其他操作,将信息放入字典中,便完成了信息提取工作。核心代码如下:

  •  
for i in range(len(matching_columns)):    m = matching_columns[i]    isMatching = re.match(m, curData) #把标题、作者等信息放入字典中    if isMatching:        if (i == 0):            data_dict['article'] = curData.replace(m,'')        elif (i == 1):            data_dict['author'] = curData.replace(m,'')        elif (i == 2):            data_dict['keyword'] = curData.replace(m,'')        elif (i == 3):            data_dict['year'] = curData.replace(m,'').split(',')[0]        elif (i == 4):            isReference = 1isSeparator = re.match(separator, curData)

在完成信息提取之后,生成了这一个主题的题录信息字典data_dict,通过len(data_dict)可以知道这一个主题一共有多少条文献题录数据。

  •  
searchNum = len(data_dict)

四、关键词与引文数据统计

关键词的词频计算使用的是类似Excel的数据透视表的方法写成的,这一点在《如何用python表白》一文中已经讲到,计算函数如下。其中,words_count.head(10)是输出到word中的排名前10的关键词,len(set(all_words))是关键词的数量,对应word中的词频分布表和关键词个数keywordNum。

  •  
def all_words(df):    all_words = []    for w in df['keyword']:        w_group = w.split('/')        all_words.extend(w_group)    print('关键词次数:',len(all_words))    print('关键词个数:',len(set(all_words))) #使用set方法    print('\n')
df_word = pd.DataFrame({'word': all_words}) words_count = df_word.groupby(by=['word'])['word'].count() words_count = words_count.to_frame() words_count.columns = ['count'] words_count = words_count.sort_values(by='count', ascending=False) print(words_count.head(10)) return all_words, words_count, len(set(all_words))

引文数据的提取编程思路类似, references_count.head(10)是输出到word中的被引量排名前10的参考文献。

  •  
def all_references(df):    all_references = []    for r in df['reference']:        r_group = r.split('/')        all_references.extend(r_group)    print('\n')    print('引用文献次数:',len(all_references))    print('引用文献篇数:',len(set(all_references))) #使用set方法
df_references = pd.DataFrame({'reference': all_references}) references_count = df_references.groupby(by=['reference'])['reference'].count() references_count = references_count.to_frame() references_count.columns = ['count'] references_count = references_count.sort_values(by='count', ascending=False)
for index in list(references_count.index): if not isRef(index): references_count.drop(index)
print(references_count.head(10)) return references_count

五、关键词共现网络的生成

由于需要分析,关键词共现网络以截图的方式放入报告中,有一些结果还是很好的,可以说很好看了,比如下面这张,很容易给像我这样的博士研究生以思考的启发,比如可以这么说:“创新创业教育的生长,根基在于创新创业活动的开展,课程体系是连接两者的关键因素。此外,创新创业教育还涉及教学改革、教学组织模式、高校人才培养、教学策略的运用等多方面的内容……”

用Python实现科研自动化_python_10

其他的也有好看的,比如“产教融合”的图,中心词、核心词和外围词都十分完整,十分便于分析。

用Python实现科研自动化_python_11

六、word的自动编写

当我们所有的内容都准备好之后,就可以考虑word的自动生成了。我使用的模块是python-docx,没安装的话需要事先安装一下。

  •  
pip install python-docx

安装完成后,导入自己已经调好样式的空白word页面。

  •  
document = Document('Auto_data/result/input.docx')

先将我们的内容以字符串的形式存储在几个变量中。

  •  
first_para = '专题下的思考方向包括:'+ themeKeyword + '。'second_para = '使用CSSCI进行检索,检索词为:'+ str(searchWord) + str(searchWay) + '。共下载文献题录数据' + str(searchNum) + '条,所有文献一共涉及关键词' + str(keywordNum) + '个,词频分布如下。'third_para = '关键词共现网络如下。'fourth_para = '被引用次数排名前10的文献如下。'

使用document.add_paragraph方法就可以将我们的内容以段落的形式插入word中,style可以选择样式,例如'Heading 2'是指二级标题样式,'Normal'是指正文样式。

  •  
t1 = document.add_paragraph(themeName, style = 'Heading 2')p1 = document.add_paragraph(first_para, style = 'Normal')p2 = document.add_paragraph(second_para, style = 'Normal')

表格的插入比较麻烦。先使用document.add_table生成题头。然后使用.add_row().cells方法增加行,使用for循环进行对表格单元格进行赋值,完成表格的生成。

  •  
table1 = document.add_table(rows=1, cols=4, style='网格型1')hdr_cells = table1.rows[0].cellshdr_cells[0].text = '关键词'hdr_cells[1].text = '词频'hdr_cells[2].text = '关键词'hdr_cells[3].text = '词频'table_size = int(maxKeyword/2)for i in range(table_size):    another_i = i + table_size    row_cells = table1.add_row().cells    row_cells[0].text = t1_data.index[i]    row_cells[1].text = str(t1_data['count'][i])    row_cells[2].text = t1_data.index[another_i]    row_cells[3].text = str(t1_data['count'][another_i])

之后,使用for循环,将11个专题的内容都放入word中,使用document.save保存word,这样,我们6000字的报告就生成啦!

  •  
document.save('Auto_data/result/11个专题下的文献计量分析.docx')

写在后面

在思考编程过程的时候,觉得这并不是什么难事,下载数据、提取信息、生成word就完事了。

用Python实现科研自动化_python_12

但是……想法一时爽,编程编断手,虽然报告的生成仅仅需要不到3秒钟,但是累计编程时间超过9个小时,中间涉及正则表达式、字符的unicode编码等新知识点,以及许多大大小小的bug,太占用专业学习的时间。这种报告只是信息的简单叠加,并不具备自主分析的效果,论文还是得自己写[微笑]。能实现一个想法总还是一件开心的事情,程序最大的特点就是复用性,以后就当做写文献综述前的预处理流程吧。大家如果对报告或者源码感兴趣,欢迎在后台留言与我交流哇!

用Python实现科研自动化_python_13