美文网首页officePython
科研神器(1)——python实现自动读取英文文献翻译并生成综述

科研神器(1)——python实现自动读取英文文献翻译并生成综述

作者: 走错说爱你 | 来源:发表于2020-12-01 23:57 被阅读0次

    经常看到公众号推什么“学姐一年发五篇SCI,原来是靠它”之类的文章,点进去全是Python的安利,然而跟着广告进去也不一定能学会。正好时值学校要求写文献阅读报告,然而至少一万字的报告实在是让人望而却步,于是想到了自己使用Python去实现自动读取英文文献,并翻译生成综述(当然,只适用于凑字数的情况,如果需要写综述,还是建议自己总结归纳)。这里分享给大家,希望大家都能学废(不是)

    如果不想了解技术细节,只想直接拿来用,可以直接跳过代码编写部分,直达最后代码使用部分。

    本代码免费开源,已发布release,可在GitHub上进行下载
    ,如果你觉得好用,希望能够给我一个赞(能GitHub给一颗Star更好),也欢迎去github发表意见建议。

    代码实现效果如下:


    实现效果

    开发环境

    • Windows 10
    • Sublime Text 3
    • Python 3.7
    • Pdfminer、requests
    • 有道翻译API

    事前准备

    接口申请

    本代码使用了有道翻译的API,因此,如需使用,需要去有道翻译接口官方申请APP Key和Secret key,直接按照其官方教程申请即可,后续需要在代码中配置。接口申请完全免费,初始会送100元的面值,用完需要续费,不过一般情况100元可以用很久了。

    安装pdfminer和requests

    同时按下键盘win+R,在弹出的输入框内输入cmd按下回车,在弹出的黑框中进行下面操作。
    因为我使用的是python3,因此输入以下命令安装:

    pip install pdfminer3k
    pip install requests
    

    需求分析

    这里分析了本代码实现的关键点:

    • 文献是已经下载下来的pdf文件
    • 文献中,需要提取的部分主要为:
      • 标题
      • 作者
      • 摘要
      • 结论

    因此,本代码的思路是读取本地文件夹内的pdf文件,然后读取并识别出其关键元素,调用有道翻译的API进行翻译,并进行有机组合,写入TXT文件中。

    代码编写

    读取pdf文件

    依次读取文件夹内的文件,如果后缀为pdf,则写入文件元祖:

    def getFileName(filepath):
        file_list = []
        for root,dirs,files in os.walk(filepath):
            for filespath in files:
                if 'pdf' in filespath.split('.')[1]:
                    file_list.append(os.path.join(root,filespath))
        return file_list
    

    读取文件内容并提取标题、作者、摘要和结论

    def parse(DataIO, save_path, appKey, appSecret):
     
        #用文件对象创建一个PDF文档分析器
        parser = PDFParser(DataIO)
        #创建一个PDF文档
        doc = PDFDocument()
        #分析器和文档相互连接
        parser.set_document(doc)
        doc.set_parser(parser)
        #提供初始化密码,没有默认为空
        doc.initialize()
        #检查文档是否可以转成TXT,如果不可以就忽略
        if not doc.is_extractable:
            raise PDFTextExtractionNotAllowed
        else:
            #创建PDF资源管理器,来管理共享资源
            rsrcmagr = PDFResourceManager()
            #创建一个PDF设备对象
            laparams = LAParams()
            #将资源管理器和设备对象聚合
            device = PDFPageAggregator(rsrcmagr, laparams=laparams)
            #创建一个PDF解释器对象
            interpreter = PDFPageInterpreter(rsrcmagr, device)
            last_para = '' # 记录上一段文本
            count = 0 # 对文本块进行计数,方便后续查找标题和作者
            author = '' # 记录作者
            ab_count = 0 # 记录已识别的摘要的数量,避免提取文中的abstract
    
            fanyi = YouDaoFanyi(appKey, appSecret)
            #循环遍历列表,每次处理一个page内容
            #doc.get_pages()获取page列表
            for page in doc.get_pages():
                interpreter.process_page(page)
                #接收该页面的LTPage对象
                layout = device.get_result()
                #这里的layout是一个LTPage对象 里面存放着page解析出来的各种对象
                #一般包括LTTextBox,LTFigure,LTImage,LTTextBoxHorizontal等等一些对像
                #想要获取文本就得获取对象的text属性
                for x in layout:
                    try:
                        if(isinstance(x, LTTextBoxHorizontal)):
                            with open('%s' % (save_path), 'a', encoding='utf-8') as f:
                                result = x.get_text() # 每块的内容
                                # print(result)
                                # 提取标题
                                if count==0:
                                    # 如果是researchgate的文章,直接翻页
                                    if re.findall('^see discussions', result.lower())!=[]:
                                        break
                                    # 如果第一行是各种页眉等干扰信息,直接略过
                                    if re.findall('(^[0-9])|(^(research )?article)|(unclassified)|(www.)|(accepted (from|manuscript))|(proceedings of)|(vol.)|(volume \d)|(https?://)|(^ieee)|(sciencedirect)|(\d{4}\)$)|(\d{1,4} – \d{1,4}$)|(cid:)',re.split('\s+$',result.lower())[0])!=[] or '':
                                        count -= 1
                                    else:
                                        # 将结果写入TXT
                                        f.write('\n'+result.replace('\n', '')+'\n')
                                # 提取作者
                                elif count==1:
                                    # 只取第一作者
                                    author = result.split('\n')[0].split(',')[0].split(' and ')[0]
                                    author = generate_author(author)
                                    print('author '+ author)
                                # 去掉pdf文件读取的各种换行符
                                result = result.replace('\n', '')
                                try:
                                    # 转为小写,去掉空格,方便正则识别
                                    last_para = last_para.lower().replace(' ', '')
                                    # print(result)
                                    # 匹配Abstract和摘要内容分开的情况
                                    if re.findall('abstract$', last_para)!=[]:
                                        # 去掉关键词
                                        oringin_result = re.split('(K|k)(eyword|EYWORD)[sS]?',result)[0]
                                        # 翻译并转换人称
                                        trans_result = fanyi.translate(oringin_result).replace('我们', '他们')
                                        # print(result)
                                        # 组织语言写入TXT
                                        write_cont = author + '等人提出:' + trans_result + '\n'
                                        ab_count += 1
                                        f.write(write_cont)
                                    # 匹配Abstract和摘要内容位于同一行的情况
                                    elif re.findall('^abstract', result.lower().replace(' ', ''))!=[] and re.findall('abstract$', result.lower().replace(' ', ''))==[]:
                                        # 确保摘要只匹配一次,不匹配文中的Abstract字眼
                                        if ab_count==0:
                                            # 去掉Abstract字眼及其后续的符号
                                            oringin_result = re.sub('(a|A)(bstract|BSTRACT)[- —.]?','', result)
                                            # 去掉关键词
                                            oringin_result = re.split('(K|k)(eyword|EYWORD)[sS]?',oringin_result)[0]
                                            # 翻译并转换人称
                                            trans_result = fanyi.translate(oringin_result).replace('我们', '他们')
                                            # print(result)
                                            # 组织语言写入TXT
                                            write_cont = author + '等人提出:' + trans_result + '\n'
                                            ab_count += 1
                                            f.write(write_cont)
                                    # 匹配结论
                                    elif re.findall('(^(i|v|x|\d)*\.?conclusions?)|(conclusions?$)', last_para)!=[]:
                                            # 避免因图表在标题下方导致的识别错误
                                            if re.findall('^fig', result.lower()):
                                                continue
                                            # 翻译
                                            trans_result = fanyi.translate(result)
                                            # print(result)
                                            # 转换人称
                                            write_cont = trans_result.replace('我们', '他们') + '\n'
                                            # 写入TXT
                                            f.write(write_cont)
                                except Exception as e:
                                    print(e)
                                last_para = result
                                count += 1
                    except Exception as e:
                        print('out'+str(e))
                else:
                    continue
            with open('%s' % (save_path), 'a', encoding='utf-8') as f:
                f.write('\n')
    

    按照引用的格式生成作者信息

    def generate_author(author):
        # 过滤掉作者名后面的各种符号,并生成引用的格式
        # print(author)
        author = re.sub('by |[\s\d\*∗\/@†\(\&\)]+$', '', author)
        author_list = re.split('\s+',author)
        author_str = author_list[len(author_list)-1]
        for i in range(0,len(author_list)-1):
            author_str = author_str + ' ' + author_list[i][0]
        return author_str
    

    翻译接口

    其实直接抄有道官网文档就可以了,这里在其基础上做了更改:

    class YouDaoFanyi:
        def __init__(self, appKey, appSecret):
            self.YOUDAO_URL = 'https://openapi.youdao.com/api/'
            self.APP_KEY = appKey  # 应用id
            self.APP_SECRET = appSecret  # 应用密钥
            self.langFrom = 'en'   # 翻译前文字语言,auto为自动检查
            self.langTo = 'zh-CHS'     # 翻译后文字语言,auto为自动检查
            self.vocabId = "您的用户词表ID" #非必填项,可以不写
    
        def encrypt(self,signStr):
            hash_algorithm = hashlib.sha256()
            hash_algorithm.update(signStr.encode('utf-8'))
            return hash_algorithm.hexdigest()
    
    
        def truncate(self,q):
            if q is None:
                return None
            size = len(q)
            return q if size <= 20 else q[0:10] + str(size) + q[size - 10:size]
    
        def do_request(self,data):
            headers = {'Content-Type': 'application/x-www-form-urlencoded'}
            return requests.post(self.YOUDAO_URL, data=data, headers=headers)
    
    
        def translate(self,q):
            data = {}
            data['from'] = self.langFrom
            data['to'] = self.langTo
            data['signType'] = 'v3'
            curtime = str(int(time.time()))
            data['curtime'] = curtime
            salt = str(uuid.uuid1())
            signStr = self.APP_KEY + self.truncate(q) + salt + curtime + self.APP_SECRET
            sign = self.encrypt(signStr)
            data['appKey'] = self.APP_KEY
            data['q'] = q
            data['salt'] = salt
            data['sign'] = sign
            data['vocabId'] = self.vocabId
    
            response = self.do_request(data)
            contentType = response.headers['Content-Type']
            result = json.loads(response.content.decode('utf-8'))['translation'][0]
            print(result)
            return result
    

    最后,书写主函数进行调用:

    if __name__ == '__main__':
        #解析本地PDF文本,保存到本地TXT
        folder = '文件夹路径' # 需要读取pdf的文件夹的路径,注意为绝对路径,如:E:/论文
        write_txt_file = 'result.txt' # 保存结果的文件
        appKey = '应用ID'  # 应用id
        appSecret = '应用秘钥'  # 应用密钥
        success_count = 0 # 统计成功的次数
        fail_count = 0 #统计失败的次数
    
        # 单次调用,供开发测试
        # pdf_filename = folder+'文件名'
        # with open(pdf_filename,'rb') as pdf_html:
        #     try:
        #         parse(pdf_html, folder + write_txt_file, appKey, appSecret)
        #         success_count+=1
        #     except Exception as e:
        #         print(pdf_filename)
        #         fail_count+=1
    
        pdf_list = getFileName(folder)
        # 依次读取元祖,获取pdf文件位置
        for file_item in pdf_list:
            with open(file_item,'rb') as pdf_html:
                try:
                    print(file_item)
                    parse(pdf_html, folder + write_txt_file, appKey, appSecret)
                    success_count+=1
                except Exception as e:
                    # 文件读取或翻译失败则将错误信息写入TXT
                    print('文档读取失败:' + str(e) +',路径为:' + file_item)
                    with open('%s' % (folder + write_txt_file), 'a', encoding='utf-8') as f:
                        f.write('\n'+'文档读取失败:' + str(e) +',路径为:' + file_item + '\n')
                    fail_count+=1
    
        print('共读取pdf文件' + str(success_count+fail_count) + '个,其中成功读取并翻译' + str(success_count) + '个,失败' + str(fail_count) + '个')
    

    至此,代码编写完毕

    使用

    本工具已发布release,可在GitHub上进行下载,直接双击使用即可,后面的可以不用看了。

    也可下载源码使用,代码可在Github上下载

    配置代码

    更改代码主函数的配置变量(其中的应用ID和应用秘钥需要事先申请,见上文事前准备一节):

    if __name__ == '__main__':
        #解析本地PDF文本,保存到本地TXT
        folder = '文件夹路径' # 需要读取pdf的文件夹的路径,注意为绝对路径,如:E:/论文/
        write_txt_file = 'result.txt' # 保存结果的文件
        appKey = '应用ID'  # 应用id
        appSecret = '应用秘钥'  # 应用密钥
    

    运行代码

    运行代码之前,需要安装python3以及按照事前准备中的描述安装pdfminer和requests

    在代码所在的根目录下的命令行中输入以下命令即可:

    python pdfprocessor.py
    

    运行结果

    仅花了38秒的时间,就提取并翻译完成了14个pdf文件,翻译生成的字数合计6812个字:

    运行结果

    试了一下45个文件,花了大概两分钟,生成了一万多字

    最后看一下翻译结果对比:

    翻译结果中英对比

    相关文章

      网友评论

        本文标题:科研神器(1)——python实现自动读取英文文献翻译并生成综述

        本文链接:https://www.haomeiwen.com/subject/alpewktx.html