Python基础语法项目实践-自动化录入数据

项目背景

某同学需要调研市区里的住宅小区,记录下不同小区的地址、建筑年份和每栋楼里每个单元里每一户的朝向和面积。比如其中一户的资料是:富安花园(小区)3栋 2单元 401户;朝向:南北朝向;面积:90平方。他需要把每一户的信息都记录下来。一般会将一栋楼的数据画在一张平面图,之后再慢慢录入到excel里面,但面对这样的情况,一旦遇到不同单元的户数、朝向和面积,就无法进行复制,而一遍遍的输入数据将会十分心累且耗费时间!一旦出错,难以发现以及改变很费劲,牵连甚广。

于是需求应运而生,如何用python输入模板数据,程序自动录入剩下的数据,甚至不用打开excel

拆解项目

目标是将一个小区某一栋内所有户室的资料录入到excel表里

简易的流程图可以看一下:

可以分三个版本逐渐迭代

1.0版本:输入固定表头,确定模板数据

用Python读写excel的时候,可以调用csv模块,下面将向csv里写入表头

import csv
#调用csv模块
with open('data.csv', 'a', newline='') as csvfile:
#调用open()函数打开csv文件,传入参数:文件名“data.csv”、追加模式“a”、newline=''。
    writer = csv.writer(csvfile, dialect='excel')
    # 用csv.writer()函数创建一个writer对象。
    header=['小区名称', '地址', '建筑年份', '楼栋', '单元', '户室', '朝向', '面积']
    writer.writerow(header)
    #用writerow()函数将表头写进csv文件里

将以上的复制到本地编辑器,可以看到新建了一个名为data.csv文件,打开如下:

如果是mac os,遇到了乱码,则需要在open()函数里加上参数endoding='GBK'

with open('data.csv', 'a', newline='',encoding='GBK') as csvfile:
#确定编码

下面就是确定哪些数据是可以一次输入重复利用,小区的名称、建筑年代、地址、楼号是可以重复使用的,但同一栋的单元内分布是各有不同的,楼型不同户型也不一样。放大到同一单元下,每一层的户型和朝向一般是一样的,所以只需要某一层的数据,就可以知道其他楼层的,区别只是户室号。确定了以此为模板数据,下一步就是转化成代码。

title = input('请输入小区名称')
address = input('请输入小区地址:')
year = input('请输入小区建造年份:')
block = input('请输入楼栋号:')
#输入可重复利用利用的数据

2.0版本:获取模板数据,重复使用模板数据

户室号一般有楼层+两位序号组成,比如101,102,201,202等,尾号是统一的,变化则根据楼层数而变化。根据图片可以看出每个户室的朝向和面积是并列关系,从属于户室的。

通过使用字典嵌套列表的形式,来实现数据的组合,字典的键是户室号,面积和朝向组成的列表为字典的值。类似如下形式

start_floor_rooms = {301:['南北',70],302:['南北',70],303:['东西',80],304:['东西',80]}
#初始楼层的数据

那么具体输入的代码如下所示:

start_floor = input('请输入起始楼层')
end_floor = input('请输入终止楼层')
#获取每一单元楼层数

start_floor_room = {}
floor_last_number = []
#创建字典,存放户室信息;创建列表,存放户室尾号如['01','02'],后续楼层即可重复使用

last_number = input('请输入起始楼层户室的尾号:(如01,02)')

floor_last_number.append(last_number)
#将输入的元素添加到户室尾号的列表里

room_number = int(start_floor + last_number)
#户室号由起始楼层和户室尾号组成,如301

direction = int(input('请输入 %d朝向(南北朝向输入1,东西朝向输入2):' % room_number))
#收集该户室的朝向信息

area = int(input('请输入 %d 的面积,单位为㎡:' % room_number))
#收集该户室的面积信息

start_floor_room[room_number] = [direction,area]
#户室号为键,朝向和面积均为值,添加到字典里

print(start_floor_room)
#打印起始楼层数据

运行结果如下:

这样我们就获取了一个户室的信息,但如果要获取起始楼层其他户室的信息,则需要加入循环。

start_floor = input('请输入起始楼层')
end_floor = input('请输入终止楼层')
#获取每一单元楼层数

input('接下来请依次输入起始层每个房间的户室尾号、南北朝向及面积,按任意键继续')

start_floor_room = {}
floor_last_number = []
#创建字典,存放户室信息;创建列表,存放户室尾号如['01','02'],后续楼层即可重复使用

#定义循环控制量
room_loop = True
while room_loop:
    
    last_number = input('请输入起始楼层户室的尾号:(如01,02)')

    floor_last_number.append(last_number)
    #将输入的元素添加到户室尾号的列表里

    room_number = int(start_floor + last_number)
    #户室号由起始楼层和户室尾号组成,如301

    direction = int(input('请输入 %d朝向(南北朝向输入1,东西朝向输入2):' % room_number))
    #收集该户室的朝向信息

    area = int(input('请输入 %d 的面积,单位为㎡:' % room_number))
    #收集该户室的面积信息

    start_floor_room[room_number] = [direction,area]
    #户室号为键,朝向和面积均为值,添加到字典里
    
    continued = input('是否需要输入下一个尾号?按 n 停止输入,按其他任意键继续录入')
    
    if continued == 'n':
        room_loop = False
    else:
        room_loop = True

print(start_floor_room)
#打印起始楼层数据

运行结果如下:

到这一步,已经将起始楼层的所有户室数据收集到了,下一步则只要将这层的数据迁移到其他楼层中即可。

为了更好的管理数据,将所有楼层的数据放在一起会更好管理,也就是字典嵌套字典的方式。

那么根据此方法,对刚才的代码再次进行添加,如下:

start_floor = '3'
end_floor = '4'
floor_last_number = ['01','02','03']
# 之前input()输入的数据为str类型

start_floor_rooms = {301:[1,80], 302:[1,80], 303:[2,90]}
#初始楼层的模版数据

unit_rooms = {}
#创建一个字典,存储所有楼层的数据
unit_rooms[int(start_floor)] = start_floor_rooms
#unit_rooms = {3: {301: [1, 80], 302: [1, 80], 303: [2, 90]}}

floor_rooms = {}
#给4楼创建一个字典
for i in range(len(start_floor_rooms)):
    #遍历每层有多少个房间,这里是3,即执行for i in range 3 的循环
    number = '4' + floor_last_number[i]
    #字符串拼接, number = ['401','402','403']
    info = start_floor_rooms[int(start_floor + floor_last_number[i])]
    # 依次取出字典start_floor_rooms键对应的值,即面积和朝向组成的列表
    # int(start_floor + floor_last_number[0])= 301 
    # info = [1,80]

    floor_rooms[int(number)] = info
    #给字典floor_rooms添加键值对,floor_rooms = {401:[1,80]}
    #循环三次,所以floor_rooms = {401:[1,80], 402:[1,80], 403:[2,90]}

unit_rooms[4] = floor_rooms
#以4为键,floor_rooms为值,给字典unit_rooms添加键值对
print(unit_rooms)
#unit_rooms = {3: {301: [1, 80], 302: [1, 80], 303: [2, 90]}, 4: {401: [1, 80], 402: [1, 80], 403: [2, 90]}}

运行结果如下:

{3: {301: [1, 80], 302: [1, 80], 303: [2, 90]}, 4: {401: [1, 80], 402: [1, 80], 403: [2, 90]}}

接下来继续假如循环,将所有楼层数据一次性放进字典unit_rooms里。如果是3-7楼,我们的循环执行4,5,6,7四次,循环条件可以写成:

for floor in range(start_floor + 1, end_floor + 1):  
# 在此例中,为 for floor in range (4,8)

那么将循环写入上一步,结果就是:

start_floor = '3'
end_floor = '7'
floor_last_number = ['01','02','03']
start_floor_rooms = {301:[1,80],302:[1,80],303:[2,90]}
#初始楼层的模版数据
unit_rooms = {}
#新建一个存放所有楼层的字典
unit_rooms[int(start_floor)] = start_floor_rooms

for floor in range(int(start_floor) + 1, int(end_floor) + 1):
        #遍历除初始楼层外的其他楼层
        floor_rooms = {}
        #每个楼层都建立一个字典
        for i in range(len(start_floor_rooms)):
        #遍历每层有多少个房间,这里是3,即执行for i in range 3 的循环
            number = str(floor) + floor_last_number[i]
            info = start_floor_rooms[int(start_floor + floor_last_number[i])]
            # 依次取出字典start_floor_rooms键对应的值,即面积和朝向组成的列表
            floor_rooms[int(number)] = info
            #给字典floor_rooms添加键值对,floor_rooms = {401:[1,80]}
        unit_rooms[floor] = floor_rooms
print(unit_rooms)

运行结果如下:

{3: {301: [1, 80], 302: [1, 80], 303: [2, 90]}, 4: {401: [1, 80], 402: [1, 80], 403: [2, 90]}, 5: {501: [1, 80], 502: [1, 80], 503: [2, 90]}, 6: {601: [1, 80], 602: [1, 80], 603: [2, 90]}, 7: {701: [1, 80], 702: [1, 80], 703: [2, 90]}}

3.0版本:写入CSV文件

再看一遍开头输入的表头

名称、地址、建筑年份、楼栋、单元都需要手动输入,输入一遍即可复用到其他所有单元格里。

title = input('请输入小区名称')
address = input('请输入小区地址:')
year = input('请输入小区建造年份:')
block = input('请输入楼栋号:')
unit = input('请输入单元号:')

剩下户室信息,“朝向”、“面积”都储存在字典unit_rooms里,接着需要对字典内信息进行提取。首先就要提取字典里的值,也就是大字典中的小字典

# for value in DictName.values():
# value的名字可以自行另取
# DictName是要遍历的字典的名称
# .values():是固定的用法

unit_rooms = {3:{301:[1,80],302:[1,80],303:[2,90],304:[2,90]},
             4:{401:[1,80],402:[1,80],403:[2,90],404:[2,90]},
             5:{501:[1,80],502:[1,80],503:[2,90],504:[2,90]}
            }
for sub_dict in unit_rooms.values():
    print(sub_dict)

提取出小字典后,接着需要遍历小字典的键和值,可以用for k,v in DictName.items():,k对应键,v对应值,通过小例子可以直观的感受一下:

tv_dict = {'芒果台':'湖南卫视', '荔枝台':'江苏卫视', '番茄台':'东方卫视'}    
for logo,name in tv_dict.items():
    print(logo + '是' + name)

运行结果如下:

芒果台是湖南卫视
荔枝台是江苏卫视
番茄台是东方卫视

那么运用该方法打印每一户室的门牌号、朝向和面积,如下:

unit_rooms = {3:{301:[1,80],302:[1,80],303:[2,90],304:[2,90]},
             4:{401:[1,80],402:[1,80],403:[2,90],404:[2,90]},
             5:{501:[1,80],502:[1,80],503:[2,90],504:[2,90]}
             }
for sub_dict in unit_rooms.values():
    for room,info in sub_dict.items():
        print('户室号:%d 朝向 %d 面积:%d'% (room,info[0],info[1]))

运行结果如下:

户室号:301 朝向 1 面积:80
户室号:302 朝向 1 面积:80
户室号:303 朝向 2 面积:90
户室号:304 朝向 2 面积:90
户室号:401 朝向 1 面积:80
户室号:402 朝向 1 面积:80
户室号:403 朝向 2 面积:90
户室号:404 朝向 2 面积:90
户室号:501 朝向 1 面积:80
户室号:502 朝向 1 面积:80
户室号:503 朝向 2 面积:90
户室号:504 朝向 2 面积:90

朝向显示数字总觉得会怪怪的,可以运用条件判断和赋值语句,也可以通过列表索引的方式进行更改。

unit_rooms = {3:{301:[1,80],302:[1,80],303:[2,90],304:[2,90]},
             4:{401:[1,80],402:[1,80],403:[2,90],404:[2,90]},
             5:{501:[1,80],502:[1,80],503:[2,90],504:[2,90]}
             }
for sub_dict in unit_rooms.values():
    for room,info in sub_dict.items():
        dire = ['', '南北', '东西']
        print('户室号:%d 朝向:%s 面积:%d' % (room,dire[info[0]],info[1]))

输出结果为:

户室号:301 朝向: 南北 面积:80
户室号:302 朝向: 南北 面积:80
户室号:303 朝向: 东西 面积:90
户室号:304 朝向: 东西 面积:90
户室号:401 朝向: 南北 面积:80
户室号:402 朝向: 南北 面积:80
户室号:403 朝向: 东西 面积:90
户室号:404 朝向: 东西 面积:90
户室号:501 朝向: 南北 面积:80
户室号:502 朝向: 南北 面积:80
户室号:503 朝向: 东西 面积:90
户室号:504 朝向: 东西 面积:90

到这为止,需求差不多基本满足了,再加入一层单元间的循环即可完成最后的代码,最终代码如下:

import csv
#调用csv模块
with open('data.csv', 'a', newline='') as csvfile:
#调用open()函数打开csv文件,传入参数:文件名“data.csv”、追加模式“a”、newline=''。
    writer = csv.writer(csvfile, dialect='excel')
    # 用csv.writer()函数创建一个writer对象。
    header=['小区名称', '地址', '建筑年份', '楼栋', '单元', '户室', '朝向', '面积']
    writer.writerow(header)

title=input('请输入小区名称:')
address = input('请输入小区地址:')
year = input('请输入小区建造年份:')
block = input('请输入楼栋号:')


unit_loop = True
while unit_loop:
    unit=input('请输入单元号:')
    start_floor = input('请输入起始楼层:')
    end_floor = input('请输入终止楼层:')

    # 开始输入模板数据
    input('接下来请输入起始层每个房间的门牌号、南北朝向及面积,按任意键继续')

    start_floor_rooms = {}
    floor_last_number = []
    # 收集起始层的房间信息

    # 定义循环控制量
    room_loop = True
    while room_loop:
        last_number = input('请输入起始楼层户室的尾号:(如01,02)')
        floor_last_number.append(last_number)
        #将尾号用append()添加列表里,如floor_last_number = ['01','02']
        room_number = int(start_floor + last_number)
        #户室号为room_number,由楼层start_floor和尾号last_number组成,如301

        direction = int(input('请输入 %d 的朝向(南北朝向输入1,东西朝向输入2):' % room_number ))
        area = int(input('请输入 %d 的面积,单位 ㎡ :' % room_number))
        start_floor_rooms[room_number] = [direction,area]
        # 户室号为键,朝向和面积组成的列表为值,添加到字典里,如start_floor_rooms = {301:[1,70]}

        continued= input('是否需要输入下一个尾号?按 n 停止输入,按其他任意键继续:')
        #加入打破循环的条件
        if continued == 'n':
            room_loop = False
        else:
            room_loop = True       

    unit_rooms = {}
    #新建一个放单元所有户室数据的字典
    unit_rooms[start_floor] = start_floor_rooms
    #unit_rooms={3:{301:[1,80],302:[1,80],303:[2,90],304:[2,90]}}
    for floor in range(int(start_floor) + 1, int(end_floor) + 1):
    #遍历除初始楼层外的其他楼层
        floor_rooms = {}
        #每个楼层都建立一个字典
        for i in range(len(start_floor_rooms)):
        #遍历每层有多少个房间,这里是3,即执行for i in range 3 的循环
            number = str(floor) + floor_last_number[i]
            info = start_floor_rooms[int(start_floor + floor_last_number[i])]
            # 依次取出字典start_floor_rooms键对应的值,即面积和朝向组成的列表
            floor_rooms[int(number)] = info
            #给字典floor_rooms添加键值对,floor_rooms = {401:[1,80]}
        unit_rooms[floor] = floor_rooms
    
    with open('data.csv', 'a', newline='')as csvfile:
    #Mac用户要加多一个参数 encoding = 'GBK'
        writer = csv.writer(csvfile, dialect='excel')
        for sub_dict in unit_rooms.values():
            for room,info in sub_dict.items():
                dire = ['', '南北', '东西']
                writer.writerow([title,address,year,block,unit,room,dire[info[0]],info[1]])   

    unit_continue = input('是否需要输入下一个单元?按 n 停止单元输入,按其他任意键继续:')
    if unit_continue == 'n':
        unit_loop = False
    else:
        unit_loop = True

print('恭喜你,信息录入工作完成!')        

来看一下运行后生成的excel吧!

这样就完成了一栋楼所有信息的录入,虽然中间要输入很多次信息,但程序的完成,为以后的录入减少了很多的工作量,同时也可以给别人使用,节省的时间远远大于付出的时间成本。快来试试吧!

文章部分图片及代码来源风变编程,我当时第一次看的时候有点懵,借此机会复习一遍,强化一下,不然很容易生疏,同时也分享给各位。

最后修改:2020 年 12 月 23 日 11 : 04 PM
如果觉得我的文章对你有用,请随意赞赏