Чтение официальных данных о численности муниципальных образований с параметрами форматирования текста с помощью библиотеки xlrd

в 6:21, , рубрики: python, открытые данные, электронное правительство, метки: ,

Для одного общественного проекта (визуализация бюджетов поселений и районов) мне потребовались данные об иерархии муниципальных образований и их численности.
Нужные данные я нашел, но форма их представления для корректного использования оставляла желать лучшего.
Все необходимые данные были в одном файле, однако, его форматирование затрудняло извлечение иерархии. Все названия муниципалитетов, районов и областей располагались в одном столбце и отличались только форматом ячейки и шрифта. Область выделялась жирным шрифтом, район — жирным наклонным, а поселение имело отступ. Также в файле находились несколько ошибок, например один район был выделен как область (или наоборот, уже не помню), а еще в одном месте в середине названия образования встретился переход строки (этот момент выяснился на этапе импорта в Google App Engine, когда db.StringProperty() ругнулся на multiline), исходный файл в этих местах пришлось исправить.

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

Ячейка
alignment (XFAlignment object):
hor_align: 0
indent_level: 0
rotation: 0
shrink_to_fit: 0
text_direction: 0
text_wrapped: 0
vert_align: 2
background (XFBackground object):
background_colour_index: 65
fill_pattern: 0
pattern_colour_index: 64
border (XFBorder object):
bottom_colour_index: 64
bottom_line_style: 7
diag_colour_index: 0
diag_down: 0
diag_line_style: 0
diag_up: 0
left_colour_index: 64
left_line_style: 1
right_colour_index: 64
right_line_style: 1
top_colour_index: 64
top_line_style: 1
font_index: 7
format_key: 0
is_style: 0
lotus_123_prefix: 0
parent_style_index: 0
protection (XFProtection object):
cell_locked: 1
formula_hidden: 0
xf_index: 556

Шрифт

struck_out: 0
underline_type: 0
underlined: 0
weight: 400
bold: 1
character_set: 204
colour_index: 32767
escapement_type: 0
family: 0
font_index: 10
height: 200
italic: 1
name: u'Arial Cyr'
outline: 0
shadow: 0

Со всеми параметрами я не разбирался, мне для данной задачи хватило типа шрифта и отступа (ident) в ячейке. Но видно, что возможности большие, вплоть до цвета конкретной границы ячейки или типа линии.

Код скрипта

# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import xlrd
import json


rb = xlrd.open_workbook('Tabl-35-12.xls', formatting_info=True)
font_list = rb.font_list  # list of all fonts in excel table
sheet = rb.sheet_by_index(1)
rows_number = sheet.nrows

peoples_dict = {}  # main dict
for rownum in range(7, rows_number):  # data starts with line 7
    cell = sheet.cell(rownum, 0)
    value = cell.value.strip().replace('n', ' ')  # delete spaces at start and end
    peoples_count = sheet.cell(rownum, 1).value
    if peoples_count == 0 or peoples_count == '':  # empty row - continue
        continue
    peoples_count = int(peoples_count)  # from 12313.0 to integer

    cell_format = rb.xf_list[cell.xf_index]
    current_font = font_list[cell_format.font_index]
    
    bold = bool(current_font.bold)
    italic = bool(current_font.italic)
    indent = cell_format.alignment.indent_level

    is_region = bold and not italic
    is_raion = bold and italic
    is_municipal = (indent == 2)

    if is_region:
        region = value
        peoples_dict[region] = {'count': peoples_count}
    elif is_raion:
        raion = value
        peoples_dict[region][raion] = {'count': peoples_count}
    elif is_municipal:
        municipal = value
        peoples_dict[region][raion][municipal] = {'count': peoples_count}

print peoples_dict['Московская область']['Истринский муниципальный район']['Городское поселение Истра']['count']

with open('peoples.json', 'w') as outfile:
    json.dump(peoples_dict, outfile)

В качестве бонуса — получившийся выходной файл, в формате json. Структура — вложенные словари, где каждый элемент содержит ключ 'count', где записана численность образования, и ключи его потомков.
То есть численность Московской области можно получить так:

peoples_dict['Московская область']['count']

а численность города Истры Истринского муниципального района — так:

peoples_dict['Московская область']['Истринский муниципальный район']['Городское поселение Истра']['count']

Автор: KulikovPavel

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js