Рассмотрим задачи парсинга PDF: разбиение документа на страницы и их сохранение; объединение листов в один; извлечение текста и таблиц.
13К открытий15К показов
В этой статье мы выполним задачи парсинга PDF:
Из файла PDF удалить страницы с таблицами.
Страницы без таблиц сохранить отдельными файлами pdf, прибавив к названию основного файла суффикс «_n», где n — порядковый номер страницы.
Страницы без таблиц объединить в один файл pdf с названием основного файла + ‘ no tables’.
Из страниц с таблицами извлечь таблицы и сохранить в файл csv/xlsx c названием «table-n», где n – порядковый номер таблицы.
Для выполнения задания пока потребуются такие модули: pdfplumber — для извлечения таблиц и pdfrw — для чтения/записи файлов pdf. Эти модули не входят в стандартную библиотеку Python, по этому их нужно устанавливать.
Установить их можно командами: pip install pdfrw, pip install pdfplumber.
Работа с библиотекой pdfrw
Чтение документа
from pdfrw import PdfReader
path_pdf = 'path/to/file.pdf'
x = PdfReader(path_pdf)
print(len(x.pages))
Всё просто. Импорт подкласса PdfReader, создание его объекта, который читает файл, атрибут pages возвращает список всех страниц в документе.
Запись одной страницы
# запись выбранной страницы
from pdfrw import PdfWriter
y = PdfWriter()
y.addpage(x.pages[0])
y.write('result1.pdf')
Также всё просто. Объекту подкласса PdfWriter Y передаём через метод .addpage прочитанную объектом Xнужную нам страницу для записи, метод .write делает запись.
Запись нескольких страниц в один файл
# запись нескольких страниц в одну
from pdfrw import PdfWriter
y = PdfWriter()
y.addpage(x.pages[0])
y.addpage(x.pages[2])
y.write('result2.pdf')
Думаю, тут комментарий не нужен.
Здесь приведены примеры только тех методов и атрибутов, которые нужны для выполнения задания. Для более глубокого изучения ссылки на документации: https://pypi.org/project/pdfrw, https://pypi.org/project/pdfplumber/.
Работа с модулем pdfplumber
import pdfplumber
path_pdf = 'path/to/file.pdf'
with pdfplumber.open(path_pdf) as pdf:
print(pdf.pages)
print()
page = pdf.pages[2]
table = page.extract_table()
print(table)
print()
text = page.extract_text()
print(text)
Здесь метод .open возвращает экземпляр pdfplumber.PDF класса, атрибут pages возвращает список экземпляров pdfplumber.Page каждой страницы документа, метод .extract_table извлекает табличные данные со страницы. Он возвращает двухмерный список, где элементами списка есть списки с данными каждой строки таблицы. Дальше этими данными мы воспользуемся для записи таблицы в файл csv/xlsx. Метод .extract_text возвращает текст таблицы одной строкой с символами перехода на новую строку.
Для записи в файл с расширением csv, ничего устанавливать не надо. Модуль CSV уже уставлен в стандартную библиотеку Python.
CSV-модуль имеет два класса: reader — для чтения табличных данных формата csv, writer — для записи.
Нам нужен класс writer:
import csv
with open('path/to/file.csv', 'w') as f:
writer = csv.writer(f, delimiter=';')
writer.writerows(table)
Здесь writer — экземпляр класса writer с параметрами: f — дескриптор открытого файла для записи, delimiter — задаёт значение для разделения полей в строках. Запись делает метод .writerows для всех строк table.
Запись в XLSX-файл
Для записи документов с расширением .xlsx в стандартной библиотеке нет модулей. Здесь будут рассмотрены модуль xlsxWriter и библиотека Pandas.
Модуль xlsxWriter
Установка модуля: pip install XlsxWriter.
import xlsxwriter
workbook = xlsxwriter.Workbook('path/to/file.xlsx)
worksheet = workbook.add_worksheet()
for row, el in enumerate(table):
for column, data in enumerate(el):
worksheet.write(row, column, data)
workbook.close()
Здесь:
Импортируем модуль.
Создаём объект книги конструктором Workbook().
Метод add_worksheet() добавляет новый рабочий лист книги.
Перебор данных и запись методом write() с параметрами:
row — номер строки;column— номер колонки;data — данные для записи в ячейку.
Для создания и записи в документ .xlsx или .csv (pandas предоставляет обе возможности), нужно создать объект класса DataFrme, и сохранить документ с нужным расширением.
import pandas as pd
df = pd.DataFrame(table)
df.to_excel('path/to/file.xlsx')
df.to_csv('path/to/file.csv')
Выполняем задание
import csv
import pdfplumber
from pdfrw import PdfReader, PdfWriter
path_pdf = 'path/to/file.pdf’
def wrt_csv(k, table):
# функция записывает файл .csv
# k - номер таблицы
# table - двухмерный список данных
with open(f'table-{k}.csv', 'w') as f:
writer = csv.writer(f, delimiter=';')
writer.writerows(table)
def wrt_page(path_pdf, i, n, file_name):
# функция записывает одну страницу .pdf
# path_pdf - путь к файлу
# i - номер страницы
# n - номер страницы для названия
# file_name - название документа
x = PdfReader(path_pdf)
y = PdfWriter()
y.addpage(x.pages[i])
y.write(f'{file_name}_{str(n)}.pdf')
def wrt_pages(path_pdf, list_page, file_name):
x = PdfReader(path_pdf)
y = PdfWriter()
for n in list_page:
y.addpage(x.pages[n])
y.write(f'{file_name} no tables.pdf')
def rezult(path_pdf):
file_name = path_pdf.split('\')[-1].split('.')[0]
with pdfplumber.open(path_pdf) as pdf:
n = 0
list_page = []
k = 0
for i in range(len(pdf.pages)):
page = pdf.pages[i]
table = page.extract_table() # None, list
if not table:
list_page.append(i)
n += 1
# запись одной страницы.pdf без таблицы
wrt_page(path_pdf, i, n, file_name)
# объединение страниц в одну страницу .pdf
wrt_pages(path_pdf, list_page, file_name)
else:
k += 1
# функция для записи таблицы .csv
wrt_csv(k, table)
if __name__ == '__main__':
rezult(path_pdf)
Итоги
Мы рассмотрели основные задачи парсинга PDF:
разбиение документа PDF на отдельные страницы и их сохранение;
объединение нескольких листов .pdf в один лист;
извлечение текста и таблиц из PDF.
Ещё очень часто приходится извлекать из PDF картинки, но это уже тема для следующей статьи.
Свежий проект собрал личные сайты создателей популярных языков программирования Python, Go и Ruby в одном месте, но столкнулся с техническими трудностями, такими как высокая загрузка процессора