IT-инфраструктура для бизнеса и творчества
Разработка
NTA

Как найти однотипную информацию в большом количестве файлов, используя Python?

Недавно мы решали следующую задачу – необходимо найти и удалить содержащие номера карт файлы, размещенные на общем ресурсе. Если нужно было бы искали что-то, определенное и однозначное, мы могли бы воспользоваться поиском в самой операционной системе (используя стандартны поиск текста в содержимом файла). Но, как правило, поиск стандартными средствами занимает очень много времени. А если еще нужно хотите использовать маски или регулярные выражения, то как быть? Поделимся, как мы решили эту задачу.

Инструменты

Данную задачу можно решить на многих языках взяв за основу идею, описанную в этой статье. Я буду делать реализацию на языке Python, а инструменты использовать «из коробки», без импорта сторонних библиотек. Почему я не использовал библиотеку Pandas? Pandas хороший инструмент для работы с файлами Excel, но он достаточно массивный и ресурсоемкий для решения нашей задачи.

Решение задачи

Углубимся в формат XLSX. Что он из себя представляет? Файл Excel — это обычный структурированный архив с расширением. XLSX. Если мы изменим расширение на. ZIP, то сможем открыть его с помощью архиватора, установленного в вашей операционной системе.

Давайте так и сделаем:

Файл Excel открылся в архиваторе, и мы видим структуру самого архива. Нам нужна папка [xl]. Проваливаемся в нее и видим:

Нам интересны директория [worksheets] и файл [sharedStrings.xml].

В файле [sharedString.xml] хранятся все текстовые поля, которые есть на листах в Excel, т.е. если поле текстовое, то оно будет хранится в этом файле, а ссылка на это поле будет находится в директории [worksheets] на соответствующем листе. Если в нескольких ячейках будет одно и тоже слово, то в файле будет одно слово, а в ячейках будет указана одна ссылка на это слово (см. рис.).

Итак, мы знаем, что номер карты является текстовым полем, соответственно он будет находится в этом файле. Приступим к написанию кода. Нам понадобятся следующие библиотеки: os – для работы с путями ОС, zipfile – для работы с архивами, re – для работы с регулярными выражениями — паттернами.

import os, zipfile, re #импортируем библиотеки #Определяем регулярные выражения pattern_card16=rb"(\b\d{16}\b|\b\d{4}\s\d{4}\s\d{4}\s\d{4}\b|\b\d{8}\s\d{8}\b)" pattern_card18=rb"(\b\d{18}\b|\b\d{8}\s\d{10}\b)"

Далее пишем функцию, которая будет сканировать выбранную нами директорию:

def find_file(dirn, path): # функция принимает os.listdir, и путь на папку try: for i in dirn: if os.path.isfile(path+'/'+i): #проверяем что перед нами, файл или нет #Проверяем расширение файла и исключаем системные которые начинаются на [~$] if i.find('.xlsx')!=-1and i.find('~$')==-1 and i.find('.xlsx.')==-1: open_arch(path+'/'+i) #Функция по обработке архивов else: #Если это директория, то проваливаемся в нее find_file(os.listdir(path+'/'+i),path+'/'+i) except Exception as err: print(err,path+'/'+i)

Теперь напишем саму функцию, которая будет обрабатывать найденные по условию файлы:

def open_arch(path_file): z = zipfile.ZipFile(path_file, 'r') #открываем архив files=z.namelist() #получаем список файлов в архиве try: for f in files: if f=='xl/sharedStrings.xml': if re.search(pattern_card16, z.read(f))!=None or re.search(pattern_card18, z.read(f))!=None: list_file.write(path_file+'\n') #Если находит совпадение, то пишем путь в файл #print(re.findall(pattern_card16, z.read(r))) # если вам нужно #print(re.findall(pattern_card18, z.read(r))) # выводить совпадения except Exception as err: print(err, files)

Определяем директорию для поиска и запускаем функцию для поиска:

path='Y:' #указываем путь к общему ресурсу, здесь я его подцепил как диск Y: list_file=open('list_file', 'w+') #открываем файл для записи find_file(os.listdir(path), path) #запускаем обработку

Резюме

Наша работа сделана. Ждем, когда отработает скрипт и получим итоговый файл для анализа. Вы зададите вопрос, почему я сразу не стал удалять файлы? Потому что поиск основан на простом регулярном выражении и туда могут попасть номера заявок, договоров и т.д.

В результате нам удалось избежать ручного анализа более 154 тысяч файлов и сократить выборку более чем в 100 раз.

Я надеюсь, моя инструкция была полезна. Спасибо за внимание.

{ "author_name": "NTA", "author_type": "editor", "tags": ["\u0444\u0443\u043d\u043a\u0446\u0438\u044f","\u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c","\u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c","\u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c","\u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u043c","\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c","\u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c","\u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c","\u0435\u0441\u043b\u0438","selectel_\u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f","print"], "comments": 0, "likes": 2, "favorites": 7, "is_advertisement": false, "subsite_label": "dev", "id": 156704, "is_wide": true, "is_ugc": false, "date": "Tue, 08 Sep 2020 17:54:58 +0300", "is_special": false }
(function () { let cdnUrl = `https://specialsf378ef5-a.akamaihd.net/SelectelBranding/images/` let previousArticleNumber = null let currentArticleNumber = 0 let platform = 'Desktop' let articles = [ // { // name: 'camera', // url: `${cdnUrl}CameraCat`, // text: 'умную камеру для\u00A0наблюдения за\u00A0котиками', // link: '1', // }, { name: 'chill', url: `${cdnUrl}ChillCat`, text: 'трекер, который подскажет, когда пора отдохнуть', link: 'https://vc.ru/promo/288561-eye-tracker', }, // { // name: 'cloud', // url: `${cdnUrl}CloudCat`, // text: 'котика: даёшь ему «пять», а\u00A0он делает бэкап в облако', // link: '3', // } ] let buttonCycle = document.querySelector('.button--cycle') let textField = document.querySelector('.selectel-footer-subtitle') let imageAgent = document.querySelector('.image--agent') let banner = document.querySelector('.selectel-footer') buttonCycle.addEventListener('click', cycleClick) let media = window.matchMedia("(max-width: 570px)") media.addEventListener('change', matchMedia) function matchMedia() { if (media.matches) { platform = 'Mobile' } else { platform = 'Desktop' } update() } matchMedia() function cycleClick(event) { if (event) { event.preventDefault() event.stopPropagation() } window.open('https://vc.ru/tag/selectelDIY', '_blank') //cycle(event) } function cycle(event) { // incrementArticleNumber() textField.innerHTML = generatedText() imageAgent.src = articles[currentArticleNumber].url + platform + '.svg?5' imageAgent.setAttribute("class", "") imageAgent.classList.add('image--agent', articles[currentArticleNumber].name) banner.href = articles[currentArticleNumber].link } function update() { banner.href = articles[currentArticleNumber].link imageAgent.src = articles[currentArticleNumber].url + platform + '.svg?5' textField.innerHTML = generatedText() } function incrementArticleNumber() { previousArticleNumber = currentArticleNumber if (currentArticleNumber >= articles.length - 1) { currentArticleNumber = 0 } else { currentArticleNumber++ } } function generatedText() { let defaultText if (platform === 'Desktop') { defaultText = `Мы тут собрали %text%. Хотите почитать?` } else { defaultText = `Мы тут собрали %text%.` } return defaultText.replace('%text%', articles[currentArticleNumber].text) } function getRandom(min, max) { min = Math.ceil(min) max = Math.floor(max) return Math.floor(Math.random() * (max - min + 1)) + min } (function create() { currentArticleNumber = getRandom(0, articles.length - 1) cycle() let page = document.querySelector('.page--entry') if (page) { function insertAfter() { let parents = page.querySelectorAll('[data-id="7"]') let referenceNode = parents[0] referenceNode.parentNode.insertBefore(banner, referenceNode.nextSibling); loaded() } setTimeout(() => insertAfter(), 0) } }()) function loaded() { banner.classList.add('loaded') } loadImages([ `${cdnUrl}CameraCatDesktop.svg`, `${cdnUrl}ChillCatDesktop.svg`, `${cdnUrl}CloudCatDesktop.svg`, `${cdnUrl}CameraCatMobile.svg`, `${cdnUrl}ChillCatMobile.svg`, `${cdnUrl}CloudCatMobile.svg`, ]) function loadImages(urls) { return Promise.all(urls.map(function (url) { return new Promise(function (resolve) { var img = document.createElement('img'); img.onload = resolve; img.onerror = resolve; img.src = url; }); })); } }())
0
0 комментариев
Популярные
По порядку
Читать все 0 комментариев
Переход бизнеса на Apple: нет причин отказывать себе в удовольствии

Работать на устройствах Apple – это просто, удобно, приятно, современно. А еще, как продолжают считать некоторые – дорого и не для всех. Однако это не так: хотя «яблочные» устройства и работают в каждой международной корпорации из Fortune 500, сегодня они доступны практически любой SMB-компании, стартапу, и даже общеобразовательной школе. Причина кроется как в самих технологиях Apple, так и в выстроенных вокруг них сервисных программах.

Компонент в Figma с нулевыми размерами. Приёмы и фишки

Как сделать компонент с размерами 0 на 0 пикселей, и где это можно применить.

«На новую систему потратили не более 1 млн рублей»: баттл предпринимателей о том, как модель управления бизнесом лучшая

Владельцы «Перилаглавснаб», Gartel, Compleader и «Архитектуры благополучия» — о том, почему модные «бирюзовые организации» не для всех, как выдержать трёхкратный рост бизнеса и не работать по 14 часов в день.

Из жизни клуба
Министерство транспорта предложило устанавливать в такси устройства контроля за усталостью водителя Статьи редакции

И размещать на крыше автомобиля оранжевый фонарь.

Готовы выбрать победителя премии «Экспортер года eBay — 2021»?
Повелись на красивые кейсы таргетологов из «Hope group» и вот что из этого вышло

В августе я наткнулся на vc.ru не кейсы ребят из «Hope group», с ними вы можете ознакомиться по этой ссылке. И на удивление кейсы показались супер адекватными ведь в них ребята оперируют не кликами, показами и прочими ничего не значащими показателями, а конкретными продажами и конверсиями. Я связался с основателем и в сентябре мы подписали…

Сергей Галицкий о деньгах: «В гробу карманов нет. Два завтрака съесть не сможешь» Статьи редакции

В сентябре бизнесмен сообщил о своей болезни, которая мешает ему работать.

Во-первых, следующее поколение должно иметь мотивацию. Во-вторых, в гробу карманов нет. Ты заработал в этом обществе. И ты должен отдавать этому обществу. Два завтрака ты съесть не сможешь, как ни пытайся. Второй завтрак уже будет полдником.

Ты не можешь употребить больше двух-трёх тысяч калорий в день. Тебе не нужно столько. Не нужно двадцать машин, тридцать самолетов.

Сергей Галицкий
цитата по Sports.ru
Как мы проводили командную ретроспективу в Minecraft

Рассказываем историю, на что стоит обратить внимание при проведении командного мероприятия в игре Minecraft, какие грабли могут быть, как организовать онлайн- и офлайн-участие.

Нужны ли в России сити-фермы

И появятся ли грядки на крышах пятиэтажек.

re-thinkingthefuture.com
Пивот маркетплейса для маркетплейсов

Сегодня я снова расскажу про «маркетплейс маркетплейсов», который мы делали девять месяцев. Прежде я уже упоминал его в своём блоге, сообщая об этапах его развития, а сейчас основатель проекта, зашёл в тупик, что и стало причиной, по которой я решил написать эту статью.

null