RE模块

    核心函数和方法

        match函数

            尝试用正则表达式模式从字符串的开头匹配,如果匹配成功,则返回一个匹配对象,否则返回None

            >>> re.match('foo','food')   #在food 搜索foo
             <_sre.SRE_Match object at 0xb70babb8>
            >>> m = re.match('foo','food')
            >>> m.group()
            'foo'
            >>> m = re.match('foo','seafood')   # 在seafood中匹配foo,匹配不到,因为match是从开头开始匹配
            >>> print m
            None


        search函数

            在字符串中查找正则表达式模式的第一次出现,如果匹配成功,则返回一个匹配对象否则返回Non

            >>> m = re.search('foo','seafood') # 在seafood中匹配foo,search在字符串中匹配。
            >>> m.group()
            'foo'

        group函数

            使用match或search匹配成功后,返回的匹配对象可以使用group方法获得匹配内容

        findall

            >>> m = re.search('foo','seafood is food.')
            >>> m.group()
            'foo'
            >>> re.findall('foo','seafood is food.')
            ['foo', 'foo']

        finditer

            >>> re.finditer('foo','seafood is food.')
            
            >>> m = re.finditer('foo','seafood is food.')
            >>> for i in m:
            ...   print i.group()
            ...
            foo
            foo

        compile函数

            对正则表达式模式进行编译,返回一个正则表达式对象

            不是必须使用这种方式,但是在大量匹配情况下,可以提升效率

            >>> import re
            >>> patt = re.compile('foo')
            >>> m = patt.match('food')
            >>> print m.group()
            foo

        split方法

            根据正则表达式中的分隔符把字符串分隔为一个列表,并返回匹配成功的列表

            字符串也有

            >>> mylist = re.split('\.|-','hell-world.data')   #使用'.'和‘-’作为字符串的分隔符
            >>> print mylist
            ['hell', 'world', 'data']


        sub方法

            把字符串中所有匹配正则表达式的地方替换成新的字符串

            >>> import re
            >>> re.sub('X','Mr. Smith','Hi X, Nice to see you X.')
            'Hi Mr. Smith, Nice to see you Mr. Smith.'

        groups

            >>> import re

            >>> m = re.search("(tom)orrow","I will see you tomorrow.")
            >>> m.group()
            'tomorrow'
            >>> m.groups()
            ('tom',)
            >>> m.groups(1)
            ('tom',)

>>> m = re.search("(tom)or(row)","I will see you tomorrow.")
>>> m.group()
'tomorrow'
>>> m.groups()
('tom', 'row')
>>> m.groups(1)
('tom', 'row')
>>> m.groups(2)
('tom', 'row')
>>> m.group(1)
'tom'
>>> m.group(2)
'row'

注意分组情况

            >>> m = re.search('((b(c))d)e','abcdef')
            >>> m.group()
            'bcde'
            >>> m.group(1)
            'bcd'
            >>> m.group(2)
            'bc'
            >>> m.group(3)
            'c'

    正则表达式

        匹配单个字符


说明
.
匹配任意字符,换行符除外
[...x-y...] 匹配字符组里的任意字符
[^...x-y...]
匹配不再字符组里的任意字符
\d
匹配任意数字,与[0-9]同义
\D
匹配非数字
\w
匹配任意数字字母下划线,与[0-9a-aA-Z_]同义
\W
\w的反,匹配非数字字母下划线
\s
匹配空白字符,与[\r\v\f\t\n]同义
\S
\s的反,匹配非空格字符

        匹配一组字符

符号
说明
literal
匹配字符串的值
re1|re2
匹配正则表达式re1或re2
*
匹配前面出现的正则表达式零次或多次
+
匹配前面出现的正则表达式一次或多次

匹配前面出现的正则表达式零次或一次
{M,N}
匹配前面出现的正则表达式至少M次最多N次

        其他元字符

符号
说明
^
匹配字符串的开头
$
匹配字符串的结尾
\b

匹配单词的边界

echo "tom tomorrow" | grep '\btom\b'

()
对正则表达式分组
\nn
匹配已保存的分组

        贪婪匹配

            *、+和?都是贪婪匹配操作符,在其后加上?可以取消其贪婪匹配行为

            正则表达式匹配对象通过groups函数获取子组

            >>> import re
            >>> data = 'My phone number is:15088889999'
            >>> m = re.search('.+(\d+)',data)
            >>> print m.groups()
            ('9',)
            >>> m = re.search('.+?(\d+)',data)
            >>> m.groups()
            ('15088889999',)

分析apache访问日志

    编写一个apache

1、统计每个客户端访问apache服务的次数

2、将统计信息通过字典的方式显示出来

3、分别统计客户端是Firefox和MSI的访问次数

4、分别使用函数式编程和面向对象编程的方式实现

#!/usr/bin/env python
# coding: utf8

import re

def count_patt(fname,patt):
    patt_dict = {}
    cpatt = re.compile(patt)
    with open('fname') as fobj:
        for line in fobj:
            m = cpatt.search(line)
            if m:
                key = m.group()
                '''if key not in patt_dict:
                    patt_dict[key] = 1
                else:
                    patt_dict[key] +=1'''
                # 如果key不在字典中,值为1,否则值加1.
                patt_dict[key] = patt_dict.get(key,0) + 1
                return patt_dict

def sort(adict):
    alist = []
    patt_list = addict.items()
    for i in range(len(patt_list)):
        greater = patt_list[0]
        for j in range(len(patt_list[1:])):
            '''if greater[1] < patt_list[j + 1][1]:
                greater = patt_list[j + 1]'''
            greater = greater if greater[1] > = patt_list[j + 1][1] else patt_list[j + 1]
        alist.append(greater)
        patt_list.remove(greater)
        return alist

if __name__ == '__main__':
    log_file = '/var/log/httpd/access.log'
    ip_patt ='^(\d+\.){3}\d+'
    br_patt = 'Firefox|MSIE'
    print count_patt(log_file,ip_patt)
    print count_patt(log_file,br_patt)
    ip_count = count_patt(log_file,ip_patt)
    print ip_count
    print sort(ip_count)


>>> import tab
>>> import collections
>>> c = collections.Counter()
>>> c
Counter()
>>> c.update('abc')
>>> c
Counter({'a': 1, 'c': 1, 'b': 1})
>>> c.update('ab')
>>> c
Counter({'a': 2, 'b': 2, 'c': 1})
>>> c.update('a')
>>> c
Counter({'a': 3, 'b': 2, 'c': 1})
>>> c = collections.Counter()
>>> c.update(('192.168.1.1',))
>>> c
Counter({'192.168.1.1': 1})
>>> c.update(('192.168.1.3',))
>>> c.update(('192.168.1.34',))
>>> c
Counter({'192.168.1.3': 1, '192.168.1.34': 1, '192.168.1.1': 1})
>>> c.update(('192.168.1.34',))
>>> c.update(('192.168.1.34',))
>>> c
Counter({'192.168.1.34': 3, '192.168.1.3': 1, '192.168.1.1': 1})
>>> c.most_common(1)
[('192.168.1.34', 3)]
>>> c.most_common(2)
[('192.168.1.34', 3), ('192.168.1.3', 1)]


#!/usr/bin/env python
#coding; utf8

import re
import collections
class CountPatt(object):
    def __init__(self,patt):
        self.cpatt = re.compile(patt)
    def count_patt(self,fname):
        c = collections.count()
        with open(fname) as fobj:
            for line in fobj:
                m = self.cpatt.search(line)
                if m:
                    c.update(m.group())
        return c

if __name__ == '__main__':
    log_file = '/var/log/httpd/access.log'
    ip_patt ='^(\d+\.){3}\d+'
    br_patt = 'Firefox|MSIE'
    c1 = CountPatt(ip_patt)
    print c1.count_patt(log_file)
    print c1.count_patt(log_file).most_common(2)
    c2 = CountPatt(br_patt)
    print c2.count_patt(log_file)
    print c2.count_patt(log_file).most_common(2)


socket模块

技术

    C/S B/S Peer to Peer

地域

    LAN / WAN / MAN

安全

    intranet / /extranet/internet

    c/s架构

        什么是C/S架构

            服务器是一个软件或硬件,用于提供客户需要的“服务”

            硬件上,客户端常见的就是平时所使用的pc机,服务器常见的有联想、DELL等厂商生产的各种系列服务器

            软件上,服务器提供的服务主要是程序的运行,数据的发送与接受、合并、升级或其它的程序或数据的操作

        套接字

            套接字是一种具有“通讯端点”概念的计算机网络数据结构

            套接字起源于20世纪70年代,加利福尼亚大学伯克利分校版本的Unix

            一种套接字是Unix套接字,其“家族名”为AF_UNIX

            另一种套接字十基于网络的,“家族名”为AF_INET

            如果把套接字比作电话的插口,那么主机与端口就像区号与电话号码的一对组合

        面向连接和无连接

            无论是哪一种地址家族,套接字的类型只有两种。一种是面向连接的,一种是无连接的套接字

            无连接的主要协议十用户数据包协议(UDP),套接字类型为SOCK_DGRAM

            python中使用socket模块中的socket函数实现套接字的创建

    socket函数与方法

        创建TCP服务器

            创建Tcp服务器的主要步骤如下:

            1、创建服务器套接字: s = sockets.socket()

            2、绑定地址到套接字: s.bind()

            3、启动监听:s.listen()

            4、接受客户连接: s.accept()

            5、与客户端通信:recv()/send()

            6、关闭套接字:s.close()

tcpsrv.py

#!/usr/bin/env python
#coding:utf8

import socket

host = ''  #指定该服务运行的地址,空字符串表示:0.0.0.0
port = 12345  #端口号必须是整数(int)类型
addr = (host,port)
#创建套接字socket(模块名).socket(模块内方法)(socket.AF_INET(地址家族),socket.SOCK_STREAM(套接字类型,TCP用STREAM表示))
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#程序默认行为:比如程序默认使用了一个端口,当程序结束了,该套接字/端口会被系统保留一分钟。
#为了避免这样的情况(端口/套接字不被占用),设置套接字的选项
#SOL_SOCKET套接字本身
#SO_REUSEADDR,是否允许重用地址,1表示允许,一般服务器端会设置这个选项
s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)

#绑定IP 和端口号
s.bind(addr)
#监听
#listen里面接受一个数值,很多系统支持到5
s.listen(1)
#accept返回一个元组,客户机的套接字,客户机的地址,记住一个阻塞的概念
cli_sock,cli_addr = s.accept()
print "Got connetion from : ",cli_addr
#从客户机接收数据存到data中
data = cli_sock.recv(4096)
print data
#向客户端发送数据
cli_sock.send("I C U!\n")
#关闭客户端套接字
cli_sock.close()
#关闭服务器端的套接字
s.close()

测试:

1终端

# python tcpsrv.py

2终端

# netstat -ntpl | grep 12345

# telnet Ip  12345

        创建TCP时间戳服务器

        编写一个tcp服务器

            1.服务器监听在0.0.0.0的12345 的端口上

            2.收到客户端数据后,将其加上时间戳后返回给客户端

            3.如果客户端发过来的字符全是空白字符,则终止与客户端的连接

#!/usr/bin/env python
#coding: utf8
import socket
import time

host = ''   #0.0.0.0
port = 12345

addr = (host,port)

s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
s.bind(addr)
s.listen(1)

while True:
    cli_sock,cli_addr = s.accept()
    print "Got connection from :", cli_addr
    while True:
        data = cli_sock.recv(4096)
        if not data.strip():
            break
        print data
        cli_sock.send("[%s] %s" % (time.ctime(),data))
    cli_sock.close()
s.close()

        创建TCP客户端

            创建TCP客户端的步骤主要如下:

            1、创建客户端套接字:cs = socket.socket()

            2、尝试连接服务器:cs.connect()

            3、与服务器通信:cs.send()/cs.recv()

            4、关闭客户端套接字:cs.close()

#!/usr/bin/env python
#coding: utf8
import socket

host = '172.40.3.217'  # 要连接的服务器的IP
port = 12345 #要连接服务器的端口
addr = (host,port)
#创建套接字,家族是AF_INET,类型是SOCK_STREAM
c = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#连接服务器
c.connect(addr)

while True:
    data = raw_input('> ')
    if not data:
        break
    c.send(data)  #将数据发送给服务器
    print c.recv(4096)

c.close()


WEB.py

#!/usr/bin/env python

import socket

host = ''
port = 80
addr = (host,port)

with open('/var/www/html/index.html') as fobj:
    contents = fobj.read()

s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
s.bind(addr)
s.listen(1)

while True:
    cli_sock,cli_addr = s.accept()
    cli_sock.send(contents)
    cli_sock.close()

s.close()

        创建UDP服务器

            创建UDP服务器的主要步骤如下:

                1、创建服务器套接字: s = socket.socket()

                2、绑定服务器套接字:s.bind()

                3、接收、发送数据:s.recvfrom()/s.sendto()

                4、关闭套接字:s.close()

            创建UDP时间戳服务器

                编写一个UDP服务器

                1 、服务器监听在0.0.0.0的12345端口

                2、r接收客户端数据后,将其加上时间戳后回送给客户端

#!/usr/bin/env python
#coding: utf8
import  socket
import time

host = ''
port = 12345
addr = (host,port)

# 创建套接字。家族AF_INET,类型:SOCK_DGRAM
s =  socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
#保证程序退出之后可以立即运行
s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
s.bind(addr)

while True:
    data,cli_addr = s.recvfrom(4096)  #recvfrom 返回发送方的数据和地址
    #收到的数据在发挥给发送方,数据,目的地地址
    s.sendto("[%s] %s" % (time.ctime(),data),cli_addr)
#关闭套接字
s.close()

        创建UDP客户端

        创建UDP客户端的步骤主要如下:

        1.创建客户端套接字:cs = socketsocket()

        2.与服务器通信: cs.sendto()/cs.recvfrom()

        3.关闭客户端套接字: cs.close()

#!/usr/bin/env python
#coding: utf8

import socket
import sys

host = sys.argv[1]
port = int(sys.argv[2])
addr = (host,port)

c = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

while True:
    data = raw_input('> ')
    if not data:
        break
    c.sendto(data,addr)  #发送给addr服务器的数据。
    print c.recvfrom(4096) #输出接受到的数据,默认返回数据,服务器地址,服务器端口

    print c.recvfrom(4096)[0]

c.close()