Поиск файлов с расширением pdf python
Problem
I'm trying to determine what type a document is (e.g. pleading, correspondence, subpoena, etc) by searching through its text, preferably using python. All PDFs are searchable, but I haven't found a solution to parsing it with python and applying a script to search it (short of converting it to a text file first, but that could be resource-intensive for n documents).
What I've done so far
I've looked into pypdf, pdfminer, adobe pdf documentation, and any questions here I could find (though none seemed to directly solve this issue). PDFminer seems to have the most potential, but after reading through the documentation I'm not even sure where to begin.
Is there a simple, effective method for reading PDF text, either by page, line, or the entire document? Or any other workarounds?
I was looking for the same solution. The problem is that PDF documents are notorious for breaking up text into chunks that are difficult to reassemble. It depends on the program that wrote the PDF. I ended up using PDFminer and a lot of "elif" code to parse PDFs.
10 Answers 10
os.walk is the answer, this will find the first match:
And this will find all matches:
And this will match a pattern:
Note that these examples will only find files, not directories with the same name. If you want to find any object in the directory with that name you might want to use if name in file or name in dirs
Be careful of case sensitivity. for name in files: will fail looking for super-photo.jpg when it's super-photo.JPG in the file system. (an hour of my life I'd like back ;-) Somewhat messy fix is if str.lower(name) in [x.lower() for x in files]
What about using yield instead of preparing the result list? . if fnmatch.fnmatch(name, pattern): yield os.path.join(root, name)
Comprehention list can replace the function, e.g. find_all: res = [os.path.join(root, name) for root, dirs, files in os.walk(path) if name in files]
In Python 3.4 or newer you can use pathlib to do recursive globbing:
In Python 3.5 or newer you can also do recursive globbing like this:
I used a version of os.walk and on a larger directory got times around 3.5 sec. I tried two random solutions with no great improvement, then just did:
While it's POSIX-only, I got 0.25 sec.
From this, I believe it's entirely possible to optimise whole searching a lot in a platform-independent way, but this is where I stopped the research.
If you are using Python on Ubuntu and you only want it to work on Ubuntu a substantially faster way is the use the terminal's locate program like this.
search_results is a list of the absolute file paths. This is 10,000's of times faster than the methods above and for one search I've done it was ~72,000 times faster.
For fast, OS-independent search, use scandir
Specifically, use scandir.walk() per @Nadia's answer. Note that if you're using Python 3.5+, os.walk() has the scandir.walk() speedups already. Also, PEP 471 is probably a better document to read for info than that issue.
If you are working with Python 2 you have a problem with infinite recursion on windows caused by self-referring symlinks.
This script will avoid following those. Note that this is windows-specific!
It returns a list with all paths that point to files in the filenames list. Usage:
Below we use a boolean "first" argument to switch between first match and all matches (a default which is equivalent to "find . -name file"):
The answer is very similar to existing ones, but slightly optimized.
So you can find any files or folders by pattern:
either by substring:
or using a predicate:
to search only files or only folders - replace “dirs + files”, for example, with only “dirs” or only “files”, depending on what you need.
SARose's answer worked for me until I updated from Ubuntu 20.04 LTS. The slight change I made to his code makes it work on the latest Ubuntu release.
I'm new to Stack Overflow so I'm unable to comment on someone's else answer. I'm currently working with Python 3.7.4, on Windows.
@F.M.F's answers has a few problems in this version, so I made a few adjustments to make it work.
unicode() was changed to str() in Python 3, so I made that adjustment (line 8)
I also added (in line 25) and exception to PermissionError. This way, the program won't stop if it finds a folder it can't access.
Finally, I would like to give a little warning. When running the program, even if you are looking for a single file/directory, make sure you pass it as a list. Otherwise, you will get a lot of answers that not necessarily match your search.
find("C:\", ["Python", "Homework"])
but, for example: find("C:\\", "Homework") will give un-wanted answers.
I would be lying if I said I know why this happens. Again, this is not my code and I just made the adjustments I needed to make it work. All credit should go to @F.M.F.
11 Answers 11
This is called PDF mining, and is very hard because:
- PDF is a document format designed to be printed, not to be parsed. Inside a PDF document, text is in no particular order (unless order is important for printing), most of the time the original text structure is lost (letters may not be grouped as words and words may not be grouped in sentences, and the order they are placed in the paper is often random).
- There are tons of software generating PDFs, many are defective.
Tools like PDFminer use heuristics to group letters and words again based on their position in the page. I agree, the interface is pretty low level, but it makes more sense when you know what problem they are trying to solve (in the end, what matters is choosing how close from the neighbors a letter/word/line has to be in order to be considered part of a paragraph).
An expensive alternative (in terms of time/computer power) is generating images for each page and feeding them to OCR, may be worth a try if you have a very good OCR.
So my answer is no, there is no such thing as a simple, effective method for extracting text from PDF files - if your documents have a known structure, you can fine-tune the rules and get good results, but it is always a gambling.
I would really like to be proven wrong.
The answer has not changed but recently I was involved with two projects: one of them is using computer vision in order to extract data from scanned hospital forms. The other extracts data from court records. What I learned is:
Computer vision is at reach of mere mortals in 2018. If you have a good sample of already classified documents you can use OpenCV or SciKit-Image in order to extract features and train a machine learning classifier to determine what type a document is.
If the PDF you are analyzing is "searchable", you can get very far extracting all the text using a software like pdftotext and a Bayesian filter (same kind of algorithm used to classify SPAM).
So there is no reliable and effective method for extracting text from PDF files but you may not need one in order to solve the problem at hand (document type classification).
В основном вы можете использовать два метода для открытия всех файлов внутри каталога в Python: функцию os.listdir() и функцию glob.glob() . В этом руководстве будут представлены методы открытия всех файлов в каталоге в Python. Мы также включили примеры программ, которым вы можете следовать.
Показываем содержимое директории
Еще одна полезная команда — os.listdir(). Она показывает все содержимое каталога.
Команда отличается от os.walk (), где последний рекурсивно показывает все, что находится «под» каталогом. os.listdir () намного проще в использовании, потому что просто возвращает список содержимого:
В некоторых случаях нужно что-то более продвинутое — например, поиск всех CSV-файлов в каталоге «sample_data». В этом случае самый простой способ — использовать встроенную библиотеку glob:
Удаление файлов и папок
Теперь пришел черед разобраться с процедурой удаления файлов и папок. Нам здесь снова поможет библиотека OS.
Когда нужно удалить файл, нужно воспользоваться командой os.remove():
Если требуется удалить каталог, на помощь приходит os.rmdir():
Однако он может удалить только пустой каталог. На приведенном выше скриншоте видим, что удалить можно лишь каталог level_3. Что если мы хотим рекурсивно удалить каталог level_1? В этом случае зовем на помощь shutil.
Функция shutil.rmtree() сделает все, что нужно:
Пользоваться ею нужно с осторожностью, поскольку она безвозвратно удаляет все содержимое каталога.
Собственно, на этом все. 8 важных операций по работе с файлами и каталогами в среде Python мы знаем. Что касается ссылки, о которой говорилось в анонсе, то вот она — это Google Colab Network с содержимым, готовым к запуску.
I have a file that may be in a different place on each user's machine. Is there a way to implement a search for the file? A way that I can pass the file's name and the directory tree to search in?
Откройте все файлы в каталоге с помощью функции glob.glob() в Python
Модуль glob используется для вывода списка файлов внутри определенного каталога. Функция glob() внутри модуля glob используется для получения списка файлов или подкаталогов, соответствующих указанному шаблону внутри указанного каталога. Функция glob.glob() принимает шаблон в качестве входного параметра и возвращает список файлов и подкаталогов внутри указанного каталога.
Мы можем перебирать все текстовые файлы внутри определенного каталога с помощью функции glob.glob() и открывать их с помощью функции open() в Python. В следующем примере кода показано, как мы можем открыть все файлы в каталоге с помощью функций glob.glob() и open() :
Мы читаем текст из трех файлов внутри каталога files/ и распечатываем его на терминале в приведенном выше коде. Сначала мы использовали цикл for/in с функцией glob.glob() для перебора каждого файла, находящегося внутри каталога files . Затем мы открывали каждый файл в режиме read с помощью функции open() и печатали текст внутри каждого файла.
Объединение компонентов пути
В предыдущем примере я намеренно использовал слеш "/" для разделителя компонентов пути. В принципе это нормально, но не рекомендуется. Если вы хотите, чтобы ваше приложение было кроссплатформенным, такой вариант не подходит. Так, некоторые старые версии ОС Windows распознают только слеш "\" в качестве разделителя.
Но не переживайте, Python прекрасно решает эту проблему благодаря функции os.path.join (). Давайте перепишем вариант из примера в предыдущем пункте, используя эту функцию:
Сопутствующая статья - Python File
Сопутствующая статья - Python Directory
report this ad
Начнем с точки входа в приложение. Чтобы инструмент удобно было использовать, напишем приложение с командным интерфейсом. Перед началом работы также стоит создать переменное окружение и активировать его.
Для обработки параметров командной строки в Python есть удобный модуль click (установка pip install click). Обработка аргументов командной строки происходит при помощи добавления к функции декораторов. Определим обязательные параметры: search_path — путь по которому будем искать, либо файл с путями и дополнительные: режим исполнения программы (многопоточный или без), имя файла с результатами, формат записи результата (excel, csv, sqlite) и другие параметры по вашему желанию.
Функцию поиска содержимого будем вызывать из функции main(). В данном случае вызов выглядит следующим образом:
Совершим настройку логирования для сохранения информации о произошедших при исполнении скрипта ошибок. Для этого прекрасно подходит встроенный модуль logging. Информация будет записываться в файл лога.
В качестве аргументов командной строки может поступать одиночный путь, либо файл с путями. Для проверки файл это или каталог прекрасно подходит класс Path модуля pathlib. Выбор одного из двух вариантов реализуем следующим образом.
Варианты заполнения списка с путями для проверки опишем с помощью словаря с ключами, представляющими тип входного пути (отдельный путь, файл формата csv или json) и значениями – функции для обработки.
Функции для обработки считывают данные из файлов и записывают в список словарей с ключами идентификатор, имя ресурса, путь. Словари очень хорошо подходят для написания красивого кода и возможности избавиться от множественных проверок условий.
Каждая функция принимает два параметра список для хранения результатов и путь к файлу с данными.
Также не стоит забывать обрабатывать параметры командной строки – пользователь может ввести их неправильно. Посмотрим обработку на примере аргумента search_type:
Теперь, когда имеется словарь с функциями для заполнения списка входных данных из файлов с разными форматами заполнение списка будет выглядеть довольно просто:
Многопоточность и обработка частями
Чтобы наше приложение могло использовать как можно больше вычислительных ресурсов добавим многопоточность при помощи ThreadPoolExecutor из стандартной библиотеки. Для отображения прогресса работы программы используем tqdm (pip install tqdm).
Результаты поиска будем записывать в датафрейм модуля pandas (pip install pandas). В процессе поиска будем сохранять промежуточные результаты, на случай если что-то пойдёт не так и скрипт завершит работу.
Количество обрабатываемых файлов для записи промежуточных результатов определим в FILES_IN_POOL, а колонки для отчёта опишем в переменной REPORT_COLUMNS (список строк).
Обработка файлов и архивов
Для обработки результатов напишем функцию-генератор, возвращающий результаты обработки и использующую функцию os.walk для рекурсивного обхода по файлам:
Для работы с файлами и поиска по ним используется отдельный класс:
Обработку файла реализуем при помощи метода process() класса File.
Отдельно стоит упомянуть, что при обработке архивов разных форматов их прийдётся извлекать во временные папки и обрабатывать. Конечно, как вариант, можно использовать отдельные модули для обработки архивов разного формата (есть стандартные модули zip, tarfile остальные нужно устанавливать), но для задач, в каких целях применялся разработанный инструмент, требовалась обработка rar формата. В данном случае будет использоваться модуль patoolib (pip install patool).
Также при обработке архивов стоит учесть, что внутри могут находиться другие архивы. Поэтому извлекать архивы стоит рекурсивно. Класс для обработки архивов представлен ниже:
Для хранения результатов поиска удобно организовать отдельный класс.
Для обработки файлов с различными расширениями напишем отдельные функции. Для их вызова также используем словарь.
При обработке текстовых файлов нам помогут средства стандартной библиотеки Python, табличных – модули pandas, pyexcel, xlrd ; файлов Word – модули docx2txt, win32com/пакет LibreOffice; rtf –модуль striprtf; pdf файлов – модуль pdfminer.
Поиск по содержимому
Для поиска информации воспользуемся модулем re. Если нужно искать данные по каким-то конкретным шаблонам, как в случае с задачей для которых использовался инструмент, определим их отдельно в переменной SEARCH_REGEXPS.
Обработка результатов
Промежуточные результаты сохраняются в файлы на локальном компьютере. Для записи результатов Обработка полученных результатов выглядит следующим образом.
Для записи в базу данных воспользуемся модулями sqlalchemy, pymssql, pandas. Настройки для подключения будем хранить в отдельном файле или переменных среды. Код для записи в БД выглядит следующим образом.
Вот так будет выглядеть результат:
Таким образом, получим инструмент, позволяющий обрабатывать файлы в указанных каталогах.
Python становится все популярнее благодаря относительной простоте изучения, универсальности и другим преимуществам. Правда, у начинающих разработчиков нередко возникают проблемы при работе с файлами и файловой системой. Просто потому, что они знают не все команды, которые нужно знать.
Эта статья предназначена как раз для начинающих разработчиков. В ней описаны 8 крайне важных команд для работы с файлами, папками и файловой системой в целом. Все примеры из этой статьи размещены в Google Colab Notebook (ссылка на ресурс — в конце статьи).
Проверяем, существует файл или каталог
Прежде чем задействовать команду по созданию файла или каталога, стоит убедиться, что аналогичных элементов нет. Это поможет избежать ряда ошибок при работе приложения, включая перезапись существующих элементов с данными.
Функция os.path.exists () принимает аргумент строкового типа, который может быть либо именем каталога, либо файлом.
В случае с Google Colab при каждом запуске создается папка sample_data. Давайте проверим, существует ли такой каталог. Для этого подойдет следующий код:
Эта же команда подходит и для работы с файлами:
Если папки или файла нет, команда возвращает false.
Создание директории
Ну а теперь самое время создать директорию с именем test_dir внутри рабочей директории. Для этого можно использовать функцию
os.mkdir():
Давайте посмотрим, как это работает на практике.
Если же мы попытаемся создать каталог, который уже существует, то получим исключение.
Именно поэтому рекомендуется всегда проверять наличие каталога с определенным названием перед созданием нового:
Еще один совет по созданию каталогов. Иногда нам нужно создать подкаталоги с уровнем вложенности 2 или более. Если мы все еще используем os.mkdir (), нам нужно будет сделать это несколько раз. В этом случае мы можем использовать os.makedirs (). Эта функция создаст все промежуточные каталоги так же, как флаг mkdir -p в системе Linux:
Вот что получается в результате.
Откройте все файлы в каталоге с помощью функции os.listdir() в Python
Функция listdir() внутри модуля os используется для вывода списка всех файлов в указанном каталоге. Эта функция принимает указанный путь к каталогу в качестве входного параметра и возвращает имена всех файлов внутри этого каталога. Мы можем перебирать все файлы внутри определенного каталога с помощью функции os.listdir() и открывать их с помощью функции open() в Python.
В следующем примере кода показано, как мы можем открыть все файлы в каталоге с помощью функций os.listdir() и open() .
Мы читаем текст из трех файлов внутри каталога files/ и распечатываем его на терминале в приведенном выше коде. Сначала мы использовали цикл for/in с функцией os.listdir() для перебора каждого файла, находящегося внутри каталога files . Затем мы открывали каждый файл в режиме read с помощью функции open() и печатали текст внутри каждого файла.
Копирование файлов
Аналогичным образом shutil подходит и для копирования файлов по уже упомянутым причинам.
Если нужно скопировать файл README.md из папки «sample_data» в папку «test_dir», поможет функция shutil.copy():
Перемещение файлов
Самое время попробовать переместить файлы из одной папки в другую. Рекомендованный способ — еще одна встроенная библиотека shutil.
Сейчас попробуем переместить все CSV-файлы из директории «sample_data» в директорию «test_dir». Ниже — пример кода для выполнения этой операции:
Кстати, есть два способа выполнить задуманное. Например, мы можем использовать библиотеку OS, если не хочется импортировать дополнительные библиотеки. Как os.rename, так и os.replace подходят для решения задачи.
Но обе они недостаточно «умные», чтобы позволить перемесить файлы в каталог.
Чтобы все это работало, нужно явно указать имя файла в месте назначения. Ниже — код, который это позволяет сделать:
Здесь функция os.path.basename () предназначена для извлечения имени файла из пути с любым количеством компонентов.
Другая функция, os.replace (), делает то же самое. Но разница в том, что os.replace () не зависит от платформы, тогда как os.rename () будет работать только в системе Unix / Linux.
Еще один минус — в том, что обе функции не поддерживают перемещение файлов из разных файловых систем, в отличие от shutil.
Поэтому я рекомендую использовать shutil.move () для перемещения файлов.
Показать текущий каталог
Самая простая и вместе с тем одна из самых важных команд для Python-разработчика. Она нужна потому, что чаще всего разработчики имеют дело с относительными путями. Но в некоторых случаях важно знать, где мы находимся.
Относительный путь хорош тем, что работает для всех пользователей, с любыми системами, количеством дисков и так далее.
Так вот, для того чтобы показать текущий каталог, нужна встроенная в Python OS-библиотека:
Ее легко запомнить, так что лучше выучить один раз, чем постоянно гуглить. Это здорово экономит время.
Имейте в виду, что я использую Google Colab, так что путь /content является абсолютным.
Читайте также: