re模块
>>> import re
#match函数
尝试用正则表达式模式从字符串的开头匹配,如果匹配成功,则返回一个匹配对象;否则返回None
>>> re.match('f..', 'food') #匹配以"f.."开头的字符串
<_sre.SRE_Match object; span=(0, 3), match='foo'>
>>> re.match('f..', 'seafood')
>>> print(re.match('f..', 'food'))
<_sre.SRE_Match object; span=(0, 3), match='foo'>
>>> print(re.match('f..', 'seafood'))
None
#search函数
在字符串中查找正则表达式模式的第一次出现,如果匹配成功,则返回一个匹配对象;否则返回None
>>> re.search('f..', 'food') #查找第一个匹配"f.."的字符串
<_sre.SRE_Match object; span=(0, 3), match='foo'>
>>> re.search('f..', 'seafood')
<_sre.SRE_Match object; span=(3, 6), match='foo'>
#group方法
使用match或search匹配成功后,返回的匹配对象可以通过group方法获得匹配内容
>>> m = re.search('f..', 'seafood')
>>> m.group() # 返回匹配到的内容
'foo'
#findall函数
在字符串中查找正则表达式模式的所有(非重复)出现,返回一个匹配对象的列表
>>> re.findall('f..', 'seafood is food')
['foo', 'foo']
#finditer函数
和findall()函数有相同的功能,但返回的不是列表而是迭代器;对于每个匹配,该迭代器返回一个匹配对象
>>> for m in re.finditer('f..', 'seafood is food'):
... print(m.group())
...
foo
foo
#split方法
根据正则表达式中的分隔符把字符分割为一个列表,并返回成功匹配的列表
>>> re.split('-|\.', 'hello-world.tar.gz')
['hello', 'world', 'tar', 'gz']
sub方法
把字符串中所有匹配正则表达式的地方替换成新的字符串
>>> re.sub('X', 'tom', 'Hi X.Nice to meet you X.' )
'Hi tom.Nice to meet you tom.'
compile函数
• 对正则表达式模式进行编译,返回一个正则表达式对象
• 不是必须要用这种方式,但是在大量匹配的情况下,可以提升效率
>>> patt = re.compile('f..')
>>> patt.search('seafood')
>>> m = patt.search('seafood')
>>> m
<_sre.SRE_Match object; span=(3, 6), match='foo'>
>>> m.group()
'foo'
<_sre.SRE_Match object; span=(3, 6), match='foo'>
>>> patt.findall('seafood is food')
['foo', 'foo']
Counter对象
统计对象次数并降序排列
>>> from collections import Counter
>>> c = Counter()
>>> c.update('1.1.1.1') #对象是字符串时,统计字符个数
>>> c
Counter({'1': 4, '.': 3}) #“1”出现了4次,“.”出现了3次
>>> c1 = Counter()
>>> c1.update(['1.1.1.1']) #对象是列表时,将列表作为整体进行统计
>>> c1.update(['1.1.1.2'])
>>> c1.update(['1.1.1.2'])
>>> c1.update(['1.1.1.2'])
>>> c1.update(['1.1.1.3'])
>>> c1.update(['1.1.1.3'])
>>> c1.update(['1.1.1.3'])
>>> c1.update(['1.1.1.3'])
>>> c1.update(['1.1.1.3'])
>>> c1
Counter({'1.1.1.3': 5, '1.1.1.2': 3, '1.1.1.1': 1}) #统计各列表次数
>>> c1.most_common(2) 取出(次数)排名前二的对象
[('1.1.1.3', 5), ('1.1.1.2', 3)]
案例:分析apache访问日志
• 编写一个apche日志分析脚本
- 统计每个客户端访问apache服务器的次数
- 将统计信息通过字典的方式显示出来
- 分别统计客户端是Firefox、MSIE和Chrome的访问次数
- 分别使用函数式编程和面向对象编程的方式实现
#函数式编程
[root@room9pc01 day09]# vim count_patt.py
import re
from collections import Counter
def count_patt(fname, patt):
cpatt = re.compile(patt) #先编译模式
c = Counter() #用于保存结果
#打开文件,从每一行中匹配,将匹配结果更新到c中
with open(fname) as fobj:
for line in fobj:
m =cpatt.search(line)
if m:
c.update([m.group()])
return c
if __name__ == '__main__':
fname = 'access_log'
ip = '^(\d+\.){3}\d+' #匹配ip地址正则表达式(如: 192.168.1.25, 545135.445465.765.312354566)
br = 'Firefox|MSIE|Chrome' #匹配浏览器类型正则表达式
print(count_patt(fname, ip))
print(count_patt(fname, br))
[root@room9pc01 day09]# python3 count_patt.py
Counter({'172.40.0.54': 391, '172.40.50.116': 244, '201.1.1.254': 173, '127.0.0.1': 121, '201.1.2.254': 119, '192.168.2.254': 110, '192.168.4.254': 103, '172.40.58.150': 10, '172.40.58.101': 10, '172.40.58.124': 6})
Counter({'Firefox': 870, 'MSIE': 391, 'Chrome': 24})
#面向对象编程
[root@room9pc01 day09]# vim count_patt2.py
mport re
from collections import Counter
class CountPatt: #定义类(常用于定义固定不变的属性)
def __init__(self, fname):
self.fname = fname
def count_patt(self, patt): #定义类中的方法(函数)
cpatt = re.compile(patt) #先编译模式
c = Counter() #用于保存结果
#打开文件,从每一行中匹配,将匹配结果更新到c中
with open(self.fname) as fobj:
for line in fobj:
m =cpatt.search(line)
if m:
c.update([m.group()])
return c
if __name__ == '__main__':
cp = CountPatt('access_log') #调用Countatt类创建实例cp
ip = '^(\d+\.){3}\d+' #匹配ip地址正则表达式(如: 192.168.1.25, 545135.445465.765.312354566)
br = 'Firefox|MSIE|Chrome' #匹配浏览器类型正则表达式
result1 = cp.count_patt(ip)
result2 = cp.count_patt(br)
print(result1)
print(result2)
[root@room9pc01 day09]# python3 count_patt2.py //程序运行结果一致
Counter({'172.40.0.54': 391, '172.40.50.116': 244, '201.1.1.254': 173, '127.0.0.1': 121, '201.1.2.254': 119, '192.168.2.254': 110, '192.168.4.254': 103, '172.40.58.150': 10, '172.40.58.101': 10, '172.40.58.124': 6})
Counter({'Firefox': 870, 'MSIE': 391, 'Chrome': 24})
安装pymysql模块
更改安装源
- python软件包的官方站点:https://pypi.org/
- 通过国内镜像站点安装软件包的设置:
#在线安装
[root@room9pc01 day09]# mkdir ~/.pip/
[root@room9pc01 day09]# vim ~/.pip/pip.conf
[global]
index-url= http://mirrors.163.com/pypi/simple/
[install]
trusted-host=mirrors.163.com
[root@room9pc01 day09]# pip3 install pymysql
#离线安装
[root@room9pc01 zzg_pypkgs]# cd pymysql_pkgs/
[root@room9pc01 pymysql_pkgs]# ls
asn1crypto-0.24.0-py2.py3-none-any.whl
cffi-1.11.5-cp36-cp36m-manylinux1_x86_64.whl
cryptography-2.4.2-cp34-abi3-manylinux1_x86_64.whl
idna-2.7-py2.py3-none-any.whl
pycparser-2.19.tar.gz
PyMySQL-0.9.2-py2.py3-none-any.whl
six-1.11.0-py2.py3-none-any.whl
[root@room9pc01 pymysql_pkgs]# pip3 install *
配置mysql或mariadb
- 安装
- 启动
- 修改密码
- 创建数据库
[root@room9pc01 ~]# yum install -y mariadb-server
[root@room9pc01 ~]# systemctl start mariadb
[root@room9pc01 ~]# mysql -uroot -ptedu.cn
MariaDB [(none)]> CREATE DATABASE nsd1812 DEFAULT CHARSET utf8;
案例:小型企业员工数据库
1、为一个小型企业编写数据库,能够记录员工信息,记录发工资情况。
2、经过调查,需要这些字段:姓名、出生日期、联系方式、部门、工资日、基本工资、奖金、总工资。
3、关系型数据库,应该尽量减少数据冗余(重复的数据)。
#关系型数据库字段需要满足数据库范式:
- 所谓第一范式(1NF)是指在关系模型中,所有的域都应该是原子性的。联系方式不满足1NF,因为它包括家庭住址、电话号码、email等,所以要把联系方式拆分成更小的项目。
- 2NF在1NF的基础上,非码属性必须完全依赖于码。简单来说就是表需要一个主键。根据2NF,最好为员工表加上员工ID作为主键;工资表应该记录的是员工ID,而不是员工姓名,但是员工ID也不能成为主键,因为每个月都要发工资,用现有的任何字段作为主键都不合适,干脆强加一个主键。
- 第三范式(3NF)任何非主属性不得传递依赖于主属性,非主属性不能依赖其他非主属性。工资表中的总工资依赖于基本工资和奖金,它不应该出现在表中。
[root@room9pc01 day09]# vim py_mysql.py
import pymysql
conn = pymysql.connect( #创建连接
host='127.0.0.1',
port=3306,
user='root',
passwd='123456',
db='nsd1812',
charset='utf8'
)
#游标
#• 游标(cursor)就是游动的标识
•# 通俗的说,一条sql取出对应n条结果资源的接口/句柄,就是游标,沿着游标可以一次取出一行
cursor = conn.cursor()
#创建表
#create_dep = '''CREATE TABLE departments(
#dep_id INT, dep_name VARCHAR(50),
#PRIMARY KEY(dep_id)
#)'''
#create_emp = '''CREATE TABLE employees(
#emp_id INT, emp_name VARCHAR(50), email VARCHAR(50), dep_id INT,
#PRIMARY KEY(emp_id), FOREIGN KEY (dep_id) REFERENCES departments(dep_id)
#)'''
#create_sal = '''CREATE TABLE salary(
#id INT, date DATE, emp_id INT, basic INT, awards INT,
#PRIMARY KEY(id), FOREIGN KEY(emp_id) REFERENCES employees(emp_id)
#)'''
#cursor.execute(create_dep)
#cursor.execute(create_emp)
#cursor.execute(create_sal)
###################################################
#插入语句
#insert_dep = 'INSERT INTO departments VALUES (%s, %s)'
#cursor.executemany(insert_dep, [(1, '人事部')])
#deps = [(2, '财务部'), (3, '运维部'), (4, '开发部'),(5, '测试部'), (6, '市场部')]
#cursor.executemany(insert_dep, deps)
##################################################
#基础查询
#select1 = 'SELECT * FROM departments'
#cursor.execute(select1) #游标默认停留在第一行
#print(cursor.fetchone()) #读取游标所在行记录的数据(游标自动下移一行)
#print('*' * 20)
#print(cursor.fetchmany(2)) #读取游标自当前行之后的2条记录(游标自动下移一行)
#print('*' * 20)
#print(cursor.fetchall()) #读取游标自当前行之后所有行
##################################################
#移动游标
#select1 = 'SELECT * FROM departments ORDER BY dep_id'
#cursor.execute(select1)
#cursor.scroll(2, mode='relative') # 以相对方式向下移动2行记录
#print(cursor.fetchone())
#print('*' * 20)
#cursor.scroll(0, mode='absolute') # 以绝对方式移动到第1行记录
#print(cursor.fetchone())
#################################################
#修改
#update1 = 'UPDATE departments set dep_name=%s WHERE dep_name=%s'
#cursor.execute(update1, ('人力资源部', '人事部'))
#################################################
#删除
#delete1 = 'DELETE FROM departments WHERE dep_name=%s'
#cursor.execute(delete1, ('市场部',))
conn.commit() #对数据库做修改操作,必须要commit(提交)
cursor.close()
conn.close() #断开连接
sqlalchemy模块
可以操作各种数据库,如mysql、sql server、oracle等。它不需要书写sql语句,可以通过简单的python语法,实现对数据库的增删改查。
[root@room8pc16 zzg_pypkgs]# cd sqlalchemy_pkgs/
[root@room8pc16 sqlalchemy_pkgs]# pip3 install *
ORM:Object Relationship Mapping(对象关系映射)
- 对象:指OOP编程的方式
- 关系:关系型数据库
- 将python中的class映射到数据库的表
- class中的类变量映射到数据库表中的每个字段
- class的每个实例映射到数据库表中的每行记录
创建数据库
MariaDB [nsd1812]> CREATE DATABASE tedu1812 DEFAULT CHARSET utf8;
[root@room9pc01 day09]# vim dbconn.py
from sqlalchemy import create_engine, Column, Integer, String, ForeignKey, Date
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
engine = create_engine(
#mysql+pymysql://用户名:密码@服务器/数据库?参数
'mysql+pymysql://root:123456@127.0.0.1/tedu1812?charset=utf8',
encoding = 'utf8',
#echo = True # 在屏幕上输出日志,生产环境中不要使用
)
#创建ORM的基类
Base = declarative_base()
Session = sessionmaker(bind=engine)
class Department(Base):
__tablename__ = 'departments' # 定义库中的表名
dep_id = Column(Integer, primary_key=True)
dep_name =Column(String(50), unique=True, nullable=False) #名称唯一,不能为空
class Employee(Base):
__tablename__ = 'employees' # 定义库中的表名
emp_id = Column(Integer, primary_key=True)
emp_name = Column(String(50), nullable=False) #不能为空
email = Column(String(50), unique=True, nullable=False)
dep_id = Column(Integer, ForeignKey('departments.dep_id'))
class Salary(Base): # 定义库中的表名
__tablename__ = 'salary'
id = Column(Integer, primary_key=True)
data = Column(Date, nullable=False)
emp_id = Column(Integer, ForeignKey('employees.emp_id'))
basic = Column(Integer)
awards = Column(Integer)
if __name__ == '__main__':
# 如果库中没有相关的表则创建,有的话不会创建
Base.metadata.create_all(engine)
数据库常用操作
from dbconn import Session, Department, Employee, Salary
session = Session()
###########################################
# hr = Department(dep_id=1, dep_name='人事部')
# finance = Department(dep_id=2, dep_name='财务部')
# ops = Department(dep_id=3, dep_name='运维部')
# dev = Department(dep_id=4, dep_name='开发部')
# qa = Department(dep_id=5, dep_name='测试部')
# session.add_all([hr, finance, ops, dev, qa])
#############################################
# wt = Employee(
# emp_id=1,
# emp_name='王涛',
# email='wangtao@qq.com',
# dep_id=3
# )
# zj = Employee(
# emp_id=2,
# emp_name='张钧',
# email='zhangjun@163.com',
# dep_id=3
# )
# sy = Employee(
# emp_id=3,
# emp_name='苏艳',
# email='suyan@qq.com',
# dep_id=1
# )
# wjy = Employee(
# emp_id=4,
# emp_name='吴计印',
# email='wujiying@126.com',
# dep_id=4
# )
# kzw = Employee(
# emp_id=5,
# emp_name='康志文',
# email='kangzhiwen@qq.com',
# dep_id=4
# )
# hzq = Employee(
# emp_id=6,
# emp_name='胡志强',
# email='huzhiqiang@163.com',
# dep_id=5
# )
# lh = Employee(
# emp_id=7,
# emp_name='李浩',
# email='lihao@126.com',
# dep_id=2
# )
# session.add_all([wt, zj, sy, wjy, kzw, hzq, lh])
#########################################################
#qset1 = session.query(Department)
#print(qset1) # qset1只是个sql语句,当取具体值的时候,才真正查数据库
# qset1.all()取出全部的部门,因为查询的是类名,所以返回所有的实例组成的列表
#print('*' * 30)
#print(qset1.all())
#print('*' * 30)
#for dep in qset1: # 遍历实例列表中的每个实例
# print('%s: %s' % (dep.dep_id, dep.dep_name))
##########################################################
# qset2 = session.query(Department).order_by(Department.dep_id) #按部门id号排序查询
# for dep in qset2: #遍历实例列表中的每个实例
# print('%s: %s' % (dep.dep_id, dep.dep_name))
##########################################################
# qset3 = session.query(Employee.emp_name, Employee.email) #查询员工对应邮箱
# 查询的参数是字段,返回的结果是元组
# for item in qset3:
# print(item)
# print('*' * 30)
# for name, email in qset3:
# print('%s: %s' % (name, email))
#########################################################
# qset4 = session.query(Department).order_by(Department.dep_id)[1:4] #查询按部门id号排序后的第2、3、4个部门名称
# for dep in qset4: #遍历实例列表中每个实例
# print('%s: %s' % (dep.dep_id, dep.dep_name))
########################################################
# qset5 = session.query(Department).filter(Department.dep_id==2) #查询部门id为2的部门名称
# print(qset5)
# print(qset5.all()) #all()返回列表
# dep = qset5.one() # 返回一个实例,如果返回值不是一个,将报错
# print(dep.dep_id, dep.dep_name)
###########################################################
# qset6 = session.query(Department).filter(Department.dep_id>1).filter(Department.dep_id<4) 查询部门id大于1小于4的部门名称
# for dep in qset6:
# print(dep.dep_id, dep.dep_name, sep=': ') #打印时,部门id和部门名称之间用:隔开
######################################################
# qset7 = session.query(Employee).filter(Employee.email.like('%@qq.com')) #模糊查询,查询使用qq邮箱的员工姓名
# for emp in qset7:
# print(emp.emp_name, emp.email)
#########################################################
# qset8 = session.query(Department).filter(Department.dep_id.in_([3, 4])) #查询部门id在[3,4]范围内的部门名称
# for dep in qset8:
# print(dep.dep_id, dep.dep_name)
#######################################################
# qset9 = session.query(Department).filter(Department.dep_name.isnot(None)) #查询部门名称不是非空的部门
#for dep in qset9:
# print(dep.dep_id, dep.dep_name)
########################################################
# query中先写的是Employee,join中要写Department
# qset10 = session.query(Employee.emp_name, Department.dep_name).join(Department) #多表查询
# for row in qset10:
# print(row)
########################################################
# 修改数据,先找到实例,再给实例的属性重新赋值
# qset11 = session.query(Department).filter(Department.dep_name=='人事部')
# hr = qset11.one()
# hr.dep_name='人力资源部'
########################################################
# 删除,只要找到实例,然后删除即可
# qset12 = session.query(Employee).filter(Employee.emp_id==6)
# emp = qset12.one()
# session.delete(emp)
##########################################################
session.commit()
session.close()