这是“Python1024-自动化办公”的第一篇。
在Python1024的基础篇中,我们已经介绍过文件管理和文本文件的读写:
《编程的第一个应用,往往都从文件读写开始》
在路径处理方面,Python3.6版本后,建议采用pathlib
,它采用面向对象封装接口,使用起来比os.path
更人性化。
在学习后续章节前,有必要先介绍几个基本的概念,方便后续的理解。
文本文件其实是一种特殊的二进制文件,它约定了以字符格式的读取方式,字符符合ASCII或UNICODE等编码标准。因为文本文件太通用、太特殊(字符形式)了,我们把它单独列出对待。
其他二进制文件则随应用的不同,有各式各样的读写规则。比如:
当然,除了上面这些文件格式外,我们还可以定义自己的格式,只要定义的格式,能被对应软件支持打开和写入即可。换句话说,如果你定义的文件格式,没人写出软件去支持,那就没办法应用。或者,你自己写了软件,但大部分人都不知道,或不想用,那它也就丧失了应用价值。在软件行业向互联网演进过程中,淘汰了大量的软件,才诞生出目前相对稳定的互联网基础设施。
Youtube上有人做了一个视频,呈现了90年代到2020年间最受欢迎浏览器的更替:视频地址。
文本文件,本质上是用于存储字符的文件。
所有那些以字符保存的文件格式,其实都是文本文件,只不过文本内容还有额外特定含义。
常见的比如:CSV、HTML、XML、JSON、JS、CSS,还有各种语言的代码。
CSV文件常用于保存数据表格,比如:
姓名, 电话, 地址
张三, 18900000001, 上海
李四, 13800000002, 广州
这就是一个典型的CSV文件,我们可以用文本编辑器打开它,也可以用Excel等软件打开它。如果用Excel软件打开它,Excel会把英文逗号作为分隔符号,提取单元格内容,我们看到的就是一张表格。
Python同样也支持这类文件的读写,通过csv模块:
import pathlib
import csv
path = list(pathlib.Path.cwd().parents)[1].joinpath('data/automate/001basic')
csv_path = path.joinpath('hello.csv')
with open(csv_path ,'r') as f:
f_csv = csv.reader(f)
headers = next(f_csv)
for row in f_csv:
for h, v in zip(headers, row):
print(f'{h.strip()}: {v.strip()}')
这样就能读出CSV文件中的数据:
姓名: 张三
电话: 18900000001
地址: 上海
姓名: 李四
电话: 13800000002
地址: 广州
XML(eXtensible Markup Language)是为了结构化存储和传输数据而生,是一种标记语言。
<mail>
<to>Worldto>
<from>程一初from>
<title>Hello Worldtitle>
<body>Welcome to Python1024!body>
mail>
我们可以自定义标记,一种定义就是一种数据格式。在Python中,有三种处理数据的方式:
以ElementTree为例:
import pathlib
import xml.etree.ElementTree as ET
path = list(pathlib.Path.cwd().parents)[1].joinpath('data/automate/001basic')
xml_path = path.joinpath('hello.xml')
tree = ET.parse(xml_path)
root = tree.getroot() # 根节点
print('root_tag:', root.tag) # 根标签:mail
for elem in root:
print(f'{elem.tag}: {elem.text}')
此外,HTML是XML的一个子集,即HTML是一种特殊的XML,它定义了一整套标签规范,比如文字、超链接、表单等,按照这套规范来呈现HTML的应用就是浏览器了。当然,浏览器除了支持HTML,还需要支持JS脚本、CSS样式文件等其他规范。
相比XML文件格式,JSON文件格式更精简。同样的信息可以用更少的字符表示:
{
"mail": {
"to": "World",
"from": "程一初",
"title": "Hello World",
"body": "Welcome to Python1024!"
}
}
少了对称标记以及<>符号,JSON需要占用更少标记数据,所以它更常被用于互联网应用的数据传输。Python也内置了处理模块json:
import pathlib
import json
path = list(pathlib.Path.cwd().parents)[1].joinpath('data/automate/001basic')
json_path = path.joinpath('hello.json')
with open(json_path, 'r') as f:
data = json.loads(f.read())
print(f'root_tag: {list(data.keys())[0]}')
for k, v in data['mail'].items():
print(f'{k}: {v}')
代码文件,比如Python代码文件,也是一种文本文件。所以,有一些静态代码检测工具,如pylint、pep8、flake8等,可以读取代码文件后检查编写质量。甚至,你可以编写程序自动生成代码,在自动化测试中用的比较多。
代码文件的读取和其他文本文件一样,都可以用open()函数打开,但是要解析代码文件,就必须用“语法树”来解析,它也提供了对应的ast模块。比如我们写一个简单的Python代码文件,包含一个注释块,以及一行代码:
'''
Author: 程一初
'''
print('hello world!')
然后用语法树解析它:
import pathlib
import ast
path = list(pathlib.Path.cwd().parents)[1].joinpath('data/automate/001basic')
py_path = path.joinpath('hello.py')
with open(py_path, 'r') as f:
node = ast.parse(f.read())
# 获取文档注释
print(ast.get_docstring(node))
class MyVisitor(ast.NodeVisitor):
# 定义一个遍历代码节点的类
# 按需重定义generic_visit函数
def generic_visit(self, node):
print(node)
super(MyVisitor, self).generic_visit(node)
v = MyVisitor()
v.visit(node)
会得到这样的结果:
Author: 程一初
<_ast.Module object at 0x118e4e890>
<_ast.Expr object at 0x118ce1b50>
<_ast.Str object at 0x118ce1f90>
<_ast.Expr object at 0x118ce1d90>
<_ast.Call object at 0x118ce1ad0>
<_ast.Name object at 0x118ce1b10>
<_ast.Load object at 0x103ed39d0>
<_ast.Str object at 0x118eb3ed0>
第一行为注释文档,剩下8行为ast内部对象,包括模块、表达式、字符串、函数名、调用等。这里只是举个例子,说明代码文件也是一种特殊的文本文件。平时应用中,我们几乎不会这么去读写代码文件,而是直接用Python解释器来执行代码。
了解什么是文件,就能明白每个文件都有自己的规范,想要处理某类文件,就得先找到符合规范的应用,或者模块。找到模块后,就可以通过结构化的代码来批量处理了。
常见的自动化处理无非就这几种:
Python的魅力,就是能把所有重复的工作,按模块组织起来,形成流水线,一个人发挥N个人的效率。