Форум программистов, компьютерный форум, киберфорум
nekit270
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
Добро пожаловать, здесь я программирую бессмысленно и беспощадно

Чтение из XLSX-файла с помощью Python

Запись от nekit270 размещена 11.12.2023 в 02:42
Показов 2152 Комментарии 0
Метки excel, python, xlsx

Вдохновившись этой статейкой от sqltd1, решил написать на питончике скрипт для чтения данных из ячейки XLSX-файла.

Но не просто написать скрипт, а сделать это без внешних библиотек и всего прочего.


Формат XLSX

XLSX представляет собой zip-архив. Для извлечения значений нужны два файла из него:
/xl/worksheets/<лист>.xml - собственно лист
/xl/sharedStrings.xml - строки


Извлечение значений

Для распаковки использую модуль zipfile, а в качестве простенького XML-парсера подойдут регулярные выражения.

Код класса (42 строки, поэтому под спойлером):
Кликните здесь для просмотра всего текста

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import zipfile, re
 
class XlsxReader:
    __worksheet = None
    __strings = []
 
    def __init__(self, file, worksheet):
        # Открытие XLSX-файла как ZIP-архива
        with zipfile.ZipFile(file) as zip:
            # Чтение файла листа из архива
            self.__worksheet = zip.read(f'xl/worksheets/{worksheet}.xml').decode('utf-8')
 
            # Чтение файла хранилища строк из архива
            strings_file = zip.read('xl/sharedStrings.xml').decode('utf-8')
 
            # Добавление строк в список
            for match in re.finditer('\\<si\\>\\<t\\>([^\\<]+)\\</t\\>\\</si\\>', strings_file):
                self.__strings.append(match.group(1))
 
    def read(self, cell):
        # Если в документе есть строковые значения
        if len(self.__strings) > 0:
            # Поиск элемента <c r="ячейка" t="s"><v>индекс</v></c>
            s_match = re.search(f'\\<c r="{cell}" t="s"\\>\\<v\\>([^\\<]+)\\</v\\>\\</c\\>', self.__worksheet)
 
            # Если элемент найден
            if(s_match != None and len(s_match.groups()) > 0):
                # Найти строку в списке по индексу и вернуть
                return self.__strings[int(s_match.group(1))]
 
        # В документе нет строковых значений
 
        # Поиск элемента <c r="ячейка"><v>значение</v></c>
        n_match = re.search(f'\\<c r="{cell}"\\>\\<v\\>([^\\<]+)\\</v\\>\\</c\\>', self.__worksheet)
 
        # Если элемент найден
        if(n_match != None and len(n_match.groups()) > 0):
            # Вернуть его
            return n_match.group(1)
        
        # Если ничего не найдено, вернуть None
        return None


Пример использования:
Python
1
2
3
4
5
6
7
from xlsx_reader import XlsxReader
 
reader = XlsxReader('test.xlsx', 'sheet1')
print('A1', reader.read('A1'))
print('B2', reader.read('B2'))
print('B8', reader.read('B8'))
print('D6', reader.read('D6'))
Тестировал я на этом файле:
Нажмите на изображение для увеличения
Название: Снимок экрана 2023-12-11 022747.png
Просмотров: 234
Размер:	8.6 Кб
ID:	8395
test.xlsx

Результат:
Code
1
2
3
4
A1 5
B2 92
B8 String2
D6 TestString

Версия без комментариев (для пущей экономии места и использования в качестве библиотеки):
Кликните здесь для просмотра всего текста

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import zipfile, re
 
class XlsxReader:
    __worksheet = None
    __strings = []
 
    def __init__(self, file, worksheet):
        with zipfile.ZipFile(file) as zip:
            self.__worksheet = zip.read(f'xl/worksheets/{worksheet}.xml').decode('utf-8')
 
            strings_file = zip.read('xl/sharedStrings.xml').decode('utf-8')
 
            for match in re.finditer('\\<si\\>\\<t\\>([^\\<]+)\\</t\\>\\</si\\>', strings_file):
                self.__strings.append(match.group(1))
 
    def read(self, cell):
        if len(self.__strings) > 0:
            s_match = re.search(f'\\<c r="{cell}" t="s"\\>\\<v\\>([^\\<]+)\\</v\\>\\</c\\>', self.__worksheet)
 
            if(s_match != None and len(s_match.groups()) > 0):
                return self.__strings[int(s_match.group(1))]
 
        n_match = re.search(f'\\<c r="{cell}"\\>\\<v\\>([^\\<]+)\\</v\\>\\</c\\>', self.__worksheet)
 
        if(n_match != None and len(n_match.groups()) > 0):
            return n_match.group(1)
        
        return None


Внимание! Даже если тип значения в XLSX-файле - не строка, возвращено будет значение типа str. Это сделано специально, чтобы вызывающий мог сам конвертировать его в нужный тип числа.

P.S. Обратите внимание, что, к примеру, "Лист 1" называется "sheet1" внутри XLSX-файла. Использовать нужно именно "внутреннее" название.
Метки excel, python, xlsx
Размещено в Без категории
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 0
Комментарии
 
Новые блоги и статьи
Debian 13: Установка Lazarus QT5
ВитГо 09.05.2026
Эта инструкция моя компиляция инструкций volvo https:/ / www. cyberforum. ru/ blogs/ 203668/ 10753. html и его же старой инструкции по установке Lazarus с gtk2. . .
Нейросеть на алгоритме "эстафета хвоста" как перспектива.
Hrethgir 06.05.2026
На десерт, когда запущу сервер. Статья тут https:/ / habr. com/ ru/ articles/ 1030914/ . Автор я сам, нейросеть только помогает в вопросах которые мне не известны - не знаю людей которые знали-бы. . .
Асинхронный приём данных из COM-порта
Argus19 01.05.2026
Асинхронный приём данных из COM-порта Купил на aliexpress термопринтер QR701. Он оказался странным. Поключил к Arduino Nano. Был очень удивлён. Наотрез отказывается печатать русские буквы. Чтобы. . .
попытка написать игровой сервер на C++
pyirrlicht 29.04.2026
попытка написать игровой сервер на плюсах с открытым бесконечным миром. возможно получится прикрутить интерпретатор питон для кастомизации игровой логики. что есть на текущий момент:. . .
Контроль уникальности выбранного документа-основания при изменении реквизита
Maks 28.04.2026
Алгоритм из решения ниже разработан на примере нетипового документа "ЗаявкаНаРемонтСпецтехники", разработанного в КА2. Задача: уведомлять пользователя, если указанная заявка (документ-основание). . .
Благородство как наказание
Maks 24.04.2026
У хорошего человека отношения с женщинами всегда складываются трудно. А я человек хороший. Заявляю без тени смущения, потому что гордиться тут нечем. От хорошего человека ждут соответствующего. . .
Валидация и контроль данных табличной части документа перед записью
Maks 22.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа, разработанного в КА2. Задача: контроль и валидация данных табличной части документа перед записью с учетом регламента компании. . .
Отчёт о затраченных материалах за определенный период с макетом печатной формы
Maks 21.04.2026
Отчёт из решения ниже размещён в конфигурации КА2. Задача: разработка отчёта по затраченным материалам за определённый период, с возможностью вывода печатной формы отчёта с шапкой и подвалом. В. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru