python:re模块、apache访问(次数、浏览器)日志分析、pymysql模块、sqlalchemy模块

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日志分析脚本

  1. 统计每个客户端访问apache服务器的次数
  2. 将统计信息通过字典的方式显示出来
  3. 分别统计客户端是Firefox、MSIE和Chrome的访问次数
  4. 分别使用函数式编程和面向对象编程的方式实现
#函数式编程
[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

  1. 安装
  2. 启动
  3. 修改密码
  4. 创建数据库
[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、关系型数据库,应该尽量减少数据冗余(重复的数据)。

#关系型数据库字段需要满足数据库范式:

  1. 所谓第一范式(1NF)是指在关系模型中,所有的域都应该是原子性的。联系方式不满足1NF,因为它包括家庭住址、电话号码、email等,所以要把联系方式拆分成更小的项目。
  2. 2NF在1NF的基础上,非码属性必须完全依赖于码。简单来说就是表需要一个主键。根据2NF,最好为员工表加上员工ID作为主键;工资表应该记录的是员工ID,而不是员工姓名,但是员工ID也不能成为主键,因为每个月都要发工资,用现有的任何字段作为主键都不合适,干脆强加一个主键。
  3. 第三范式(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()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值