Python3自然语言处理——处理原始文本


文本的最重要来源无疑是网络。探索现成的文本集合很方便,但是每个人都有自己的文本来源,我们需要学习如何访问它们。


1.在Python中读取PDF文件

要从Python中访问PDF文件,首先需要安装PyPDF2库:

pip install pypdf2

创建一个新的Python文件,命名为pdf.py并添加以下代码:

from PyPDF2 import PdfFileReaderdef getTextPDF(pdfFileName,password=''):  pdf_file=open(pdfFileName,'rb')  read_pdf=PdfFileReader(pdf_file)  if password!='':    read_pdf.decrypt(password)  text=[]  for i in range(0,read_pdf.getNumPages()-1):    text.append(read_pdf.getPage(i).extractText())  return '\n'.join(text)

第1代码会导入PyPDF2库中的PdfFileReader类。然后创建一个可以读取一个PDF文件并返回其全文的函数,该函数需要两个参数,一个是你要读取的PDF文件路径,一个是这个PDF文件的密码(如果有的话),password参数是可选的。第3行代码会以读取和反向查找模式打开文件,本质是一个Python文件打开命令/函数,仅能打开非文本的二进制文件。以反向查找模式打开文件很重要,因为当加载文件内容时,PyPDF2模块试图从尾部开始读取文件内容。第4行将打开的文件传递给PdfFileReader类,用于处理PDF文档。如果文件设置了密码保护,就要解密被密码保护的PDF文件,当然,如果在函数调用时设置了密码,那么我们在解密这个文件时也同样需要密码。从第7行开始从PDF文件中读取文本,创建一个字符串列表,并将每一页的文本都添加到这个列表中。第10行为返回最终的输出结果,将列表中所有的字符串都连接起来,并且在每个字符串之间都加一个换行符,返回连接后的单一字符串。

在pdf.py目录下创建另一个名为test.py的文件,在test.py中添加如下代码:

import pdfpdfFile=r'C:\Users\Administrator\Desktop\examples\pdf2.pdf'print('PDF1:\n',pdf.getTextPDF(pdfFile))

pdfFile的路径是我的文件存储路径,读者可以根据自己的情况调整。上面的例子中我们打印输出的是一个未加密的PDF文档,如果加密的话格式如下(假定密码为123456):

import pdfpdfFile=r'C:\Users\Administrator\Desktop\examples\pdf2.pdf'print('PDF1:\n',pdf.getTextPDF(pdfFile,'123456'))


2.在Python中读取Word文件

我们将从python docx库中导入docx对象。在命令行中执行下面的命令将安装这个库:

创建一个新的Python文件,命名为word.py并添加以下代码:

import docxdef getTextWord(wordFileName):    doc=docx.Document(wordFileName)    fullText=[]    for para in doc.paragraphs:        fullText.append(para.text)    return '\n'.join(fullText)

第1行导入python-docx模块的docx对象。第2行定义getTextWord函数:该函数需要一个字符串参数wordFileName,包含你要读取的Word文件的绝对路径。doc对象加载了你要读取的Word文件,我们要从已经加载文档的doc对象中读取文本,首先初始化一个字符串列表fullText,然后采用for循环逐段从文档中读取文本,并把每段都放到fullText列表中去,然后我们将所有的片段/段落连接为一个字符串对象,并将其作为函数的输出结果返回。通过以上操作,我们将fullText数组的所有元素用“\n”分隔符连接起来,并返回连接后的对象。最后保存该Python文件并退出。

创建另一个Python文件,命名为wordtest.py,并添加以下代码:

import docximport worddocName=r'C:\Users\Administrator\Desktop\examples\word1.docx'print('Document in full:\n',word.getTextWord(docName))doc=docx.Document(docName)print('Number of paragraphs:',len(doc.paragraphs))print('Paragraph 1:',doc.paragraphs[0].text)print('Paragraph 1:',doc.paragraphs[0].style)print('Number of runs in paragraph 1:',len(doc.paragraphs[0].runs))for idx,run in enumerate(doc.paragraphs[0].runs):  print('Run %s:%s'%(idx,run.text))print('is Run 3 underlined:',doc.paragraphs[0].runs[3].underline)print('is Run 1 bold:',doc.paragraphs[0].runs[1].bold)print('is Run 5 italic:',doc.paragraphs[0].runs[5].italic)

第1、2行为导入docx库以及我们之前实现的word.py文件。第3、4行读取一个DOCX文件并使用我们在word.py中实现的API打印输出它的全部内容。Word/DOCX文档是一个更加丰富的信息来源,除了提供文本内容外,还能提供很多信息。第6行代码打印出了给定文档中段落的数量。第7行打印出了文档中第1段的内容,而第8行将会打印出第1段的样式。从第9行开始我们将了解什么是run对象。每个段落用多个run对象表示段落内格式的变化,这里的格式包含有字体、尺寸、颜色和其他样式元素(如粗体、斜体、下划线等等)。这些元素每次发生变化时,都会创建一个新的run对象。首先我们获得第一段中run对象的数目,然后我们把每个run对象打印输出。本次提取的word1.docx是一个带有一些粗体文本、一些斜体文本和一些下划线文本的文档,为了明确每个run对象的格式,12-14行分别检查了相应run对象的下划线样式、粗体样式以及斜体样式。最终输出如下:

Document in full: The newly-coined word "online education" may by no means sound strange to most people.During the past several years, hundreds of online education colleges have sprung up around China.Number of paragraphs: 2Paragraph 1: The newly-coined word "online education" may by no means sound strange to most people.Paragraph 1: _ParagraphStyle('Normal') id: 2606148545792Number of runs in paragraph 1: 9Run 0:The Run 1:newly-coinedRun 2: word "Run 3:online educationRun 4:" may Run 5:by no means Run 6:sound strange toRun 7: most peopleRun 8:.is Run 3 underlined: Trueis Run 1 bold: Trueis Run 5 italic: True


3.创建自定义语料库

现在我们要创建自己的语料库,而不是使用从互联网上得到的语料库。这一部分在之前有介绍过,但是这一次将更加深入。创建一个新的Python文件,命名为createCorpus.py并添加以下代码:

import osimport word,pdffrom nltk.corpus.reader.plaintext import PlaintextCorpusReader
def getText(txtFileName): file=open(txtFileName,'r') return file.read()
newCorpusDir='mycorpus/'if not os.path.isdir(newCorpusDir): os.mkdir(newCorpusDir)
txt1=getText(r'C:\Users\Administrator\Desktop\examples\1.txt')txt2=pdf.getTextPDF(r'C:\Users\Administrator\Desktop\examples\pdf1.pdf')txt3=word.getTextWord(r'C:\Users\Administrator\Desktop\examples\word1.docx')
files=[txt1,txt2,txt3]for idx,f in enumerate(files): with open(newCorpusDir+str(idx)+'.txt','w') as fout: fout.write(f)
newCorpus=PlaintextCorpusReader(newCorpusDir,'.*')
print(newCorpus.words())print(newCorpus.sents(newCorpus.fileids()[1]))print(newCorpus.paras(newCorpus.fileids()[0]))

我们导入os库用于与文件有关的操作,word库和pdf库是本章前两节完成的库,最后导入的PlaintextCorpusReader是为了完成语料库建立这一最终目标。代码第5行编写一个简单的函数,用来打开并读取一个纯文本文件,并将其全部内容作为string对象返回。9-11行在磁盘或文件系统中创建一个新文件夹corpus。13-15行逐个读取前面提到的三个文件并写到磁盘文件中。首先从纯文本文件开始,调用之前完成的getText函数,它将读取txt文件并将输出结果存入名为txt1的字符串对象中。然后使用PDF.py模块的getTextPDF()函数读取pdf文件并将文件内容存入名为txt2的字符串对象中。左后使用word.py模块的getTextWord()函数读取docx文件并将文件内容存入名为txt3的字符串对象中。17-20行将上面读到的三个字符串对象写到磁盘文件中。先创建一个包含以上三个字符串对象的数组,然后使用for循环来遍历files数组,再以只写模式打开一个新文件(采用w选项调用open函数),最后将当前字符串内容写到文件中。第22行在mycorpus目录下新建一个PlainTextCorpus对象它在内部做了很多的文本处理,如识别段落、句子、单词等等。该函数的两个参数分别是语料库目录的路径以及要处理的文件名模式。通过以上步骤,我们就创建了一个用户自定义的语料库。接下来,我们用24-26行来测试PlainTextCorpusReader是否加载正常。24行将打印输出语料库包含的所有单词数组(部分),25行将打印输出文件1.txt中的句子,26行将打印输出文件0.txt中的段落。

提示:在18-20行的for循环中,提取PDF文本内容时,可能由于编码问题报错:

UnicodeEncodeError: 'gbk' codec can't encode character '\u2122' in position 219: illegal multibyte sequence

如果出现这种情况,可以改变目标文件的编码,加上encoding='utf-8',即:

for idx,f in enumerate(files):    with open(newCorpusDir+str(idx)+'.txt','w',encoding='utf-8') as fout:        fout.write(f)

这样就可以正常运行。

本文由“公众号文章抓取器”生成,请忽略上文所有联系方式或指引式信息。有问题可以联系:五人工作室,官网:www.Wuren.Work,QQ微信同号1976.424.585