之前有说过正则表达式,这里不想水了,直接上🔗链接.

文章链接

正则表达式回顾

匹配单个字符

  • . 任意单个字符
  • [] 括号列举的字符
  • /d 数字/D 非数字
  • /s 空白 /S 非空白
  • /w 非特殊字符(数字字母汉字下划线 /W 特殊字符

匹配多个字符

  • 匹配前一个字符0到多次*
  • 匹配前一个字符1到多次+
  • 匹配前一个字符0-1次(非贪婪匹配)?
  • 匹配前一个字符m次 {m}
  • 匹配前一个字符至少m次 {m,}
  • 匹配前一个字符m到n次{m,n}

分组匹配

首先了解分组是什么东西!一个括号()中的东西就可以是一个分组.

对于分组的操作, 可以取分组中的|左右的任意字符,也可以对分组其别名,方便后面复用.

  • | 匹配左右任意一个表达式
  • (ab) 将括号中字符作为一个分组
  • \num 引用分组num匹配到的字符串
  • (?P<name>) 分组起别名
  • (?P=name) 引用别名为name分组匹配到的字符串

Request需求

需求1:在列表中[“apple”, “banana”, “orange”, “pear”],匹配apple和pear

Demo

1
2
3
4
5
6
7
list = ["apple", "banana", "orange", "pear"]
# 遍历列表
for i in list:
# 如果i 是 apple 或者 pear 就为true, 最后打印匹配到的字符串
res = re.match("(apple|pear)", i)
if res:
print(res.group())

Result

1
2
apple
pear

需求2:匹配出163、126、qq等邮箱

1
2
# todo: 匹配括号中的(任意一个)字符4到20次,@就是@,括号是取|左右任意一个字符串,\是转义表示.为普通字符
regex = '[a-zA-Z0-9_]{4,20}@(163|126|qq|sina|yahoo)\.com'

需求3:匹配出hh

1
2
# todo: \\1 代表分组1 匹配到的字符串, 也就相当于跟分组1的正则格式相同
regex1 = "<([a-zA-Z1-6]+)>.*</\\1>"

需求4:匹配出

www.baidu.com

1
2
# todo: \\1,\\2太多分组会导致混乱,于是就使用了(?P<name>)分组起别名,(?P=name)引用别名
regex2 = "<(?P<分组1>[a-zA-Z1-6]+)><(?P<分组2>[a-zA-Z1-6]+)>.*<(?P=分组1)><(?P=分组2)>"

拓展Extension

  • match 从左边开始匹配, 严格匹配, 匹配不到就结束,匹配到就停止
  • search 从左往右匹配, 非严格匹配,只匹配一个,匹配到就停止,匹配不到就往下走到底
  • findall 从左往右匹配, 匹配到所有的字符, 直至匹配到字符串结束为止

Demo

1
2
3
4
5
6
7
str = '我最喜欢看的书是<<三国演义>>和<<西游记>>,以及<<红楼梦>>还有<<水浒传>>'
# todo: 得到所有的书名,但是由于数据匹配的时候默认是贪婪匹配的
# todo: 这里有两个两次*?, 代表匹配前面一个字符0到多次,而且是非贪婪匹配
regex3 = "<<.*?>>"
print(re.match(regex3, str))
print(re.search(regex3, str).group())
print(re.findall(regex3, str))

ReMatch和Search

语法

1
re.match(pattern, string, flags=0)

参数说明:

参数 描述
pattern 匹配的正则表达式
string 要匹配的字符串。
flags 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。参见:正则表达式修饰符 - 可选标志

可以使用group(num) 或 groups() 匹配对象函数来获取匹配表达式。

匹配对象方法 描述
group(num=0) 匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。
groups() 返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。

match和search之间的区别

  • match 是从头开始匹配的,如果字符串的开头没有匹配上, 匹配结束返回None
  • search 会搜索整个字符串, 看是否有能匹配上的内容

可选标志

正则表达式可以包含一些可选标志修 饰符来控制匹配的模式。修饰符被指定为一个可选的标志。

多个标志可以通过按位 OR(|) 它们来指定。如 re.I | re.M 被设置成 I 和 M 标志:

修饰符 描述
re.I 使匹配对大小写不敏感
re.L 做本地化识别(locale-aware)匹配
re.M 多行匹配,影响 ^ 和 $
re.S 使 . 匹配包括换行在内的所有字符
re.U 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B.
re.X 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。
  • re.compile方法

    使用compile函数将正则表达式的字符串形式编译为一个Pattern对象

  • 分组别名

(?P<name>…) 可以通过这种方式, 给() 起个别名, 起了别名之后, 就可以通过角标/别名访问对应() 中匹配上的内容

1
2
3
4
5
graph LR
正则表达式--> A(match方法)
A-->Match是从头开始匹配的,如果字符串的开头没有匹配上,匹配结束返回None
正则表达式--> search方法
search方法-->search会搜索整个字符串,看是否有能匹配上的内容

正则表达式处理Nginx日志对象

Nginx系统日志格式

image-20230524125654217

字段说明

字段1:real_ip(访问者来源ip)

字段3:access_time

字段5:req_method

字段6:request_uri

字段8:status

字段9:bytes

字段10:referer_url

字段11:ua

字段12:proxy_address

为什么需要进行nginx日志分析?

  • 用户行为分析:根据分析nginx日志,得到用户的pv和uv,能分析出系统网站的访问量和实际用户数,从而可以判断出该网站受欢迎程度,再与内部的客户关系管理系统对比,分析出访问用户和客户总体情况。为公司运营,服务器配比,融资等提供科学决策依据。
  • 异常用户筛选:根据分析日志信息,既可以根据ip解析出地理位置信息,又可以通过同一个ip在一定时间内访问的频次,筛选出爬虫用户或恶意访问用户,从而对这些用户进行加入黑名单操作,拦截网站的异常请求,保障系统网站的稳定运行。
  • 性能排查:根据分析nginx日志,得到响应耗时的url、以及请求时间,再得到这段时间的请求量,并发量,分析是并发的原因,还是本身就比较慢,如果是应用本身的原因,只需要找到对应的代码,再进行优化。

使用正则解析Nginx日志

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# coding:utf-8

if __name__ == '__main__':
import re

# python nginx日志解析方式
obj = re.compile(
r'(?P<ip>.*?) - - \[(?P<time>.*?)\] "(?P<request>.*?)" (?P<status>.*?) (?P<bytes>.*?) "(?P<referer>.*?)" "(?P<ua>.*?)" "(?P<proxy_address>.*)"')

nginx_log = [
'224.220.73.29 - - [07/May/2022:11:40:36 +0800] "GET /pa18shopnst/nstShop/128.html HTTP/1.1" 200 419 "http://baoxian.htv.com/pa18shopnst/" "Mozilla/5.0 (X11; OpenBSD i386) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36" "-"',
'224.192.169.90 - - [07/May/2022:11:40:36 +0800] "GET /zaixiangoumai/chexian/chexian.shtml HTTP/1.1" 200 964 "http://baoxian.htv.com?item=室内财产全方位保障" "Mozilla/5.0 (Linux; Android 10; PACM00 Build/QP1A.190711.020; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0" "-"',
'67.17.10.89 - - [07/May/2022:11:40:36 +0800] "GET /pa18shopnst/nstShop/index.html#/productInfo/resources/list?type=FILE&_t=0.7003008955390666 HTTP/1.1" 200 487 "http://baoxian.htv.com?item=汽车保险" "Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)" "-"',
]

for line in nginx_log:
result = obj.match(line)
ip = result.group("ip")
# ip = result.group(1)
time = result.group("time")
# time = result.group(2)
request = result.group("request")
status = result.group("status")
bytes = result.group("bytes")
referer = result.group("referer")
ua = result.group("ua")
proxy_address = result.group("proxy_address")
print(
"nginx解析日志后: ip:{ip}, time:{time}, request:{request}, status:{status}, bytes:{bytes}, referer:{referer}, ua:{ua}, proxy_address:{proxy_address}"
.format(ip=ip, time=time, request=request, status=status, bytes=bytes, referer=referer, ua=ua,proxy_address=proxy_address))