数学建模社区-数学中国
标题:
Python爬虫 正则表达式应用详解
[打印本页]
作者:
杨利霞
时间:
2020-3-30 11:00
标题:
Python爬虫 正则表达式应用详解
6 X" y G; V0 m
Python爬虫 正则表达式应用详解
+ A; j- @% H/ Q( F
. G. D4 d5 K7 x: ^4 ]7 t
学习Python爬虫过程中的心得体会以及知识点的整理,方便我自己查找,也希望可以和大家一起交流。
2 d2 c* _: ]5 n+ h* ~( [
k- B6 n) J) W' }- J @9 F
—— 正则表达式应用详解 ——
* `; \. Q0 o# z$ l0 p7 d# t7 X
1 e% @# P7 ]* \3 ]/ X
文章目录
6 B' O, U, T* J. p: g5 i8 {
5 X, o# H F9 }0 k
Python爬虫(二十一)
E- M" J* o. F9 z
—— 正则表达式应用详解 ——
* \ W- r% [- L4 j: [: d
1. 简介
% j3 s8 C9 l, h! q
2. 语法
' `& B$ |% C* B s
3. 部分元字符应用详解
* A5 i0 Q* Q' G. s4 U# I T
^
) u6 h5 v" l0 I7 V& N g
$
' U& O' U" D9 [( r( |
\A
8 _, G$ o# p1 S Z) m7 ~: c
\b
- p2 H8 V8 i4 s# i( }+ f8 E F
\B
) S* Y. v- D: R t& p
3. 正则表达式实例
0 x; t2 I( b, v9 s6 f* v+ ^3 J& J) S
相关文章:
5 g" ~7 P: \- Q+ [4 t/ T& g t
1.Python的Re库应用详解(正则表达式的库)
( k1 x8 q9 G) v0 U7 \6 B
2.Python的Re库与正则表达式的细节解析(正则表达式的库)
/ Q, X! i$ h8 ]3 ^2 q2 n9 p( I9 u
' t+ @8 }9 G( r2 L
1. 简介
2 N. v# a4 ]! Z4 ~
/ }# U+ d" P; ?+ ]
正则表达式:regular expression,也称regex,简称 RE
" k5 y X+ S. |5 u( ?( r+ O
+ g; j. X6 x! M% a! Q% ^
正则表达式模式被编译成一系列的字节码,然后由一个 C 语言写的匹配引擎所执行。
6 ?0 P9 h* ~$ x; P4 C) ?: q
' D) H% d* u% Z3 ^: e
正则表达式是用来简洁表达一组字符串的表达式
" X. A) \# W9 J
. p5 |3 A- M; T/ Q6 u4 g
通用的字符串表达框架
; A. s3 w" n5 q: `1 C- W [9 ]! E
k5 b! J6 Q7 h7 P, N8 e) v9 J
简洁表达一组字符串的表达式
6 Q# F9 {+ z7 H3 M
5 q1 y1 c4 B6 s* v6 B( y9 N
针对字符串表达“简洁”和“特征”思想的工具
- B5 c7 \% i8 r' s8 a
+ j6 r w/ ?6 ?7 w: H
判断某字符串的特征归属
/ H% j3 E( {( [3 k$ `6 P
: n/ h0 Q( j/ h' L5 ?, i4 x6 j3 |
正则表达式在文本处理中十分常用
r( U) \$ B: x) {# n
8 ?- B- i/ a# [% m
表达文本类型的特征(病毒、入侵等)
2 O n3 w4 N) w0 h: Q: o, y
, ^; B$ E: W. X( H
同时查找或替换一组字符串
0 d& I$ J/ l0 a0 M4 [3 f. P
. }" \6 L# a& B( j
匹配字符串的全部或部分
" p* b4 A" P" A, g: c6 g, i: O9 x
, Y9 k# k# x5 g$ k3 _4 Z. H
正则表达式的使用
0 |4 @" A1 T. z+ N3 a4 l! C
- t, u1 l( r6 D% T" r/ n
编译:将符合正则表达式语法的字符串转换成正则式表达特征
9 H. W- R( ]5 M& G) U' ]
$ Z9 }/ @: Y# a9 z- a+ P4 O
* X# u8 v2 `. q7 t' P. h- {9 _
2. 语法
n, d( b; o: ?* ~3 o& w4 z
' {$ k/ {) {3 r V
正则表达式语法由字符和操作符构成
3 u) @& Q( S/ g/ ^1 C. n, B
2 I, h2 D) p/ b! @
有一些符号不能匹配自身,它们定义了字符类、子组匹配和模式重复次数等功能,被称为元字符 (metacharacter)。
4 G& F" z# V! J, v, S+ a4 C5 K7 S
元字符包括:. ^ $ * + ? { } [ ] \ | ( )
( T6 z/ E- Z+ c# a
正则表达式的常用操作符
' w7 Z9 ^: D6 r, @
在反斜杠后边紧跟着一个元字符,那么元字符的“特殊功能”也不会被触发
9 R8 l1 c1 T& g8 }1 B+ W8 y
操作符 说明 实例
0 g l! X8 h" `$ ^/ z
. 表示任何单个字符(除换行符) 【注1】
% j! K1 U+ U) k* }
[ ] 字符集,对单个字符给出取值范围,元字符在方括号中不会触发功能 [abc$]表示a、b、c、$,[a--z]表示a到z单个字符
W" {8 b# F6 `! S' H% V
[^ ] 非字符集,对单个字符给出排除范围 [^abc]表示非a或b或c的单个字符
# }, l- d/ T; l# j, f3 Q; t, z
* 前一个字符0次或无限次扩展 【注2】 abc* 表示 ab、abc、abcc、abccc等
. d1 T; j1 M# ?4 _. `
+ 前一个字符1次或无限次扩展 abc+ 表示 abc、abcc、abccc等
* K1 M: h) j$ ?" e& }+ c1 J
? 前一个字符0次或1次扩展 abc?表示 ab、abc
4 W) `/ `) b0 X {0 R
| 左右表达式任意一个 【注3】 |abc|def 表示 abc、def
3 h4 n& K5 o7 ^ ?5 k3 c
{m} 扩展前一个字符m次 ab{2}c 表示 abbc
7 |1 I0 K/ J) M s+ p( N1 c
{m,n} 扩展前一个字符m至n次(含n) 【注4】 ab{1,2}c 表示 abc、abbc
% B* T2 B% `" }; ]# H" L
^ 匹配字符串开头 ^abc 表示abc且在一个字符串的开头
7 }6 M5 r1 q' E6 K; h* d8 m
$ 匹配字符串结尾 abc$ 表示abc且在一个字符串的结尾
9 P3 e# ]9 w1 Y
( ) 分组标记,内部只能使用 | 操作符 (abc) 表示abc,(abc|def) 表示 abc、def
; S8 }) d# W, I. J
\ 后边跟元字符去除特殊功能,跟普通字符实现特殊功能,如需消除反斜杠的特殊功能只需在前面再加一个反斜杠\\ \d \w \u
( G- z7 D6 f* d2 A
\d 匹配十进制数字,等价于[0--9]
1 k- f+ ?; `7 @& d& b$ L. \1 n( o
\D 与 \d 相反,匹配非十进制数字的字符,相当于 [^0-9]
; x" b' `/ j2 n4 u" b' @' c7 K
\s 匹配空白字符(包含空格、换行符、制表符等),等价于 [ \t\n\r\f\v]
' S6 A+ x# g7 i/ M
\S 与 \s 相反,匹配非空白字符,等价于 [^ \t\n\r\f\v]
4 P0 I0 r4 q( k4 v
\w 单词字符 【注5】 ,等价于[A--Z,a--z,0--9]
( J; }0 v$ J; l( n9 D3 f# ^+ l
\W 于 \w 相反
, a4 V$ d* g* x: j
\b 匹配单词的开始或结束
5 X) ? Z- a1 A( B
\B 与 \b 相反
" p" v3 J, E6 A1 l( U6 t% W# q: k& M
\Z 只匹配字符串的结束位置。
0 W( Q5 g5 O: _. X$ j
【注1】:如果设置了 re.DOTALL 标志,. 将匹配包括换行符在内的任何字符。
$ W" S; f* L, f( W) H
* X- |5 S& C. U. R5 q/ l
【注2】:由于受到 C 语言的 int 类型大小的内部限制,正则表达式引擎会限制字符重复个数不超过 20 亿个;
/ ?0 O, r+ d1 ?! l# S) [# _( X* J
# }. I1 R0 ~! B% B. S0 n
【注3】:为了能够更加合理的工作,| 的优先级非常低。例如 banana|orange 应该匹配banana 或 orange,而不是匹配 banan,然后一个 ‘a’ 或 ‘o’。同样,我们使用 \| 来匹配 |字符本身;或者包含在一个字符类中,像这样 [|]。
/ L" b- U" B5 A! m5 L9 G' _3 D* ~
: p7 q) {/ {6 g
【注4】:可以省略 m 或者 n,引擎会假定一个合理的值代替。省略 m,将被解释为下限 0;省略 n 则会被解释为无穷大(事实上是上边我们提到的 20 亿)。
( k8 ~) e1 Q E$ @2 f1 u
# y, ^. Z2 P1 m6 n; `
【注5】:\w 匹配任何字符。如果正则表达式以字节的形式表示,这相当于字符类 [a-zA-Z0-9_];如果正则表达式是一个字符串,\w 会匹配所有 Unicode 数据库(unicodedata 模块提供)中标记为字母的字符。你可以在编译正则表达式的时候,通过提供 re.ASCII 表示进一步限制 \w 的定义。
" u7 @& d* k+ |2 }
5 Z" ^6 M" ~8 L% Y4 ], U0 n* h3 P, \
3. 部分元字符应用详解
7 ?; j( Q% t. y/ ^1 `3 l' V$ c3 x
6 G2 ]) N0 u2 @5 w+ L7 `0 \* H
^
) Y) ~7 G0 K" }" v( I
$ b/ S# v! k: [, p
匹配字符串的起始位置。如果设置了 MULTILINE 标志,就会变成匹配每一行的起始位置。在 MULTILINE 中,每当遇到换行符就会立刻进行匹配。
* ^+ Z9 k% {3 |& V- Z
v9 M* E, A0 g, W. o9 K: B
举个例子,如果你只希望匹配位于字符串开头的单词 From,那么你的正则表达式可以写为 ^From:
- z+ n5 I$ @4 m$ l( I
& x, e* H# A, A ^, T
print(re.search('^From', 'From Here to Eternity'))
+ I/ C3 ?. h0 J& K! J. `2 y2 P
print(re.search('^From', 'Reciting From Memory'))
" g0 X$ {3 B6 T: Z! C% ~' J
1
+ T" @$ }8 k. A+ c" Y6 ]* C9 ?$ H
2
_$ [" l1 m- _5 \# q
结果如图:
; c% e7 j2 o, Y
9 ?7 ~% g5 B( o9 D; k
' Q3 z; {) O4 v) U: N) L
$
, V, N( N5 B0 l: E% ]* U1 A$ [
0 G+ e' C5 x" `& _7 j( N' x/ N
匹配字符串的结束位置,每当遇到换行符也会离开进行匹配。
3 ], \( q5 X j
{- X& c- D; n% g H! L
print(re.search('}$', '{block}'))
w, ^: v. C+ \
$ I( A b! h- u6 U- V
print(re.search('}$', '{block} '))
- @: R. P5 j: d9 n3 a( C, m
- Z( X( i6 t# U9 M
print(re.search('}$', '{block}\n'))
. u, u- G6 o1 [+ m; r/ \# \
1
) I" n+ ]( o' z: b3 C6 F* V0 l$ N) C
2
6 o, }) b* I6 V( }. `5 z( f
3
- a7 Q4 k1 ^9 |( r6 Q4 Q) H, c# t
4
0 K" a/ X5 d; ?- ~
5
6 r' _( I9 @% f7 x3 s& c
结果如图:
, o) C( p: a9 W2 }# {
& e- J2 \% J# \. j& B' O1 I
# ~" l* Z- i3 S" n1 \
# E7 B5 b2 c) t# t4 s* x9 f
同样,我们使用 $ 来匹配 $字符本身;或者包含在一个字符类中,像这样 [$]。
4 G: x/ I0 Z8 X; i) o4 ~
# G9 z9 s( t" D/ g1 `- U
\A
" U d) K) V9 s( p
8 ]2 o8 [' I* X% d
只匹配字符串的起始位置。如果没有设置 MULTILINE 标志的时候,\A 和 ^ 的功能是一样的;但如果设置了 MULTILINE 标志,则会有一些不同:\A 还是匹配字符串的起始位置,但 ^ 会对字符串中的每一行都进行匹配。
2 ~( y- g6 R/ E6 y! O: `$ `
! X# M; j; [4 r( |3 f! A
\b
! R: ^$ c5 _+ _0 }. T1 K
/ E/ |# q- l. @. l. P/ E" [
单词边界,这是一个只匹配单词的开始和结尾的零宽断言。“单词”定义为一个字母数字的序列,所以单词的结束指的是空格或者非字母数字的字符。
. ]) P0 l% Q$ a2 C
* ~0 u' y$ d! z+ e* w
零宽断言相关信息请点击零宽断言查看。
3 r* z! \7 g; H2 L. g
{* Y, z- _- [& |; Q- h' e2 R! t
下边例子中,class 只有在出现一个完整的单词 class 时才匹配;如果出现在别的单词中,并不会匹配。
0 ?/ k0 \: a- j) B
* U. k/ U/ }4 A
p = re.compile(r'\bclass\b')
6 U# g& z! B: i( D# J2 I, o
print(p.search('no class at all'))
. e2 M6 a: ^ c# F& @! N
" t8 o; `8 E$ i, |
print(p.search('the declassified algorithm'))
! m; _$ N/ m6 f9 Y
- M' y, @) Z( g3 d& s( F
print(p.search('one subclass is'))
& F4 F* |+ E# q6 {) ^& [) u2 m
1
& y' l8 ?2 D8 v6 }" Z; |
2
, Y- j4 x4 n. t$ u
3
7 d4 S+ y5 e, u- G$ e
4
, B; q) s: k) Y/ W
5
& H* {9 L U- v; h0 N9 L3 F
6
3 u! ^# x* {) i0 O+ S4 s
结果如图:
/ y+ K9 q+ S# e% d5 K: u
0 f+ [$ O2 t$ q- _
在使用这些特殊的序列的时候,有两点是需要注意的:
* W6 r; \- B1 i; a7 Z. s$ D
: D# A8 m) f$ q
第一点是,Python 的字符串跟正则表达式在有些字符上是有冲突的。比如说在 Python 中,\b 表示的是退格符(ASCII 码值是 8)。所以,你如果不使用原始字符串,Python 会将 \b 转换成退格符处理,这样就肯定跟你的预期不一样了。
0 W: k# S5 L4 `9 z- M. A; v4 Y
相关原理和解决方法点击详情查看。
9 X- g2 G, D% M: m6 b; J
3 Y3 w9 a+ D' F" J( i% ]# F! o
第二点需要注意的是,在字符类中不能使用这个断言。跟 Python 一样,在字符类中,\b 只是用来表示退格符。
N" p; Y- }' U1 E' i5 T
2 n$ G* n) {2 r5 \
\B
& F8 G" U7 H4 e/ {; v+ J9 n2 w: q
; A8 n. |. G8 A O, k* }
另一个零宽断言,与 \b 的含义相反,\B 表示非单词边界的位置。
; W# n, ]$ \! }* S
0 w4 q/ v. @8 N+ i6 u1 g$ C3 V
3. 正则表达式实例
9 p0 y7 H: s4 x e; y1 I. ? _+ W
# d {6 c3 X- J2 y* O% q: n/ c
* c( k+ C" N; n6 {. R5 m
经典正则表达式实例
% m# q- x O0 `& y4 J* w
* q' m; ~# w$ k I1 S
匹配IP地址的正则表达式
6 `0 O& b+ A) h, p& a
9 h, ^: r+ ^9 ~7 u. s
IP地址字符串形式的正则表达式(IP地址分分4段,每段0-255) \d+.\d+.\d+.\d+ \d{1,3}.\d{1,3}.\d{1,3}.\d{1,3} 不精确
7 X$ a, z+ i: y- D# m
7 U0 d3 h7 Y, Q% p5 f# n9 M
精确写法
Q# s1 ~ `! [7 g# M, A9 E& X
" q7 L) V/ y& I$ W( g5 c r# J
0--99: [1--9]?\d 100--199: 1\d{2} 200--249: 2[0--4]\d 250--255: 25[0--5]
5 a- w# N6 z- C2 U- ]
(([1-9]?\d|1\d{2}|2[0--4]\d|25[0--5]).){3}([1--9]?\d|1\d{2}|2[0--4]\d|25[0--5])
% @: O9 J' Y5 t; L8 k
原文链接:https://blog.csdn.net/qq_44867435/article/details/105104177
( o, A7 Z8 q7 b7 Q, M, {/ u
% ~3 D2 j: q Q' g4 Y/ u) q
/ Y+ U+ y% |4 l, D0 S7 i+ Q/ S
欢迎光临 数学建模社区-数学中国 (http://www.madio.net/)
Powered by Discuz! X2.5