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

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

Запись от nekit270 размещена 11.12.2023 в 02:42
Показов 2284 Комментарии 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
Просмотров: 261
Размер:	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
Комментарии
 
Новые блоги и статьи
Был там один разговор по поводу свободы в материальном мире.
kumehtar 19.08.2026
Суть: рассматривается живое существо, оказавшееся внутри довольно странной системы (этого мира) и пытающееся обустроить в ней свой кусок пространства. Жизнь действительно предъявляет каждому. . .
Когда логика программы не спасает от человеческих ошибок
Maks 18.08.2026
В последнее время всё чаще и чаще сталкиваюсь с таким явлением, как абсолютная невнимательность (или глупость) пользователей. Проявляется это чаще всего на работе в коллективе. Допустим, человек с. . .
Лето уходит
kumehtar 17.08.2026
Мысли в слух
kumehtar 17.08.2026
Забавно, насколько сейчас стала доступна информация. Например о магии, духовном развитии, медитациях, и других подобных направлениях, ранее зачастую тайных, передаваемых от учителя к ученику. Хотя. . .
Перемещение строк из ТЧ в другой документ с учетом текущего пробега
Maks 17.08.2026
Реализация из решения ниже выполнена на примере нетипового документа "Автозапчасти", с ТЧ "Шины". За основу взят алгоритм отсюда: https:/ / www. cyberforum. ru/ blogs/ 359708/ 10838. html Задача: . . .
Саморегулирующийся социальный контракт для сервера cross-section.
Hrethgir 14.08.2026
С кодом конечно таких глубоких размышлений пока не было, впрочем я уже привык к алгоритмизации. Суть предмета записи: снова в диалоге с нейросетью (я взял пока себе ник для учётки админа - Rector). . . .
Часы электронные
Uhbif79 12.08.2026
Выкладываю программу часов. Программа позволяет: 1. Использовать системное время и дату, 2. Есть возможность вводить время и дату вручную. 3. Реализованы 2 будильника: начало и конец рабочего дня. . . .
Часы с будильником на основе класса QLCDNumber
Uhbif79 12.08.2026
Всем добрый день, выкладываю программу часов с будильником на основе класса QLCDNumber. Здесь я пробовал самостоятельно создавал классы, впервые столкнулся с видимостью переменной одного класса из. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru