python学习笔记

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

2021-01-18  本文已影响0人  Hobbit的理查德

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

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

一般下载的文献都是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.png pdf2htmlEX.png 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)
上一篇下一篇

猜你喜欢

热点阅读