Привет всем! Интересный вопрос был задан мне в Telegram несколько дней назад. В целом, он сводился к задаче, которая звучала как: поиск в Excel-файле. Давайте попробуем ее решить? 🙂
Собственно, любой Excel-файл — это некоторое количество строк и колонок. Работаем, как всегда — с помощью библиотеки Openpyxl, а для работы с каждой отдельной ячейкой — используем цикл while.
В целом, алгоритм работы кода сводится к:
1. Открываем файл (об этом я писал ранее)
2. Читаем первую ячейку в строке
3. Переходим к следующей строке в этом столбце
4. После того, как достигли максимума по количеству ячеек в столбце — переходим к следующему столбцу.
5. И так до полной обработки файла.
Важно: для того, что бы цикл работал — нам нужно знать количество ячеек в строках и в столбцах. Для этого используем конструкции в виде:
-
row_max = sheet_active.max_row # Получаем количество столбцов
и
-
column_max = sheet_active.max_column # Получаем количество строк
Сам код с комментариями — доступен ниже.
-
import openpyxl
-
from openpyxl.utils import get_column_letter
-
import re
-
-
path_to_file = 'base_to_search.xlsx'
-
-
search_text = input(str('Какой текст ищем: '))
-
search_text = search_text.lower()
-
print('Ищем:', search_text)
-
-
wb = openpyxl.load_workbook(path_to_file) # Грузим наш прайс-лист
-
sheets_list = wb.sheetnames # Получаем список всех листов в файле
-
sheet_active = wb[sheets_list[0]] # Начинаем работать с самым первым
-
row_max = sheet_active.max_row # Получаем количество столбцов
-
#print(type(row_max))
-
column_max = sheet_active.max_column # Получаем количество строк
-
-
print('В файле:', path_to_file, 'n Cтолбцов:', row_max, 'n Колонок:', column_max)
-
-
row_min = 1 #Переменная, отвечающая за номер строки
-
column_min = 1 #Переменная, отвечающая за номер столбца
-
-
while column_min <= column_max:
-
row_min_min = row_min
-
row_max_max = row_max
-
while row_min_min <= row_max_max:
-
row_min_min = str(row_min_min)
-
-
word_column = get_column_letter(column_min)
-
word_column = str(word_column)
-
word_cell = word_column + row_min_min
-
-
data_from_cell = sheet_active[word_cell].value
-
data_from_cell = str(data_from_cell)
-
#print(data_from_cell)
-
regular = search_text
-
result = re.findall(regular, data_from_cell)
-
if len(result) > 0:
-
print('Нашли в ячейке:', word_cell)
-
row_min_min = int(row_min_min)
-
row_min_min = row_min_min + 1
-
column_min = column_min + 1
Конечно, я буду рад любым комментариям и вопросам. Для этого используйте почту или Telegram.
Больше …
Самое основное, с чего начинается изучение языка — с фраз…
Устали фильтровать данные в excel?
Есть решение, как с помощью Python осуществить поиск строк в файле по ключевым словам в столбцах.
Несомненно, многие из нас в своей работе не раз сталкивались с необходимостью фильтрации данных в файле excel, обычно мы делаем это через встроенный в программу фильтр, но бывают ситуации, когда нужно осуществить отбор строк по большому количеству условий (в нашем случае – по ключевым словам) сразу по нескольким столбцам.
Рассмотрим задачу более подробно. Например, у нас есть файл excel с обращениями клиентов в банк (тысячи строк), который содержит следующие колонки: «ИНН клиента», «Дата обращения», «Обращение», «Решение». В столбце «Обращение» содержится текст обращения клиента, в столбце «Решение» — ответ банка на обращение. Суть обращений может быть абсолютно любой (кредитование, страхование, эквайринг и т.д).
Требуется с помощью поиска ключевых слов/сочетаний слов (например, «КАСКО», «ОСАГО», «автострахов», «залог…авто» и т.п.) в колонках «Обращение» и «Решение» выбрать обращения клиентов, которые относятся к страхованию автотранспорта. Нужные слова могут содержаться как в обоих столбцах, так и в одном из них.
Конечно, можно начать фильтровать данные колонки в excel, но это будет долго и трудоёмко, особенно, если слов для поиска подходящих обращений много (или столбцов, в которых необходимо найти ключевые слова). Поэтому для решения нашей задачи требуется более удобный инструмент – Python.
Ниже представлен код, с помощью которого мы отберем необходимые обращения клиентов:
# Импорт библиотек.
import pandas as pd
import numpy as np
import re
#Чтение исходного файла с данными.
df = pd.read_excel(r’ПУТЬ К ФАЙЛУНазвание исходного файла с данными.xlsx’, dtype=’str’)
# Регулярные выражения.
# Шаблон (слова/сочетания слов, которые необходимо найти в столбцах).
r = r'(каско)|(осаго)|(страх.*?транспорт)|(транспорт.*?страх)|(страх.*?авто)|(авто.*?страх)|(залог.*?транспорт)|(транспорт.*?залог)|(залог.*?авто)|(авто.*?залог)|(автострахов)’
Поясним, что «.*?» в выражении (страх.*?транспорт) ищет между «страх» и «транспорт» любое количество символов, вопросительный знак отключает жадность алгоритма поиска (поиск заканчивается как только находится первый «транспорт»).
#Для каждой строки ищем шаблон в столбце «Обращение».
obr = df[‘Обращение’].apply(lambda x: re.search(r, str(x).lower())) #другой вариант: obr = df[‘ Обращение ‘].str.lower().str.contains(r)
#Для каждой строки ищем шаблон в столбце «Решение».
otvet = df[‘Решение’].apply(lambda x: re.search(r, str(x).lower())) #другой вариант: otvet = df[‘Решение’].str.lower().str.contains(r)
#Для каждой строки проверяем наличие шаблона хотя бы в одном из столбцов «Обращение» и «Решение» (результат — True/False).
itog = np.any(np.array([~obr.isnull(), ~otvet.isnull()]), axis=0)
#Результат (оставляем только те строки в таблице, по которым получен результат True).
new_df = df[itog]
#Запись результата в excel.
new_df.to_excel(‘Название итогового файла.xlsx’, index=False)
В результате получаем новый файл excel, в который полностью скопированы нужные нам обращения клиентов:
— в обращении клиента с ИНН 1111111111 в столбцах «Обращение» и «Решение» содержится слово «КАСКО»;
— в обращении клиента с ИНН 333333333333 в столбце «Решение» содержатся сочетания слов «залог…транспорт», «транспорт…страх», «залог…авто», «страх…авто»;
— в обращении клиента с ИНН 444444444444 в столбце «Обращение» содержатся сочетания слов «страх…транспорт»; «транспорт…залог».
Количество столбцов, в которых можно производить поиск ключевых слов, не ограничен – в приведенном примере их два, но у вас может быть больше.
При необходимости для каждого столбца можно задать свой шаблон для поиска слов:
#Шаблон 1 для столбца «Обращение».
r1= r'(каско)|(осаго)|(страх.*?транспорт)|(транспорт.*?страх)|(страх.*?авто)|(авто.*?страх)’
#Шаблон 2 для столбца «Решение».
r2= r'(залог.*?транспорт)|(транспорт.*?залог)|(залог.*?авто)|(авто.*?залог)|(автострахов)’
#Поиск шаблонов 1 и 2 в столбцах «Обращение» и «Решение» соответственно.
obr = df[‘Обращение’].apply(lambda x: re.search(r1, str(x).lower()))
otvet = df[‘Решение’].apply(lambda x: re.search(r2, str(x).lower()))
Если требуется выбрать строки, в которых ключевые слова содержатся и в том, и в другом столбце, то нужно заменить функцию any() на all():
itog = np.all(np.array([~obr.isnull(), ~otvet.isnull()]), axis=0)
Теперь рассмотрим ситуацию, когда у нас имеется несколько файлов excel с обращениями клиентов (с аналогичной структурой столбцов), и необходимо в каждом выбрать подходящие обращения.
Тогда код, с помощью которого мы отберем нужные строки, будет выглядеть так:
#Импорт библиотек.
import pandas as pd
import numpy as np
import os
import re
import warnings
#Игнорирование всех предупреждений.
warnings.filterwarnings(‘ignore’)
#Путь к папке с исходными файлами.
path = r’ПУТЬ К ПАПКЕ С ФАЙЛАМИ ‘
#Регулярные выражения.
#Шаблон (слова/сочетания слов, которые необходимо найти в столбцах).
r= r'(каско)|(осаго)|(страх.*?транспорт)|(транспорт.*?страх)|(страх.*?авто)|(авто.*?страх)|(залог.*?транспорт)|(транспорт.*?залог)|(залог.*?авто)|(авто.*?залог)|(автострахов)’
#Создание папки, в которую будут сохраняться файлы с нужными обращениями.
os.makedirs(‘Нужные обращения’, exist_ok=True)
#Получение списка полных имён для всех файлов xlsx в папке с исходными файлами.
docs = []
for root, _, files in os.walk(path):
for file in files:
if file.split(‘.’)[-1] == ‘xlsx’:
docs.append(os.path.join(root, file))
print(f’В директории {path} nобнаружено {len(docs)} файлов’)
#Для каждого файла из списка производим его чтение, поиск шаблона в столбцах «Обращение» и «Решение», проверяем наличие шаблона хотя бы в одном из данных столбцов, оставляем только те строки в таблице, по которым получен результат True, записываем результат в excel в папку «Нужные обращения».
%%time
for i, doc in enumerate(docs):
df = pd.read_excel(doc)
print(f'{i+1} файл из {len(docs)} прочитан’, end=’ ‘)
obr = df[‘Обращение’].apply(lambda x: re.search(r, str(x).lower()))
otvet = df[‘Решение’].apply(lambda x: re.search(r, str(x).lower()))
itog = np.any(np.array([~obr.isnull(), ~otvet.isnull()]), axis=0)
df = df[itog]
df.to_excel(os.path.join(‘Нужные обращения’, doc.split(‘\’)[-1]), index=False)
print(‘и обработан’)
В результате создается папка «Нужные обращения», в которой содержатся новые файлы excel с полностью скопированными нужными обращениями клиентов. По количеству и названию данные файлы соответствуют исходным.
Таким образом, благодаря Python поиск строк в файлах по ключевым словам в столбцах становится быстрым и несложным делом. Приведенный код значительно ускоряет и упрощает работу аналитика в части фильтрации строк по большому количеству условий по нескольким столбцам.
I’m trying to search for a word in a cell that has a text string that looks like this (Energy;Green Buildings;High Performance Buildings). Here is the code I wrote, I get a syntax error
for row in ws.iter_rows('D2:D11'):
for cell in row:
if 'Energy' in ws.cell.value :
Print 'yes'
Obviously, I don’t want to print yes, this was to test the search function.
Additionally, I want to get the cell location, and then tell openpyxl to assign a color to a cell in the same row under column E. here is a snap shot of my Excel sheet.
I know how to assign a color using this command
c.fill = PatternFill(start_color='FFFFE0', end_color='FFFFE0'
)
fill_type='solid'
I just need help getting the cell location (the cell that has a matching text) and assign its row number to another cell in column E
UPDATE: I wrote this code below that is working fine for me:
import xml.etree.ElementTree as ET
fhand = open ('My_Collection')
tree =ET.parse('My_Collection.xml')
data= fhand.read()
root = tree.getroot()
tree = ET.fromstring(data)
title_list= ['Title']
year_list = ['Year']
author_list= ['Author']
label_list = ['Label']
for child in tree:
for children in child:
if children.find('.//title')is None :
t='N'
else:
t=children.find('.//title').text
title_list.append(t)
print title_list
print len(title_list)
for child in tree:
for children in child:
if children.find('.//year')is None :
y='N'
else:
y=children.find('.//year').text
year_list.append(y)
print year_list
print len(year_list)
for child in tree:
for children in child:
if children.find('.//author')is None :
a='N'
else:
a=children.find('.//author').text
author_list.append(a)
print author_list
print len(author_list)
for child in tree:
for children in child:
if children.find('label')is None :
l='N'
else:
l=children.find('label').text
label_list.append(l)
print label_list
print len(author_list)
Modified_label_list=list()
import re
for labels in label_list:
all_labels=labels.split(';')
for a_l in all_labels:
if a_l not in Modified_label_list:
Modified_label_list.append(a_l)
else:
continue
print Modified_label_list
print len(Modified_label_list)
label_list_for_col_header= Modified_label_list[1:]
print label_list_for_col_header
print len(label_list_for_col_header)
from openpyxl import Workbook
wb = Workbook()
ws = wb.active
for row in zip(title_list, year_list, author_list, label_list):
ws.append(row)
r = 5
for N in label_list_for_col_header:
ws.cell(row=1, column=r).value = str(N)
r += 1
from openpyxl.styles import PatternFill
general_lst= list()
COLOR_INDEX = ['FF000000', 'FFFFFFFF', 'FFFF0000', 'FF00FF00', 'FF0000FF',
'FFFFFF00', 'FFFF00FF', 'FF00FFFF', 'FF800000', 'FF008000', 'FF000080',
'FF808000', 'FF800080', 'FF008080', 'FFC0C0C0', 'FF808080', 'FF9999FF',
'FF993366', 'FFFFFFCC', 'FFCCFFFF', 'FF660066', 'FFFF8080', 'FF0066CC',
'FFCCCCFF', 'FF000080', 'FFFF00FF', 'FFFFFF00', 'FF00FFFF', 'FF800080',
'FF800000', 'FF008080', 'FF0000FF', 'FF00CCFF', 'FFCCFFFF', 'FFCCFFCC',
'FFFFFF99', 'FF99CCFF', 'FFFF99CC', 'FFCC99FF', 'FFFFCC99', 'FF3366FF',
'FF33CCCC', 'FF99CC00', 'FFFFCC00', 'FFFF9900', 'FFFF6600', 'FF666699',
'FF969696', 'FF003366', 'FF339966', 'FF003300', 'FF333300', 'FF993300',
'FF993366', 'FF333399', 'FF333333']
import random
color_lst= random.sample(COLOR_INDEX, len(label_list_for_col_header))
print color_lst
print int(label_list_for_col_header.index(label_list_for_col_header[0]))
h= len(title_list)
m= 0
for lbls in label_list_for_col_header:
j= int(label_list_for_col_header.index(lbls))+5
for row in ws.iter_rows('D2:D11'):
for cell in row:
if lbls in cell.value :
general_lst.append(cell.row)
for items in range(len(general_lst)):
ws.cell(row = general_lst[items], column = j).fill = PatternFill(start_color=str(color_lst[m]), end_color=str(color_lst[m]) , fill_type='solid')
general_lst = []
m +=1
ws.column_dimensions['A'].width = 70
ws.column_dimensions['C'].width = 23
ws.column_dimensions['B'].width = 5
wb.save("Test61.xlsx")
Доброго времени суток.
Пишу в отчаянии.
Уже несколько суток пытаюсь освоить хоть что-нибудь (openpyxl, xlsxwriter, xlrd-xlwt…) что поможет мне выполнить следующий, казалось бы простой алгоритм:
- Открыть Excel файл.
- Найти в определенном столбце ячейку совпадающую с заранее заданным словом (на русском языке).
- Скопировать всю строку вместе с этой ячейкой и всеми данными в этой строке (ряду).
- Создать новый файл Excel и записать туда все это (все ряды, в которых нашлось то заранее заданное слово).
Попробовал ровно каждый из модулей. В одних жуткие траблы с получением данных из строки, другие не воспринимают русский язык в ячейках, третьи вообще отказываются работать…
Вот допустим последний неудавшийся пример с использованием win32com:
import win32com.client
Excel = win32com.client.Dispatch("Excel.Application")
text = 'Блендер'
counter = 2
def write(val, pos):
wb = Excel.Workbooks.Add()
ws = wb.ActiveSheet
i = 1
for rec in val:
ws.Cells(pos,i).value = rec
i = i + 1
wb.SaveAs('test.xlsx')
wb.Close()
Excel.Quit()
def search():
wb = Excel.Workbooks.Open(u'C:/Users/User/Desktop/excel.xlsx')
sheet = wb.ActiveSheet
srch = [r[0].value for r in sheet.Range("B2:B13")]
for items in srch:
if text in items:
global counter
print ('Found')
found = sheet.Range("A%s:D%s" % (counter,counter)).Value
print (found)
write(found,counter)
counter += 1
search()
Наверняка этот код настолько неидеален, насколько это вообще возможно.
Но пусть там будет хоть овер999 костылей, лишь бы работало, а он не работает даже с этим — при виде русскоязычного текста впадает истерику и кричит ‘OLE error NONE NONE’. А даже без русских символов один фиг записывает только первую ячейку.
Буду бесконечно рад любой помощи.
Last updated on
Feb 10, 2022
Do you need to search and replace a list of values in a big Excel file with many sheets?
If so, I’ll show you the steps to search in Excel file — list of words and replace them. In this article you can find the exact cell(with packages like xlrd, xlwt and openpyxl) and partial cell match. At the end a new Excel file is generated with the replaced values.
Let’s check the example data:
A | B | C |
---|---|---|
4321 | 3210 | 2100 |
1 | 0 | 0 |
2 | 1 | 0 |
3 | 2 | 1 |
4 | 3 | 2 |
we are going to search for 0 and 1 — and replace them with False and True.
A | B | C |
---|---|---|
4321 | 3210 | 2100 |
True | False | False |
2 | True | False |
3 | 2 | True |
4 | 3 | 2 |
You can check also this video:
Easily extract information from Excel with Python and Pandas
Python and Excel — search and replace with xlrd and xlwt
In this example we are going to use two Python packages: xlrd
and xlwt
.
Step 1: Read Excel file
The first package reads the Excel file and a given sheet by name or index:
import xlwt
import xlrd
# read Excel file and sheet by name
workbook = xlrd.open_workbook('/home/vanx/Documents/example1.xlsx')
sheet = workbook.sheet_by_name('Test')
sheet2 = workbook.sheet_by_index(2)
Step 2: Create new Excel file
The second package — xlwt
— will be used to write the data into new Excel file:
new_workbook = xlwt.Workbook()
new_sheet = new_workbook.add_sheet('Test')
Step 3: Search and replace a cell in xlsx file
The next step is to define replacement pairs like: {1:True, 0:False}
:
replacement = {1:True, 0:False}
Step 4: Search and replace a cell in xlsx file
Finally the code iterates over the rows and columns is controlled by:
ncols
— number of columns in the selected sheetnrows
— number of rows in the selected sheet
This is the final part of the code:
# iterate over the rows
for i in range(sheet.nrows):
print(i)
data = [sheet.cell_value(i, col) for col in range(sheet.ncols)]
for index, value in enumerate(data):
if value in replacement.keys():
new_sheet.write(i, index, str(replacement.get(value)))
else:
new_sheet.write(i, index, value)
new_workbook.save('example.xls')
where new_workbook.save('example.xlsx')
saves the data into file — example.xlsx
Python and Excel — search and replace with openpyxl
Another Python package exists and can be used — openpyxl
. It can do the same as the previous example. Difference is that only one module is used for reading and writing new Excel file:
import openpyxl
from openpyxl.utils.cell import get_column_letter
wb = openpyxl.load_workbook('/home/vanx/Documents/example1.xlsx')
wb.sheetnames
sheet = wb["Test"]
number_rows = sheet.max_row
number_columns = sheet.max_column
replacement = {'1':True, '0':False}
for i in range(number_columns):
for k in range(number_rows):
cell = str(sheet[get_column_letter(i+1)+str(k+1)].value)
for key in replacement.keys():
if str(cell) == key:
newCell = replacement.get(key)
sheet[get_column_letter(i+1)+str(k+1)] = str(newCell)
wb.save('example1.xlsx')
The code above reads file: example1.xlsx
from folder ~/Documents
and then produces a new Excel file in the current working directory. In the file there are several sheets — we are interested in the one named — Test
.
Getting the number of rows and columns is done by:
sheet.max_row
sheet.max_column
Finally we iterate and search for the values. In case of a match then we will replace the cell with the new values.
Python and Excel — partial match
The previous examples work with exact text matches for the cell value. If you need to perform partial match than you can try with Python code like:
if str(cell[0]) == key:
This will search only the first character of the cell if it’s exactly the searched value.
Or if the cell contains the key:
if key in str(cell[0]):
Regex can be used as well. The problem for such partial matches is performance — it might take resources and time for large Excel files.