2022年 11月 5日

Python 编写自动化工具

引言:

在开发过程中,我们经常需要编写一些自动化的工具,例如:

  • Windows 下的 BATCH (批处理)
  • Linux 下的 Shell 等

但是假如我们要做跨平台的开发,根据每个平台去开发一套功能相同的自动化脚本显然不是最好的选择,选择跨平台通用的脚本是更好的选择,Python 就是常用来编写自动化工具的跨平台脚本语言。

Python 环境安装:

1.资源下载:

直接到 Python 官网 下载安装包,有两个分支:2.x 和 3.x,两者有着巨大的差别,当然现在比较流行的还是 2.7.x 系列,这里我直接下载此系列的最新版本:python-2.7.13.msi 。

2.安装步骤:

过程十分简单,双击打开安装包,一直 Next 直到安装完成,记得要记录一下其安装目录,后面配置系统环境时要用到。

3.环境配置:

打开 计算机 -> 属性 -> 高级系统设置 -> 环境变量... ,然后再 系统变量 中新建一项,设置参数如下:

  1. 变量名:PYTHON_HOME
  2. 变量值:D:\Develope\Python2.7

然后编辑系统变量中的 Path 变量的参数,在变量值最后加上 ;%PYTHON_HOME%;,然后保存编辑内容。然后,打开命令行窗口查询是否配置成功:

  1. C:\Users\hasee-pc>python --version
  2. Python 2.7.13

以上说明环境变量的配置已完成。

4.运行 Python:

运行 Python 代码块的方式有两种,一种是直接在命令行窗口输入 Python 指令进入交互式编程窗口,然后直接输入代码,键盘 Enter执行结果,如下:

  1. C:\Users\hasee-pc>python
  2. Python 2.7.13 (v2.7.13:a06454b1afa1, Dec 17 2016, 20:42:59) [MSC v.1500 32 bit (
  3. Intel)] on win32
  4. Type "help", "copyright", "credits" or "license" for more information.
  5. >>> print "hi,linsh"
  6. hi,linsh

也可以创建一个 .py 脚本,编辑好脚本内容,例如:

  1. # test.py
  2. print "hi,linsh"

然后,在命令行定位到脚本所在目录,执行该脚本,以下两种执行方式都可以:

  1. D:\Develope\PythonProjects>python test.py
  2. hi,linsh
  3. D:\Develope\PythonProjects>test.py
  4. hi,linsh

# 号用于注释单行,多行注释通常使用三引号 ''' 或 """ 开始和结束。


Python 基础语法:

这里不会赘述太多细节性的语法,只简述一些必要的基础语法,更详细的可以参考 【 Python 语言参考 】:

1.特殊标识符:

  • 跟其他编程语言一样,Python 中所有标识符可以包含:英文、数字以及下划线(_),但不能以数字开头;
  • 以下划线开头的表示特殊含义: 
    • 单下划线 _ 开头表示不能直接被外部类直接访问的类属性,,需要通过类提供的接口才能进行访问,例如:_foo
    • 双下划线 __ 开头表示类的私有成员,就像很多语言中的 private 权限关键字的作用,例如:__foo
    • 以双下划线开头和结尾代表 Python 中特殊方法专用的标识,例如 __init__() 代表类的构造函数。

2.缩进和代码块:

Python 与其他语言最大的不同,在于它不使用 {} 或者像 Lua 那样的关键字来包裹一个代码块以管理类、函数或逻辑判断,而是直接通过 缩进 来管理模块。

缩进的空白 数量(键盘空格键次数)是可变的,但是所有代码块语句必须包含相同的缩进空白数量。例如:

  1. if True:
  2. print "True"
  3. else:
  4. print "False"

通常将编程工具的一次 Tab 键的距离设为 4 个空格 距离,作为一级缩进的空白数。

3.数据类型和变量:

Python 有 5 种标准的数据类型:

  1. Numbers(数字)
  2. String(字符串)
  3. List(列表)
  4. Tuple(元组)
  5. Dictionary(字典)

但是,在定义变量时,不需要声明变量的类型,变量在使用前需要先进行赋值,此时解释器才能根据赋值的类型为此变量分配创建内存空间并创建此变量,只是声明但不赋值的变量是不能使用的。例如:

  1. number = 2 # 整型
  2. percent = 100.0 # 浮点型
  3. name = "linsh" # 字符串

此外,还可以同时对多个变量进行赋值:

number,percent,name = 2,100.0,"linsh"

4.函数:

函数的使用一方面是为了提高代码的重用性,另一方面又可以增强代码的可读性和模块化,下面是 Python 定义函数的格式:

  1. def funcName(param1,param2,...):
  2. ...

以关键字 def 来声明一个函数,紧跟着是函数名(函数标识符),然后是 () 包围起来的传入参数表,可以是 0 个参数,也可以是多个参数,然后用 : 号开始函数内容的开始。例如:

  1. # test.py
  2. # # -*- coding: utf-8 -*-
  3. # 方法定义
  4. def TestFunc1():
  5. print "test1"
  6. def TestFunc2(num):
  7. print "test2: num = ",num #str 和 int 类型拼接
  8. # 方法调用
  9. TestFunc1()
  10. TestFunc2(66)

执行结果:

  1. D:\Develope\PythonProjects>test.py
  2. test1
  3. test2: num = 66

编写工具:

1.设计目标:

首先说一下我要工具的功能:

遍历某个目录下包括其下子目录中所有指定的后缀文件,然后为这些文件的头部插入指定的字符串。

2.使用场景:

设计这样的工具起因是我最近在将之前 CSDN 中的博客搬运到自己的 Hexo 博客空间上,了解的应该知道,假如都是 Markdown 编写的话,搬运的时候只需要在文件头部加上如下的一串额外的内容:

  1. ---
  2. title: 博客标题
  3. date: 博客创建时间(例如:2016-09-03 17:15:22)
  4. tags: 标签(如:[Hexo,Next],多个的话用,号隔开)
  5. categories: 分类(如:Web)
  6. ---
  • 标题 title 直接使用文件名称去掉 .md 后缀即可;
  • 时间 date 需要通过文件库获取文件的创建时间;
  • 标签 tags 和分类 categories ,由于我的文件会根据分类放入不同的子目录下,所以直接获取当前文件所在目录的名称即可。

此外,为了在博客首页只展示部分内容,而不是展开博客的完整内容,还需要在博客中恰当的位置插入这个标签:<!--more--> ,通常加载第一段内容结束的位置。

3.实现代码:

根据上面的思路,我们在 source/_posts 目录下创建一个工具脚本,起名为 SuitFileToHexo.py ,然后依次完成以下步骤:

  • 指定 Linux 环境下 Python 解释器目录,并指定编码方式:

    1. #!/usr/bin/env python
    2. # -*- coding: utf-8 -*-
  • 引入的模块:

    在脚本开始的地方,最先需要做的事情就是把需要用到的模块都先引入进来,大致分析一下我们这个功能需要用到的模块:

    import os.path,time
  • 遍历当前目录下所有 .md 文件列表:

    这就需要使用到 Python 的文件目录操作模块 os.path ,使用 os.listdir 获取目录列表,然后通过 os.path.splitext 分割文件名称和后缀名,从而筛选合格的文件:

    1. # 获取指定目录指定后缀名的文件列表
    2. def getFileList(path,endStr):
    3. '''获取指定目录下,指定后缀的文件列表'''
    4. r_list = []
    5. f_list = os.listdir(path) #获取目录列表
    6. for i in f_list:
    7. # 分离文件名和后缀名,过滤掉工具脚本
    8. file_endStr = os.path.splitext(i)[1]
    9. # 判断是否是目录
    10. if os.path.isdir(i):
    11. f_list1 = os.listdir(path+'/'+i)
    12. for j in f_list1:
    13. # 过滤出指定后缀 endStr 后缀的文件
    14. if os.path.splitext(j)[1] == endStr:
    15. # 为了清晰目录把文件所在目录也标识出来
    16. r_list.append(i+'/'+j)
    17. # print j.decode("string_escape")
    18. elif file_endStr == endStr:
    19. r_list.append(i)
    20. return r_list

    这里发现了一个问题,就是在 os.path.isdir(i) 在 2.7.11 的版本莫名其妙地返回 false,需要做如下修改才能正常:

    1. if file_endStr == '':
    2. i = os.path.join(path, i) #=================〉这一行很必要
    3. # print i
    4. # 判断是否是目录
    5. if os.path.isdir(i):
    6. ...
  • 获取文件的创建时间:

    需要使用到 os.time 模块的功能:

    1. # 获取文件创建时间
    2. def get_FileCreateTime(filePath):
    3. t = os.path.getctime(filePath)
    4. return TimeStampToTime(t)
    5. # 把时间戳转化为时间: 1479264792 to 2016-11-16 10:53:12'''
    6. def TimeStampToTime(timestamp):
    7. timeStruct = time.localtime(timestamp)
    8. return time.strftime('%Y-%m-%d %H:%M:%S',timeStruct)
  • 获取博客标题:

    其实就是从目录字符串中截掉后缀名,再截掉最后一个 / 之前的内容即可得到博客名称:

    1. # 获取目录中去掉前面路径和后缀的文件名字
    2. def getFileSimpleName(filePath):
    3. name = ''
    4. # 先去掉后缀
    5. name = os.path.splitext(filePath)[0]
    6. # 获取最后一个斜杠位置
    7. index = name.rfind('/')
    8. # 找不到则返回 -1
    9. if index != -1:
    10. # 截取斜杠后面到结尾内容
    11. name = name[index+1:]
    12. # print name
    13. return name
  • 获取文件所在的目录名称作为页签值:

    与获取博客名称思路略有相似,获取最后一个斜杠位置,截掉斜杠之后的内容,在获取一个最后一个斜杠位置,假如有则截取斜杠之后的内容即是文件所在目录的名称:

    1. # 获得分类文件目录名称
    2. def getTypeNameByPath(filePath):
    3. fileTag = ''
    4. # 获取最后一个斜杠位置
    5. index = filePath.rfind('/')
    6. # 找不到则返回 -1
    7. if index != -1:
    8. # 截取斜杠后面到结尾内容
    9. fileTag = filePath[:index]
    10. # 截掉前面部分
    11. index = fileTag.rfind('/')
    12. if index != -1:
    13. fileTag = fileTag[index+1:]
    14. # print fileTag
    15. return fileTag
  • 向文件中插入内容:

    调用以上方法即可分别得到我们想要的信息:

    1. # 指定目录
    2. path = './'
    3. # 得到文件列表
    4. files = getFileList(path,'.md')
    5. for i in files:
    6. print 'title: '+getFileSimpleName((i.decode("string_escape")))
    7. print 'date: '+get_FileCreateTime((path+i.decode("string_escape")))
    8. print 'tags: ['+getTypeNameByPath((i.decode("string_escape")))+']'

    接下来要做的就是把这些内容按照格式插入到文件中去,当然插入之前需要先检查文件中是否已经插入过类似的内容了,可以简单地通过检查开头 40 个字符串中是否包含这个字符串来判别:

    1. '''---
    2. title: '''

    关于展示分隔符 <!--more--> 插入的位置,大致逻辑是:第一个标题后面,而且刚好插入在第二个标题之前即可,而使用 Markdown 语法撰写的博客标题使用 # 来表示的,最终的插入方法如下:

    1. # 向文件中插入指定数据
    2. def addHeadToFile(filePath,title,date,tags):
    3. file = open(filePath,"r")
    4. content = file.read()
    5. index = content[:40].find('''---
    6. title:''')
    7. # 添加
    8. if index == -1:
    9. print 'Undadded'
    10. addContent = '''---
    11. title: '''+title+'''
    12. date: '''+date+'''
    13. tags: ['''+tags+''']
    14. categories: '''+tags+'''
    15. <hr />
    16. '''
    17. # 检测是否插入部分显示标签
    18. content = addContent + content
    19. index = content.find('''<!--more--> ''')
    20. if index == -1:
    21. # 获取第一段的位置
    22. index = content.find('''### ''')
    23. if index != -1:
    24. #print "first ### pos = ",index
    25. # 下一个标题位置(在第二个标题之前插入即可)
    26. pos = content[index:].find('''
    27. #''',1)
    28. if pos != -1:
    29. index += pos
    30. #print "second enter pos = ",index
    31. content = content[:index]+'''
    32. <!--more-->
    33. '''+content[index:]
    34. file = open(filePath,"w")
    35. file.write(content)
    36. else:
    37. #print 'file head had added'
    38. # 记得要关闭文件
    39. file.close()

    最后完整的调用过程:

    1. # 指定目录
    2. path = './'
    3. # 得到文件列表
    4. files = getFileList(path,'.md')
    5. # 声明一些全局变量
    6. title = ''
    7. date = ''
    8. tags = ''
    9. for i in files:
    10. title = getFileSimpleName(i.decode("string_escape"))
    11. date = get_FileCreateTime(path+i.decode("string_escape"))
    12. tags = getTypeNameByPath(i.decode("string_escape"))
    13. print 'title: '+title
    14. print 'date: '+date
    15. print 'tags: ['+tags+']'
    16. addHeadToFile(path+i.decode("string_escape"),title,date,tags)

其他:

如果你跟我一样出现了打印中文文件名变成诸如: “BATCH\xc5\xfa\xb4\xa6\xc0\xed\xbc\xf2\xbc\xc7.md” 这种格式的话,可以参考:Linux 下Python2.7解决list打印中文字符问题


参考资料:

  • Python注释
  • Python 基础语法
  • Python 函数
  • Python 入门指南
  • python 获取文件大小,创建时间和访问时间
  • python插入内容到指定文件的位置
  • os.path.isdir() 判断文件夹却返回false

转载地址:  http://blog.csdn.net/linshuhe1/article/details/77659504