序言
做这个的背景是研究生导师要批量处理新三板文本数据,提取出一些自定义的关键词的词频
代码能够运行,但效率不一定最优(我的配置能够实现2.5s一份),需要安装指定的第三方模块(jieba、pdfminer等)
在我电脑里可以运行,里面涉及到一些路径(rename里的path)和参数(全局变量里的自定义词语和文件数量)需要自己去阅读和调整,如果按照文章内容还是不能运行的话,可以评论个邮箱,我打包代码和数据发给你
函数模块介绍
具体的代码可见全部代码部分,这部分只介绍思路和相应的函数模块
获取文件夹下的所有文件名称
#获取文件夹下的所有文件名称
def oslist(dealPdf):
file_name=list()
for i in os.listdir(dealPdf):
data_collect= ''.join(i)
file_name.append(data_collect)
return file_name
将PDF转化为txt,并删除换行符
PDF是无法直接进行文本分析的,所以需要将文字转成txt文件(PDF中图内的文字无法提取),因为PDF导出的txt会用换行符换行,为了避免词语因此拆开,所以删除所有的换行符
#将pdf文件转化成txt文件,并删除换行符
def pdf_to_txt(dealPdf,name):
# 不显示warning
logging.propagate = False
logging.getLogger().setLevel(logging.ERROR)
pdf_filename = dealPdf
device = PDFPageAggregator(PDFResourceManager(), laparams=LAParams())
interpreter = PDFPageInterpreter(PDFResourceManager(), device)
parser = PDFParser(open(pdf_filename, 'rb'))
doc = PDFDocument(parser)
dealTxt='TXT\\saler\\'#保存txt文件的地址
txt_filename=dealTxt+name+'.txt'
# 检测文档是否提供txt转换,不提供就忽略
if not doc.is_extractable:
raise PDFTextExtractionNotAllowed
else:
with open(txt_filename, 'w', encoding="utf-8") as fw:
for i,page in enumerate(PDFPage.create_pages(doc)):
interpreter.process_page(page)
# 接受该页面的LTPage对象
layout = device.get_result()
# 这里layout是一个LTPage对象 里面存放着 这个page解析出的各种对象
for x in layout:
if isinstance(x, LTTextBoxHorizontal):
results = x.get_text()
results=results.replace(' ','').replace('\n','')
fw.write(results)
添加自定义词语
此处可以根据自己的需要自定义,传入的wordsByMyself是全局变量
def word_by_myself():
for i in range(len(wordsByMyself)):
jieba.add_word(wordsByMyself[i])
分词与词频统计
调用jieba进行分词,读取通用词表去掉停用词(此步其实可以省略,对最终结果影响不大),将词语和出现次数合成为键值对,输出关键词出现次数
#分词并进行词频统计
def cut_and_count(outPutTxt):
with open(outPutTxt,encoding='utf-8') as f:
#step1:读取文档并调用jieba分词
text=f.read()
words=jieba.lcut(text)
#step2:读取停用词表,去停用词
stopwords = {}.fromkeys([ line.rstrip() for line in open('stopwords.txt',encoding='utf-8') ])
finalwords = []
for word in words:
if word not in stopwords:
if (word != "。" and word != ",") :
finalwords.append(word)
#step3:统计特定关键词的出现次数
valuelist=[0]*len(wordsByMyself)
counts=dict(zip(wordsByMyself,valuelist))
for word in finalwords:
if len(word) == 1:#单个词不计算在内
continue
else:
counts[word]=counts.get(word,0)+1#遍历所有词语,每出现一次其对应值加1
for i in range(len(wordsByMyself)):
if wordsByMyself[i] in counts:
print(wordsByMyself[i]+':'+str(counts[wordsByMyself[i]]))
else:
print(wordsByMyself[i]+':0')
主函数
通过for循环进行批量操作
if __name__ == "__main__":
dealPdf='PDF\\saler'#保存pdf文件的地址
file_name=oslist(dealPdf)
df=pd.DataFrame(columns=wordsByMyself,index=range(1,fileNum+1))
# 该程序支持中断,如数据量较大,中断后将range的第一个参数改完当前i的取值即可
for i in range(0,len(file_name)):
pdf_to_txt(dealPdf+'\\'+file_name[i],file_name[i][:-4])#将pdf文件转化成txt文件,传入文件路径
print(str(i)+'完成转换')
for i in range(0,len(file_name)):
word_by_myself()#添加自定义词语
print(f'----------result {i}----------')
cut_and_count('TXT\\saler\\'+file_name[i][:-4]+'.txt',df,i)#分词并进行词频统计,传入文件路径
本地文件结构
全部代码
import jieba
import jieba.analyse
import pandas as pd
from pdfminer.pdfparser import PDFParser
from pdfminer.pdfdocument import PDFDocument
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.converter import PDFPageAggregator
from pdfminer.layout import LTTextBoxHorizontal, LAParams
from pdfminer.pdfpage import PDFPage,PDFTextExtractionNotAllowed
import logging
import os
'''
该代码运行前需要调整三个变量,即:
自定义的关键词wordsByMyself
保存年报pdf的地址dealPdf
保存拆分后的txt的地址dealTxt
若年报数据量较少,调整好以上变量后即可一次性运行完成,结果将保存到该文件同级目录下
若年报数据量较大,该程序支持中断,中断后将主程序中的range()的第一个参数改完当前i加1后的取值即可
'''
wordsByMyself=['社会责任','援助','捐赠','扶贫','乡村','供应商','技术','创新'] #自定义词语,全局变量
#获取文件夹下的所有文件名称
def oslist(dealPdf):
file_name=list()
for i in os.listdir(dealPdf):
data_collect= ''.join(i)
file_name.append(data_collect)
return file_name
#将pdf文件转化成txt文件,并删除换行符
def pdf_to_txt(dealPdf,name):
# 不显示warning
logging.propagate = False
logging.getLogger().setLevel(logging.ERROR)
pdf_filename = dealPdf
device = PDFPageAggregator(PDFResourceManager(), laparams=LAParams())
interpreter = PDFPageInterpreter(PDFResourceManager(), device)
parser = PDFParser(open(pdf_filename, 'rb'))
doc = PDFDocument(parser)
dealTxt='TXT\\saler\\'#保存txt文件的地址
txt_filename=dealTxt+name+'.txt'
# 检测文档是否提供txt转换,不提供就忽略
if not doc.is_extractable:
raise PDFTextExtractionNotAllowed
else:
with open(txt_filename, 'w', encoding="utf-8") as fw:
for i,page in enumerate(PDFPage.create_pages(doc)):
interpreter.process_page(page)
# 接受该页面的LTPage对象
layout = device.get_result()
# 这里layout是一个LTPage对象 里面存放着 这个page解析出的各种对象
for x in layout:
if isinstance(x, LTTextBoxHorizontal):
results = x.get_text()
results=results.replace(' ','').replace('\n','')
fw.write(results)
#添加自定义词语
def word_by_myself():
for i in range(len(wordsByMyself)):
jieba.add_word(wordsByMyself[i])
#分词并进行词频统计
def cut_and_count(outPutTxt,df,fileNo):
with open(outPutTxt,encoding='utf-8') as f:
#step1:读取文档并调用jieba分词
text=f.read()
words=jieba.lcut(text)
#step2:读取停用词表,去停用词
stopwords = {}.fromkeys([ line.rstrip() for line in open('stopwords.txt',encoding='utf-8') ])
finalwords = []
for word in words:
if word not in stopwords:
if (word != "。" and word != ",") :
finalwords.append(word)
#step3:统计特定关键词的出现次数
valuelist=[0]*len(wordsByMyself)
counts=dict(zip(wordsByMyself,valuelist))
for word in finalwords:
if len(word) == 1:#单个词不计算在内
continue
else:
counts[word]=counts.get(word,0)+1#遍历所有词语,每出现一次其对应值加1
for i in range(len(wordsByMyself)):
if wordsByMyself[i] in counts:
print(wordsByMyself[i]+':'+str(counts[wordsByMyself[i]]))
df[wordsByMyself[i]][fileNo]=counts[wordsByMyself[i]]
else:
print(wordsByMyself[i]+':0')
df[wordsByMyself[i]][fileNo]=0
df.to_csv('result.csv',sep=',')
#主函数
if __name__ == "__main__":
dealPdf='PDF\\saler'#保存pdf文件的地址
file_name=oslist(dealPdf)
#df=pd.DataFrame(columns=wordsByMyself,index=range(1,fileNum+1))
# 该程序支持中断,如数据量较大,中断后将range的第一个参数改完当前i的取值即可
for i in range(1239,len(file_name)):
pdf_to_txt(dealPdf+'\\'+file_name[i],file_name[i][:-4])#将pdf文件转化成txt文件,传入文件路径
print(str(i)+'完成转换')
for i in range(1,fileNum+1):
word_by_myself()#添加自定义词语
print(f'----------result {i}----------')
cut_and_count('outPutTxt\\'+str(i)+'.txt',df,i)#分词并进行词频统计,传入文件路径