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.')
<callable-iterator object at 0xb70be62c>
>>> 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()