【python实战】获取英文文献pdf中参考文献信息

在看英文文献的时候,有时候想要这篇文献的参考文献的情况,比如,年份分布,作者情况等。

尤其是,当想通过一篇综述或者元分析文献来了解某个领域的情况的时候,根据该文献的参考文献的信息来了解也不失为一种方式。

一般下载的文献都是pdf格式,如果直接复制粘贴来进行整理的话,费时费力,毕竟调整格式、挑选信息都需要花费不少时间。

这时候,就想着能不能直接根据一篇文献pdf,自动获取其中的参考文献并进行整理。网上搜索半天也没有找到直接解决办法,就想着用python自己来试一试。

例如,某文献的参考文献(APA格式)如下所示:


get_paper2.png

最后,将参考文献逐条导出txt:

get_paper3.png

以及,逐条导出excel:

get_paper4.png

一、思路

整个过程用python实现的,适用于APA格式的参考文献。

思路主要是:

  1. 获取References下的参考文献的文本内容;
  2. 对文本内容解析成单条参考文献;
  3. 从每条参考文献中提取信息;
  4. 导出结果txt和excel;

二、过程

1. 获取References下的参考文献的文本内容

这部分主要涉及到用python来提取PDF的文本内容。

思路:

(1)提取References所在页面及之后页面的文本内容;

(2)从中提取参考文献的文本内容。

因为不少的期刊文献pdf是两栏排版(如上述例子所示)。

所以,花了一些时间,尝试了几种不同的包的提取效果。其中,

  • pdfplumber:pdf内容分栏的话,文本是横向提取出来的,这样的话,完全不知道哪条是哪条文献了……所以,不考虑。
pdfplumber.png
  • pdf2htmlEX:想着如果能把pdf转成html再解析会不会更方便些。所以,(1)安装pdf2htmlEX;(2)通过python调用pdf2htmlEX,把相应页面的pdf转为html;(3)再将html中的文字提取出来。结果:发现依然有个问题,文本是可以分栏提取出来,但是,文本被切得细碎,最重要的是换行没有换行符,这样也无法去分割提取信息。所以,也不考虑。
pdf2htmlEX.png
  • pdfminer:想尝试这个包提取效果,但是,始终出现错误:TypeError: __init__() missing 1 required positional argument: 'parser',研究了半天也不知道怎么解决,而且,代码和过程更复杂些,就没继续下去了。

  • pypdf2:以最后一页为例,如图所示,提取出来的文本没有空格!!!更不会考虑了,这咋提取信息……

pypdf2.png

就在快要失去信心的时候发现,PyMuPDF可以用!

import re
# PyMuPDF
import fitz
import pandas as pd

(1)获取参考文献开始及之后的页面

首先,根据关键词,即标题References(或者REFERENCES,有的居然还是referenCes)获取参考文献开始及之后的页面。

# 获取从references开始及之后的页面内容
def GetRefPages(pdfname):
    pdf=fitz.open(pdfname)
    pagenum=len(pdf)
    ref_list=[]
    for num,p in enumerate(pdf):
        content=p.getText('blocks')
        # print(num)
        for pc in content:
            # print(pc)
            txtblocks=list(pc[4:-2])
            txt=''.join(txtblocks)
            if 'References' in txt or 'REFERENCES' in txt or 'referenCes' in txt:
                refpagenum=[i for i in range(num,pagenum)]
                for rpn in refpagenum:
                    refpage=pdf[rpn]
                    refcontent=refpage.getText('blocks')
                    for n,refc in enumerate(refcontent):
                        txtblocks=list(refc[4:-2])
                        ref_list.extend(txtblocks)
    print(''.join(ref_list))
    return ref_list

结果如下图所示,获取了上述例子中那两页文献内容:

pymupdf1.png

(2)获取References后的文本内容

接着,就是将上述列表中,关键词,即标题References(或者REFERENCES,有的居然还是referenCes)之后的文本提取出来。

# 获取从references之后的文本内容
def GetRefTxt(ref_list):
    refnum=0
    for nref,ref in enumerate(ref_list):
        if 'References' in ref  or 'REFERENCES' in ref or 'referenCes' in ref:
            refnum=nref
    references_list=ref_list[refnum+1:]
    print(''.join(references_list))
    return references_list

结果如下,获取了所有的参考文献文本内容:

pymupdf2.png

2.对文本内容解析成单条参考文献

在获得了上述所有参考文献的文本内容之后,就需要提取出每条参考文献了。

思路主要是:

(1)将所有文本变成一个字符串;

(2)通过正则表达式拆分;

(3)合并成一条参考文献;

def GetUnitRef(references_list):
    # 去除一些不必要的字符
    references_list=[i.replace('\n',' ') for i in references_list]
    references_list=[re.sub(r'<.*>','',i) for i in references_list]

    # 将所有文本变成一个字符串
    references=' '.join(references_list).replace('- ','')
    references=re.sub(r'\([0-9]{1,3}\)','',references).replace('   ','')
    # print(references)

    # 根据 作者( 通过正则表达式进行拆分
    # 特殊:Taubman Ben-Ari, O.
    # 特殊:(in press)
    authorspattern=re.compile(r'([A-Za-z]+ ?[A-Za-z]* ?[A-Za-z]*-?[A-Za-z]*, [A-Z]\..*?\([0-9|a-zA-Z])')
    reflist=re.split(authorspattern,references)
    reflist=list(filter(None,reflist))
    # print(reflist)

    # 将参考文献导出(略有瑕疵)
    allref_list=[]
    # 拆分后每2个拼成1条文献,若遇到页眉,则跳过
    reflength=len(reflist)
    step=2
    for i in range(0,reflength,step):
        # 若遇到页眉则跳过(页眉的第2条没有.,等符号)
        if '.' in reflist[i+1] or '). ' in reflist[i+1]:
            unitref=reflist[i:i+step]
            unit=''.join(unitref)
            allref_list.append(unit)

    # 处理书籍参考文献(先前半段和后半段合并进入列表,再删除前半段)
    mid_list=[]
    for n,a in enumerate(allref_list):
        if 'Ed' in a and re.search(r'\([0-9]+\)',a)==None:
            mid_list.append(allref_list[n-1]+allref_list[n])
        else:
            mid_list.append(a)

    final_list=[]
    for num,i in enumerate(mid_list[:-1]):
        if i not in mid_list[num+1]:
            final_list.append(i)
    final_list.append(mid_list[-1])
    
    return final_list

(1)拼成一个字符串

这个比较好弄,结果如下:

pymupdf3.png

(2)根据正则表达式拆分

但是,通过正则表达式拆分和合并的过程,花了不少时间,尝试了几个不同的期刊文献,写出比较通用的表达r'([A-Za-z]+ ?[A-Za-z]* ?[A-Za-z]*-?[A-Za-z]*, [A-Z]\..*?\([0-9|a-zA-Z])',这里的正则表达式是适用于APA格式的。

根据作者(进行拆分后的结果:

for n,r in enumerate(reflist):
    print(n,r)
pymupdf4.png

(3)合并成一条参考文献

将每两条文献进行合并,如果遇到页眉就跳过,结果:

for n,r in enumerate(allref_list):
    print(n,r)
pymupdf5.png

至此,大部分工作就做完了,但是,有的时候,参考文献中还有书籍参考文献。
以另一篇文献中的某条参考文献为例:

Leary, M. R., & Guadagno, J. (2011). The role of hypo-egoic self processes in optimal functioning and subjective well-being. In K. Sheldon, T. B. Kashdan, & M. F. Steger (Eds.), Designing positive psychology: Taking stock and moving forward (pp. 135-146). New York, NY: Oxford University Press. doi:10.1093/acprof:oso/9780195373585.003 .0009

根据正则表达式会拆分成如下,因为Sheldon, T. B. Kashdan, & M. F. Steger (E也符合正则表达式要求。

Leary, M. R., & Guadagno, J. (2
011). The role of hypo-egoic self processes in optimal functioning and subjective well-being. In K. 
Sheldon, T. B. Kashdan, & M. F. Steger (E
ds.), Designing positive psychology: Taking stock and moving forward (pp. 135-146). New York, NY: Oxford University Press. doi:10.1093/acprof:oso/9780195373585.003 .0009  

所以,如果遇到这种情况,就做了些处理,这条文献就分来合并,然后,再将前半段加入到后半段,再删除前半段。最后得到结果:

for n,r in enumerate(final_list):
    print(n,r)
pymupdf6.png

3. 从每条参考文献中提取信息

有了每条参考文献,就可以根据正则表达式,拆分提取等方式提取作者、年份、标题、期刊、DOI等信息了。
虽然不是十分完美,但绝大部分还是没问题的。

def GetInfo(final_list):
    referencelist=[]
    authorlist,yearlist,titlelist,journallist=[],[],[],[]
    doilist=[]
    for f in final_list:
        # 全文
        referencelist.append(f)
        # print(f)
        # 作者
        try:
            author=re.findall(r'([A-Za-z]+ ?[A-Za-z]* ?[A-Za-z]*-?[A-Za-z]*, [A-Z]\..*?\()',f)[0].replace('(','')
        except:
            author='Null'
        authorlist.append(author)
        # print(len(author),author)

        # 年份
        try:
            year=re.findall(r'(\([0-9|a-z| ]+\))',f)[0].replace('(','').replace(')','')
        except:
            year='Null'
        yearlist.append(year)
        # print(len(year),year)

        # 标题
        try:
            title=f.split('). ')[1].replace('?','.').split('.')[0]
        except:
            title='Null'
        titlelist.append(title)
        # print(len(title),title)

        # 期刊
        try:
            # journal=f.split('). ')[1].split('.')[1].split(',')[0]
            journal=''.join(re.findall(r'.*?\)\. .*?[\.|?] (.*[,|.]?)',f)).split(',')[0]
        except:
            journal='Null'
        journallist.append(journal)
        # print(len(journal),journal)

        # DOI
        try:
            if 'doi.org' in f :
                DOI=f.split('org/')[1]
            elif 'doi:' in f:
                DOI=f.split('doi:')[1]
            else:
                DOI='Null'
        except:
            DOI='Null'
        doilist.append(DOI)
        # print('DOI:',DOI)

        # 转为数据框
        refdata={
        'Author':authorlist,
        'Year':yearlist,
        'Title':titlelist,
        'Journal':journallist,
        'DOI':doilist,
        'Reference':referencelist
        }
        refdata=pd.DataFrame(refdata)
    print(refdata)
    return refdata

结果如下:


pymupdf7.png

4.导出结果txt和excel

最后一步就很简单了,将提取出的每条参考文献文本导入txt,以及相关信息写入excel里。

最后就得到最开始例子的txt和excel内容啦~

# 将参考文献文本写入txt
def write2txt(path,filename,final_list):
    txtname=path+'\\'+'[Refs of]'+filename+'.txt'
    with open(txtname,"w",encoding='utf-8') as f:
        txtcontent='\n'.join(final_list)
        f.write('<<'+filename+'>>'+'\n'+txtcontent)

# 将参考文献信息写入excel
def refinfo2excel(path,filename,refdata):
    excelname=path+'\\'+'[Refs of]'+filename+'.xlsx'
    refdata.to_excel(excelname,index=0)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,390评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,821评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,632评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,170评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,033评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,098评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,511评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,204评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,479评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,572评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,341评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,893评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,171评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,486评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,676评论 2 335

推荐阅读更多精彩内容