如何优化(也是 RAM 明智的)将单词从 PDF 保存到 Python 对象然后保存到数据库中的代码?
How to optimize (also RAM wise) code that is saving words from PDF to Python object and later into database?
我正在寻找将文本从 PDF 文件保存到我的数据库中的最有效方法。目前我正在使用 pdfplumber,标准代码如下所示:
my_string = ''
with pdfplumber.open(text_file_path) as pdf:
for page in pdf.pages:
if page.extract_text():
my_string += str(page.extract_text().replace('\n', ' ').split(' '))
但目前的代码是文学性的杀死我的机器(600 页的 PDF 需要大约 3 到 6 GB 的内存),我的目标是在手机上实际托管它。
我做了一些测试,阅读PDF似乎没有问题,但是保存或存储这些文字是有问题的。我尝试创建字典,其中每个页面字符串都是一个 key/value,但并没有好多少。
也许我应该尝试将每个页面生成到 txt 文件中,然后从该 txt 文件中读取字符串?
如有任何提示,我将不胜感激,谢谢!
编辑:
with pdfplumber.open(text_file_path) as pdf:
for page in pdf.pages:
connection = sqlite3.connect('my_db.db')
cursor = connection.cursor()
cursor.execute("INSERT INTO temp_text VALUES (?, ?)",
(text_file_path, str(page.extract_text()).replace('\n', ' ')))
connection.commit()
connection.close()
我更改了代码,它稍微好一点,(现在它占用大约 2.9 GB 的 RAM)但它仍然很多。我还能做些什么吗?
问题是您要长期存储数据,这意味着随着您逐渐处理越来越多的数据,您仍然在内存中引用它们。这就是数据库旨在防止的:所有高效的数据存储和检索,而无需将其全部存储在 RAM 中。下面是一个使用 PyMongo 的简单示例(对于 iOS 应用程序,您可能会想要使用 SQLite):
import pdfplumbder
import poymongo
import os
def process_file(path, collection):
'''Process a single file, from a path.'''
basename = os.path.splitext(os.path.basename(path))[0]
with pdfplumber.open(path) as pdf:
for index, page in enumerate(pdf.pages):
# Don't store any long-term references to the data
text = page.extract_text()
data = { 'text': text, 'filename': basename, 'page': index }
collection.insert_one(data)
def main(paths):
'''Just a dummy entry point, pass args normally here.'''
client = pymongo.MongoClient('localhost', 27017)
database = client['myapp']
collection = database['pdfs']
# Sort by filename, then by page.
collection.create_index([('filename', 1), ('page', 1)])
for path in paths:
process_file(path, collection)
# Do what you want here
如您所见,我们创建了到本地客户端的连接,创建或访问我们正在使用的数据库,并创建了一个用于 PDF 存储的集合。然后我们按文件名索引,然后是页码。
然后我们遍历所有路径,并迭代处理它们。我们不会一次存储超过一页的文本,并且每次循环都将数据写入数据库。就性能而言,这可能不是最佳选择(尽管引擎可能会对此进行适当优化),但它会最大限度地减少所需的内存。
避免使用处理数 GB 数据的全局状态:您迫使 Python 在不需要时保留对所有数据的引用。
我正在寻找将文本从 PDF 文件保存到我的数据库中的最有效方法。目前我正在使用 pdfplumber,标准代码如下所示:
my_string = ''
with pdfplumber.open(text_file_path) as pdf:
for page in pdf.pages:
if page.extract_text():
my_string += str(page.extract_text().replace('\n', ' ').split(' '))
但目前的代码是文学性的杀死我的机器(600 页的 PDF 需要大约 3 到 6 GB 的内存),我的目标是在手机上实际托管它。
我做了一些测试,阅读PDF似乎没有问题,但是保存或存储这些文字是有问题的。我尝试创建字典,其中每个页面字符串都是一个 key/value,但并没有好多少。
也许我应该尝试将每个页面生成到 txt 文件中,然后从该 txt 文件中读取字符串?
如有任何提示,我将不胜感激,谢谢!
编辑:
with pdfplumber.open(text_file_path) as pdf:
for page in pdf.pages:
connection = sqlite3.connect('my_db.db')
cursor = connection.cursor()
cursor.execute("INSERT INTO temp_text VALUES (?, ?)",
(text_file_path, str(page.extract_text()).replace('\n', ' ')))
connection.commit()
connection.close()
我更改了代码,它稍微好一点,(现在它占用大约 2.9 GB 的 RAM)但它仍然很多。我还能做些什么吗?
问题是您要长期存储数据,这意味着随着您逐渐处理越来越多的数据,您仍然在内存中引用它们。这就是数据库旨在防止的:所有高效的数据存储和检索,而无需将其全部存储在 RAM 中。下面是一个使用 PyMongo 的简单示例(对于 iOS 应用程序,您可能会想要使用 SQLite):
import pdfplumbder
import poymongo
import os
def process_file(path, collection):
'''Process a single file, from a path.'''
basename = os.path.splitext(os.path.basename(path))[0]
with pdfplumber.open(path) as pdf:
for index, page in enumerate(pdf.pages):
# Don't store any long-term references to the data
text = page.extract_text()
data = { 'text': text, 'filename': basename, 'page': index }
collection.insert_one(data)
def main(paths):
'''Just a dummy entry point, pass args normally here.'''
client = pymongo.MongoClient('localhost', 27017)
database = client['myapp']
collection = database['pdfs']
# Sort by filename, then by page.
collection.create_index([('filename', 1), ('page', 1)])
for path in paths:
process_file(path, collection)
# Do what you want here
如您所见,我们创建了到本地客户端的连接,创建或访问我们正在使用的数据库,并创建了一个用于 PDF 存储的集合。然后我们按文件名索引,然后是页码。
然后我们遍历所有路径,并迭代处理它们。我们不会一次存储超过一页的文本,并且每次循环都将数据写入数据库。就性能而言,这可能不是最佳选择(尽管引擎可能会对此进行适当优化),但它会最大限度地减少所需的内存。
避免使用处理数 GB 数据的全局状态:您迫使 Python 在不需要时保留对所有数据的引用。