Как распарсить файл excel

Есть excel-файлы, несколько сотен.
Из них нужно как-то извлечь некоторые строки, по заданному принципу (текст в них отличается).
И залить эти строки в один новый экселевский файл.
Можно сделать руками, но лень. И еще есть вариант, что данная задача будет периодически повторяться.
Подскажите, пожалуйста, какими инструментами лучше это программно сделать? Автоматически по очереди пооткрывать все файлы в директории, пропарсить, взять нужные строки, залить в новый файл.
Может, был у кого похожий опыт.
Я начал смотреть в сторону python и www.python-excel.org

Может лучше сделать это visual basic’ом? Или вообще в самом экселе есть такая возможность?
Спасибо!

P.S. Все сделал так: сперва нашел плагин для эксель, бесплатно и быстро сливающий много эксель файлов в один. Вот он.
Затем искал конкретные макросы, удаляющие строки по различным критериям, типа — пустая ячейка, текст в ячейке, цифры в ячейке.
В общем, даже не пришлось сильно разбираться с VBA, все сделал готовыми средствами.

Пример с использованием модуля Pandas:

import pandas as pd   # pip install pandas

df = pd.read_excel(r'D:download1.xls', sheet_name='Лист1')
print(df)

вывод:

  Артикул Наименование  Тариф (прайс) на 12.06.83
0    а123      Товар А                        100
1    б123      Товар Б                        200
2    в123      Товар В                        300

в виде обычных Vanilla Python списков или Numpy Array:

In [20]: df['Артикул'].tolist()
Out[20]: ['а123', 'б123', 'в123']

In [21]: df.values
Out[21]:
array([['а123', 'Товар А', 100],
       ['б123', 'Товар Б', 200],
       ['в123', 'Товар В', 300]], dtype=object)

In [22]: df.values.tolist()
Out[22]: [['а123', 'Товар А', 100], ['б123', 'Товар Б', 200], ['в123', 'Товар В', 300]]

In [23]: df.T.values.tolist()
Out[23]: [['а123', 'б123', 'в123'], ['Товар А', 'Товар Б', 'Товар В'], [100, 200, 300]]

PS Pandas поддерживает работу с XLSX и XLS форматами и умеет использовать следующие модули:

  • xlrd, xlwt
  • openpyxl
  • xlsxwriter

Парсер поддерживает следующие типы файлов Excel:

  • .xls, .xlsx, xlsm, .xlsb и любые другие таблицы
  • файлы .csv можно парсить как файлы Excel и как текстовые файлы (зависит от задачи)

Для сбора данных из файлов Excel применяется стандартный алгоритм парсера файлов, но есть и некоторые нюансы:

  1. Для открытия файла используется действие «Открыть файл в Excel», с параметром «Режим» равным 2 — ReadOnly (если планируется только загрузка данных из файла, без внесения изменений в обрабатываемый файл):
    Действие Параметр Значение
    Открыть файл в Excel Путь к открываемому файлу  
    Режим 2 — ReadOnly
  2. ВАЖНО: Требуется принудительно закрывать обрабатываемые файлы Excel (так как файл остаётся открытым в процессе извлечения из него данных)

    Поскольку в исходных данных прописана только команда открытия файла, а команду закрытия там же прописать возможности нет, — команду закрытия добавляем в спец. набор действий с названием Parser_AfterLastLevel (он срабатывает на последнем подуровне после вывода на лист):

    Действие Параметр Значение
    Закрыть книгу Excel Режим 2 — ранее открытый парсером
  3. Для извлечения данных с листа используется действие «Поиск ячеек на листе».
    Оно позволяет искать на листе нужные ячейки, ориентируясь на значения соседних ячеек (например, найти на листе ячейку с заданным текстом, отступить от неё вниз/вправо/влево/вверх на заданное количество строк/столбцов, и из этой ячейки считать значение / ссылку / примечание)
    Это же действие позволяет вносить коррективы в файл перед сбором данных (например, перенести значения из одного столбца в другой, удалить лишние столбцы, посчитать количество заполненных ячеек в диапазоне, и т.п.)

Примеры настройки парсера файлов Excel можно найти в каталоге парсеров файлов:

  • парсер таблиц Excel

В процессе анализа информации часто возникает потребность в обработке данных из документов в форматах MS Word или Excel. Как считывать информации из таких файлов с использованием языка C #.

Из практического опыта сотрудника, который всегда успешно решает поставленные задачи.

Для работы с файлами Word и Excel я решил выбрать библиотеки Microsoft.Office.Interop.Word и Microsoft.Office.Interop.Excel, предоставляющие программные интерфейсы для взаимодействия с объектами MS Word и Excel.

Преимущества использования этих библиотек:

  • созданы корпорацией Microsoft, следовательно, взаимодействие с объектами программ пакета MS Office реализовано наиболее оптимально,
  • нужный пакет Visual Studio Tool for Office поставляется вместе с Visual Studio (достаточно отметить его при установке VS).

Также следует заметить, что у такого похода есть и недостаток: для того, чтобы написанная программа работала на ПК пользователя необходимо, чтобы на нём были установлены программы MS Office и MS Excel. Поэтому такой подход плохо подходит для серверных решений. Также такая программа не будет являться кроссплатформенной.

Добавление библиотек в проект Visual Studio

Библиотеки поставляются вместе с пакетом Visual Studio Tool for Office (платформа .NET Framework).

Для использования библиотеки нужно:

  • добавить ссылку на неё: в обозревателе решений необходимо кликнуть правой кнопкой мыши по пункту Ссылки (Рис. 1) и найти нужную библиотеку по ключевым словам (после добавления ссылка появится в списке),
  • указать используемое пространство имён в файле программы (в примере ему назначен алиас Word): (Рис. 2):
Пример парсинга файла MS Word​

Можно прочитать основные форматы: .doc,. docx,. rtf.

Ниже приведён листинг с примером считывания текста из документа MS Word:

object FileName = @»C:test.doc»;
object rOnly = true;
object SaveChanges = false;
object MissingObj = System.Reflection.Missing.Value;

Word.Application app = new Word.Application();
Word.Document doc = null;
Word.Range range = null;
try
{
doc = app.Documents.Open(ref FileName, ref MissingObj, ref rOnly, ref MissingObj,
ref MissingObj, ref MissingObj, ref MissingObj, ref MissingObj,
ref MissingObj, ref MissingObj, ref MissingObj, ref MissingObj,
ref MissingObj, ref MissingObj, ref MissingObj, ref MissingObj);

object StartPosition = 0;
object EndPositiojn = doc.Characters.Count;
range = doc.Range(ref StartPosition, ref EndPositiojn);

// Получение основного текста со страниц (без учёта сносок и колонтитулов)
string MainText = (range == null || range.Text == null) ? null : range.Text;
if (MainText != null)
{
/* Обработка основного текста документа*/
}

// Получение текста из нижних и верхних колонтитулов
foreach (Word.Section section in doc.Sections)
{
// Нижние колонтитулы
foreach (Word.HeaderFooter footer in section.Footers)
{
string FooterText = (footer.Range == null || footer.Range.Text == null) ? null : footer.Range.Text;
if (FooterText != null)
{
/* Обработка текста */
}
}

// Верхние колонтитулы
foreach (Word.HeaderFooter header in section.Headers)
{
string HeaderText = (header.Range == null || header.Range.Text == null) ? null : header.Range.Text;
if (HeaderText != null)
{
/* Обработка текста */
}
}
}
// Получение текста сносок
if (doc.Footnotes.Count != 0)
{
foreach (Word.Footnote footnote in doc.Footnotes)
{
string FooteNoteText = (footnote.Range == null || footnote.Range.Text == null) ? null : footnote.Range.Text;
if (FooteNoteText != null)
{
/* Обработка текста */
}
}
}
} catch (Exception ex)
{
/* Обработка исключений */
}
finally
{
/* Очистка неуправляемых ресурсов */
if(doc != null)
{
doc.Close(ref SaveChanges);
}
if(range != null)
{
Marshal.ReleaseComObject(range);
range = null;
}
if(app != null)
{
app.Quit();
Marshal.ReleaseComObject(app);
app = null;
}
}

Примечания:

  • в коде приводится пример считывания основного текста документа, текста верхних и нижних колонтитулов, а также текста сносок,
  • в коде производится очистка неуправляемых ресурсов с использованием класса Marshal

Пример парсинга файла MS Excel

Можно прочитать основные форматы: .xls,. xlsx.

Ниже приведён листинг с примером считывания текста из документа MS Excel (по ячейкам):

string FileName = @»C:UsersbeeDownloadstest.xlsx»;
object rOnly = true;
object SaveChanges = false;
object MissingObj = System.Reflection.Missing.Value;

Excel.Application app = new Excel.Application();
Excel.Workbooks workbooks = null;
Excel.Workbook workbook = null;
Excel.Sheets sheets = null;
try
{
workbooks = app.Workbooks;
workbook = workbooks.Open(FileName, MissingObj, rOnly, MissingObj, MissingObj,
MissingObj, MissingObj, MissingObj, MissingObj, MissingObj,
MissingObj, MissingObj, MissingObj, MissingObj, MissingObj);

// Получение всех страниц докуента
sheets = workbook.Sheets;

foreach(Excel.Worksheet worksheet in sheets)
{
// Получаем диапазон используемых на странице ячеек
Excel.Range UsedRange = worksheet.UsedRange;
// Получаем строки в используемом диапазоне
Excel.Range urRows = UsedRange.Rows;
// Получаем столбцы в используемом диапазоне
Excel.Range urColums = UsedRange.Columns;

// Количества строк и столбцов
int RowsCount = urRows.Count;
int ColumnsCount = urColums.Count;
for(int i = 1; i <= RowsCount; i++)
{
for(int j = 1; j <= ColumnsCount; j++)
{
Excel.Range CellRange = UsedRange.Cells[i, j];
// Получение текста ячейки
string CellText = (CellRange == null || CellRange.Value2 == null) ? null :
(CellRange as Excel.Range).Value2.ToString();

if(CellText != null)
{
/* Обработка текста */
}
}
}
// Очистка неуправляемых ресурсов на каждой итерации
if (urRows != null) Marshal.ReleaseComObject(urRows);
if (urColums != null) Marshal.ReleaseComObject(urColums);
if (UsedRange != null) Marshal.ReleaseComObject(UsedRange);
if (worksheet != null) Marshal.ReleaseComObject(worksheet);
}
} catch (Exception ex)
{
/* Обработка исключений */
}
finally
{
/* Очистка оставшихся неуправляемых ресурсов */
if (sheets != null) Marshal.ReleaseComObject(sheets);
if (workbook != null)
{
workbook.Close(SaveChanges);
Marshal.ReleaseComObject(workbook);
workbook = null;
}

if (workbooks != null)
{
workbooks.Close();
Marshal.ReleaseComObject(workbooks);
workbooks = null;
}
if (app != null)
{
app.Quit();
Marshal.ReleaseComObject(app);
app = null;
}
}

Примечания:

  • при обработке текста каждой ячейки приходится заранее знать количество задействованных строк и столбцов на текущем листе документа,
  • такой перебор не совсем оптимален (временная сложность алгоритма O(n2)): при желании его можно ускорить (например, разбив обработку на несколько потоков): в данной статье приводится лишь пример получения текста из каждой ячейки,
  • при таком переборе ячеек необходимо на каждой итерации освобождать неуправляемые ресурсы, чтобы избежать утечек памяти (аналогично предыдущему примеру, используется класс Marshal).

Приведенные примеры хорошо подходят для реализации приложения по обработке документов Word и Excel на платформе .NET Framework.

С помощью указанных библиотек можно не только читать текст из документов, но и создавать новые файлы форматов MS Word и Excel.

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

00001.jpg

А состоит этот способ в использовании библиотеки pandas. Конечно же, ее простой не назовешь. Это очень мощный инструмент для аналитики самых разнообразных данных. И в рассмотренном ниже случае мы лишь коснемся небольшого фрагмента из того, что вообще умеет делать эта библиотека.

Что понадобиться?

Для того, чтобы написать данный скрипт нам понадобиться конечно же сам pandas. Библиотеки requests, BeautifulSoup и lxml. А также модуль для записи файлов в формате xlsx – xlsxwriter. Установить их все можно одной командой:

pip install requests bs4 lxml pandas xlsxwriter

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

Python:

import requests
from bs4 import BeautifulSoup

import pandas as pd

Так же с сайта, на котором расположены целевые таблицы нужно взять заголовки для запроса. Данные заголовки не нужны для pandas, но нужны для requests. Зачем вообще использовать в данном случае запросы? Тут все просто. Можно и не использовать вовсе. А полученные таблицы при сохранении называть какими-нибудь составными именами, вроде «Таблица 1» и так далее, но гораздо лучше и понятнее, все же собрать данные о том, как называется данная таблица в оригинале. Поэтому, с помощью запросов и библиотеки BeautifulSoup мы просто будем искать название таблицы.

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

Python:

headers = {
    'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.174 '
                  'YaBrowser/22.1.3.942 Yowser/2.5 Safari/537.36',
    'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,'
              'application/signed-exchange;v=b3;q=0.9 '
}

Теперь нужен список, в котором будут перечисляться года, которые представлены в виде таблиц на сайте. Эти года получаются из псевдовыпадающего списка. Я не стал использовать selenium для того, чтобы получить их со страницы. Так как обычный запрос не может забрать эти данные. Они подгружаются с помощью JS скриптов. В данном случае не так уж много данных, которые надо обработать руками. Поэтому я создал список, в которые эти данные и внес вручную:

Python:

num_year_dict = ['443', '442', '441', '440', '439', '438', '437', '436', '435', '434', '433', '432', '431', '426',
                 '425', '1', '2', '165', '884', '1851', '3226', '4385', '4959', '5582', '6297', '6886', '7371',
                 '8071', '8671']

Теперь нам нужно будет создать пустой словарь вне всяких циклов. Именно, чтобы он был глобальной переменной. Этот словарь мы и будем наполнять полученными данными, а также сохранять их него данные в таблицу Excel. Поэтому, я подумал, что проще сделать его глобальной переменной, чем тасовать из функции в функцию.

df = {}

Назвал я его df, потому как все так называют. И увидев данное название в нужном контексте становиться понятно, что используется pandas. df – это сокращение от DataFrame, то есть, определенный набор данных.

Ну вот, предварительная подготовка закончена. Самое время получать данные. Давайте для начала сходим на одну страницу с таблицей и попробуем получить оттуда данные с помощью pandas.

tables = pd.read_html('https://www.sports.ru/rfpl/table/?s=443&table=0&sub=table')

Здесь была использована функция read_html. Pandas использует библиотеку для парсинга lxml. То есть, примерно это все работает так. Получаются данные со страницы, а затем в коде выполняется поиск с целью найти все таблицы, у которых есть тэг <table>, а далее, внутри таблиц ищутся заголовки и данные под тэгами <tr> и <td>, которые и возвращаются в виде списка формата DataFrame.

Давайте выполним запрос. Но вот печатать данные пока не будем. Нужно для начала понять, сколько таблиц нашлось в запросе. Так как на странице их может быть несколько. Помимо той, что на виду, в виде таблиц может быть оформлен подзаголовок или еще какая информация. Поэтому, давайте узнаем, сколько элементов списка содержится в запросе, а соответственно, столько и таблиц. Выполняем:

print(len(tables))

И видим, что найденных таблиц две. Если вывести по очереди элементы списка, то мы увидим, что нужная нам таблица, в данном случае, находиться под индексом 1. Вот ее и распечатаем для просмотра:

print(tables[1])

И вот она полученная таблица:

screenshot1.png

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

tables[1].drop('Unnamed: 0', axis=1, inplace=True)

На то, что нужно удалить столбец указывает параметр axis, который равен 1. Если бы нужно было удалить строку, он был бы равен 0. Ну и указываем название столбца, который нужно удалить. Параметр inplace в значении True указывает на то, что удалить столбец нужно будет в исходных данных, а не возвращать нам их копию с удаленным столбцом.

А теперь нужно получить заголовок таблицы. Поэтому, делаем запрос к странице, получаем ее содержимое и отправляем для распарсивания в BeautifulSoup. После чего выполняем поиск названия и обрезаем из него все лишние данные.

Python:

url = f'https://www.sports.ru/rfpl/table/?s={num}&table=0&sub=table'
req = requests.get(url=url, headers=headers)
soup = BeautifulSoup(req.text, 'lxml')
title_table = soup.find('h2', class_='titleH3').text.split("-")[2].strip().replace("/", "_")

Теперь, когда у нас есть таблица и ее название, отправим полученные значения в ранее созданный глобально словарь.

df[title_table] = tables[1]

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

Python:

def get_pd_table():
    for num in num_year_dict:
        url = f'https://www.sports.ru/rfpl/table/?s={num}&table=0&sub=table'
        req = requests.get(url=url, headers=headers)
        soup = BeautifulSoup(req.text, 'lxml')
        title_table = soup.find('h2', class_='titleH3').text.split("-")[2].strip().replace("/", "_")
        print(f'Получаю данные из таблицы: "{title_table}"...')
        tables = pd.read_html(url)
        tables[1].drop('Unnamed: 0', axis=1, inplace=True)
        df[title_table] = tables[1]

Итак, когда цикл пробежится по всем ссылкам у нас будет готовый словарь с данными турниров, которые желательно бы записать на отдельные листы. На каждом листе по таблице. Давайте сразу создадим для этого функцию pd_save().

writer = pd.ExcelWriter('./Турнирная таблица ПЛ РФ.xlsx', engine='xlsxwriter')

Создаем объект писателя, в котором указываем имя записываемой книги, и инструмент, с помощью которого будем производить запись в параметре engine=’xlsxwriter’.

После запускаем цикл, в котором создаем объекты, то есть листы для записи из ключей списка с таблицами df, указываем, с помощью какого инструмента будет производиться запись, на какой лист. Имя листа берется из ключа словаря. А также указывается параметр index=False, чтобы не сохранялись индексы автоматически присваиваемые pandas.

df[df_name].to_excel(writer, sheet_name=df_name, index=False)

Ну и после всего сохраняем книгу:

writer.save()

Полный код функции сохранения значений:

Python:

def pd_save():
    writer = pd.ExcelWriter('./Турнирная таблица ПЛ РФ.xlsx', engine='xlsxwriter')
    for df_name in df.keys():
        print(f'Записываем данные в лист: {df_name}')
        df[df_name].to_excel(writer, sheet_name=df_name, index=False)
    writer.save()

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

print(f'Получаю данные из таблицы: "{title_table}"...')

И во вторую функцию, с сообщением о том, данные на какой лист записываются в данный момент.

print(f'Записываем данные в лист: {df_name}')

Ну, а дальше идет функция main, в которой и вызываются вышеприведенные функции. Все остальное, в виде принтов, это просто декорации, для того чтобы пользователь видел, что происходят какие-то процессы.

Python:

import requests
from bs4 import BeautifulSoup

import pandas as pd

headers = {
    'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.174 '
                  'YaBrowser/22.1.3.942 Yowser/2.5 Safari/537.36',
    'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,'
              'application/signed-exchange;v=b3;q=0.9 '
}

num_year_dict = ['443', '442', '441', '440', '439', '438', '437', '436', '435', '434', '433', '432', '431', '426',
                 '425', '1', '2', '165', '884', '1851', '3226', '4385', '4959', '5582', '6297', '6886', '7371',
                 '8071', '8671']

df = {}


def get_pd_table():
    for num in num_year_dict:
        url = f'https://www.sports.ru/rfpl/table/?s={num}&table=0&sub=table'
        req = requests.get(url=url, headers=headers)
        soup = BeautifulSoup(req.text, 'lxml')
        title_table = soup.find('h2', class_='titleH3').text.split("-")[2].strip().replace("/", "_")
        print(f'Получаю данные из таблицы: "{title_table}"...')
        tables = pd.read_html(url)
        tables[1].drop('Unnamed: 0', axis=1, inplace=True)
        df[title_table] = tables[1]


def pd_save():
    writer = pd.ExcelWriter('./Турнирная таблица ПЛ РФ.xlsx', engine='xlsxwriter')
    for df_name in df.keys():
        print(f'Записываем данные в лист: {df_name}')
        df[df_name].to_excel(writer, sheet_name=df_name, index=False)
    writer.save()


def main():
    get_pd_table()
    print(' ')
    pd_save()
    print('n[+] Данные записаны!')


if __name__ == '__main__':
    main()

И ниже результат работы скрипта с уже полученными и записанными таблицами:

screenshot2.png

Как видите, использовать библиотеку pandas, по крайней мере в данном контексте, не очень сложно. Конечно же, это только самая малая часть того, что она умеет. А умеет она собирать и анализировать данные из самых разных форматов, включая такие распространенные, как: cvs, txt, HTML, XML, xlsx.

Ну и думаю, что не всегда данные будут прилетать «чистыми». Скорее всего, периодически будут попадаться мусорные столбцы или строки. Но их не особо то трудно удалить. Нужно только понимать, что и откуда.

В общем, для себя я сделал однозначный вывод – если мне понадобиться парсить табличные значения, то лучше, чем использование pandas, пожалуй и не придумаешь. Можно просто на лету формировать данные из одного формата и переводить тут же в другой без утомительного перебора. К примеру, из формата csv в json.

Спасибо за внимание. Надеюсь, что данная информация будет вам полезна

Понравилась статья? Поделить с друзьями:

А вот еще интересные статьи:

  • Как распечатать word не с первой страницы
  • Как распарсить текст в excel
  • Как распечатать word в изображение
  • Как распарсить таблицу excel
  • Как распечатать word 2003

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии