数学建模社区-数学中国
标题:
Python爬虫 正则表达式应用详解
[打印本页]
作者:
杨利霞
时间:
2020-3-30 11:00
标题:
Python爬虫 正则表达式应用详解
6 H* o2 A9 d+ e8 b
Python爬虫 正则表达式应用详解
& a4 |" E1 K9 f
, U5 h2 ]7 a% X1 w( Q5 n
学习Python爬虫过程中的心得体会以及知识点的整理,方便我自己查找,也希望可以和大家一起交流。
1 L4 o/ y' Z, u" Q' e2 B0 b
q8 x( K3 z' l* [
—— 正则表达式应用详解 ——
* V6 Q2 o y% j( `3 p! j9 k: p
' _& o8 U$ O% `7 F+ p. ^/ \. s& j
文章目录
: K5 e+ X7 K9 f6 t! w0 W, ~
4 N+ G4 Q: g5 P. q' S
Python爬虫(二十一)
' Z# C) H! [2 Q" C. g5 h o
—— 正则表达式应用详解 ——
! q% h& }, E* z6 `
1. 简介
# Y; r8 q6 B4 `, H( M# e1 ]
2. 语法
' i, V; E/ q9 Q; v- M
3. 部分元字符应用详解
# Q \: Y9 G' G. b& p- _, y3 R" T) e
^
2 |8 | S* Z- x+ J7 T$ `2 A6 {0 B) a
$
, \1 s1 r4 V$ C* R$ |
\A
5 x1 S3 V* ~6 Y W
\b
9 ]" J m6 n1 f7 ?- s
\B
3 @8 I0 S* U: }; R+ S" e: B
3. 正则表达式实例
' L- w( x, R1 Z0 U" r7 m% q+ [
相关文章:
" \* m* w% Z# ?; G
1.Python的Re库应用详解(正则表达式的库)
# ]3 H7 [% t/ C
2.Python的Re库与正则表达式的细节解析(正则表达式的库)
8 n* i5 _+ X- l
( m8 v1 B) w/ k# ` w- H& y
1. 简介
( O6 X v0 E7 R T: N/ J
$ _/ M$ o$ ?* |' `8 a% R
正则表达式:regular expression,也称regex,简称 RE
2 t' z5 H# [# [1 V; B" ~7 x9 F; g
* y! y( W1 j+ X H
正则表达式模式被编译成一系列的字节码,然后由一个 C 语言写的匹配引擎所执行。
. P$ L% `, B( H* M+ L% B3 u
/ H# H( ]: {. r: j- w' Y7 i4 V0 @
正则表达式是用来简洁表达一组字符串的表达式
. Y; h9 I( H! p8 J2 m3 N) n
! f' ]7 l( x; J& m) o6 b. ?3 Z3 B
通用的字符串表达框架
/ r. e& U& o" m+ @9 ]% K3 S
$ m* [; ?" ]$ ~+ X
简洁表达一组字符串的表达式
" U7 q5 U( Q/ o: k. k: A
$ W" N7 R# L) w
针对字符串表达“简洁”和“特征”思想的工具
! q% i: a4 p3 E0 U3 q) \
- B4 o3 k8 W% V
判断某字符串的特征归属
1 U" _4 h+ Q% q4 E+ j# ^
9 {, X3 o8 @( q1 \+ B* g3 _- K
正则表达式在文本处理中十分常用
. \" X( C, R4 G4 i7 ~4 h b
- W5 K( Y7 G9 s1 f7 d
表达文本类型的特征(病毒、入侵等)
) o3 |% H2 r3 b: l4 B# T
- d2 f8 i6 N1 M6 Q: t
同时查找或替换一组字符串
9 X7 a2 q& X/ ]% d" }
( N; N$ {) s* a5 N/ ]) i. R
匹配字符串的全部或部分
2 @! ]+ T/ R2 A, f
0 {# h% v5 E+ K' S n) ]
正则表达式的使用
1 y2 {" U& g- j% p
( H$ _2 i; i& `& @
编译:将符合正则表达式语法的字符串转换成正则式表达特征
7 x6 O* z; p5 p6 B0 b2 }
% y: x, c9 W `8 W+ J/ m% w
8 n D+ H8 f9 V$ A
2. 语法
+ ?/ j, s3 b1 V+ f8 v- h5 ?8 \
5 r" ]0 v7 Z* t A3 s2 \/ p ^( D) M
正则表达式语法由字符和操作符构成
* [( l1 z/ p8 c! Z( x0 G3 X, C# H
( u/ p5 Y5 F$ D- q7 a7 g
有一些符号不能匹配自身,它们定义了字符类、子组匹配和模式重复次数等功能,被称为元字符 (metacharacter)。
8 B- i5 M$ Y8 i1 w# N
元字符包括:. ^ $ * + ? { } [ ] \ | ( )
$ W6 }, ]$ E( u% X
正则表达式的常用操作符
& ?2 P7 C2 L. {; z: ^: ~( |3 t
在反斜杠后边紧跟着一个元字符,那么元字符的“特殊功能”也不会被触发
( S( o. T, X' ~* J5 q
操作符 说明 实例
- \! v# y; ^% Z @6 j6 D) @
. 表示任何单个字符(除换行符) 【注1】
8 s; p1 G3 j+ O, Q) ^( a" X7 a
[ ] 字符集,对单个字符给出取值范围,元字符在方括号中不会触发功能 [abc$]表示a、b、c、$,[a--z]表示a到z单个字符
d3 B3 ?5 p1 N( k
[^ ] 非字符集,对单个字符给出排除范围 [^abc]表示非a或b或c的单个字符
9 ^6 @. z/ U# I9 G+ F
* 前一个字符0次或无限次扩展 【注2】 abc* 表示 ab、abc、abcc、abccc等
, T0 u D, d- N, y: p3 k# U- K
+ 前一个字符1次或无限次扩展 abc+ 表示 abc、abcc、abccc等
. p" r+ X: P; |+ ~! m: |. G* X
? 前一个字符0次或1次扩展 abc?表示 ab、abc
/ L4 ]' E3 l/ m: V+ M
| 左右表达式任意一个 【注3】 |abc|def 表示 abc、def
, A/ n, U& M/ a8 I" W
{m} 扩展前一个字符m次 ab{2}c 表示 abbc
8 f2 @, o; C) E k6 }6 o
{m,n} 扩展前一个字符m至n次(含n) 【注4】 ab{1,2}c 表示 abc、abbc
2 r: B: a( M9 l; j' ]
^ 匹配字符串开头 ^abc 表示abc且在一个字符串的开头
: N' E" V8 b( |$ Y
$ 匹配字符串结尾 abc$ 表示abc且在一个字符串的结尾
& |' `% u6 w% t) o
( ) 分组标记,内部只能使用 | 操作符 (abc) 表示abc,(abc|def) 表示 abc、def
" [/ X, O% ~; E9 L( |2 E: H
\ 后边跟元字符去除特殊功能,跟普通字符实现特殊功能,如需消除反斜杠的特殊功能只需在前面再加一个反斜杠\\ \d \w \u
! x& Q: i" M8 x$ B9 t# J
\d 匹配十进制数字,等价于[0--9]
1 o7 @, n8 G; _8 T5 S- ^5 U
\D 与 \d 相反,匹配非十进制数字的字符,相当于 [^0-9]
2 m4 B' W N- z4 T
\s 匹配空白字符(包含空格、换行符、制表符等),等价于 [ \t\n\r\f\v]
0 {4 J, `& P: C2 r! @: }, F3 H
\S 与 \s 相反,匹配非空白字符,等价于 [^ \t\n\r\f\v]
' d B8 ^1 c& E6 A
\w 单词字符 【注5】 ,等价于[A--Z,a--z,0--9]
* Z2 g8 b# \) |, A3 q
\W 于 \w 相反
- l# i0 d) o) R X
\b 匹配单词的开始或结束
6 G% V7 [; _( x
\B 与 \b 相反
* m6 v+ A. B3 O9 k6 i+ _
\Z 只匹配字符串的结束位置。
; `* ~, K6 R) r9 J
【注1】:如果设置了 re.DOTALL 标志,. 将匹配包括换行符在内的任何字符。
, d/ w0 X9 H, F9 }3 ~- C
6 S/ z n. r% H V8 S) j
【注2】:由于受到 C 语言的 int 类型大小的内部限制,正则表达式引擎会限制字符重复个数不超过 20 亿个;
0 J( e1 E1 O2 |: @! J O$ V
. o% p" J! X' V. A8 B$ x
【注3】:为了能够更加合理的工作,| 的优先级非常低。例如 banana|orange 应该匹配banana 或 orange,而不是匹配 banan,然后一个 ‘a’ 或 ‘o’。同样,我们使用 \| 来匹配 |字符本身;或者包含在一个字符类中,像这样 [|]。
7 O% w6 F3 Q1 x! S# r; [/ c2 C1 F
* e. O: x4 u8 k" t5 ^. K. v
【注4】:可以省略 m 或者 n,引擎会假定一个合理的值代替。省略 m,将被解释为下限 0;省略 n 则会被解释为无穷大(事实上是上边我们提到的 20 亿)。
* z6 j0 d, U9 V \& p
4 {" O$ u: W+ c
【注5】:\w 匹配任何字符。如果正则表达式以字节的形式表示,这相当于字符类 [a-zA-Z0-9_];如果正则表达式是一个字符串,\w 会匹配所有 Unicode 数据库(unicodedata 模块提供)中标记为字母的字符。你可以在编译正则表达式的时候,通过提供 re.ASCII 表示进一步限制 \w 的定义。
8 {5 v/ B1 U; l# X5 z
. a! }* g% X$ X# {* q7 f% U
3. 部分元字符应用详解
% k( N3 U! u+ [) w- y/ v
7 N, u# a, _2 d! K" I; f3 ?
^
- y0 z" n5 T4 B" @+ w) o0 \
: x0 I5 Z5 K# a1 u) j) A8 B2 e
匹配字符串的起始位置。如果设置了 MULTILINE 标志,就会变成匹配每一行的起始位置。在 MULTILINE 中,每当遇到换行符就会立刻进行匹配。
! V3 P5 b% u& ]
. y. [8 h- @( q& J
举个例子,如果你只希望匹配位于字符串开头的单词 From,那么你的正则表达式可以写为 ^From:
$ N% e1 @0 O$ ^
: R! O+ k9 i$ B5 b' U9 u7 i
print(re.search('^From', 'From Here to Eternity'))
+ B' t! ^+ ]: i2 Q, e, u2 G) o; J
print(re.search('^From', 'Reciting From Memory'))
. c$ U$ o/ i8 |& N! j. v4 v8 l
1
[. u7 L; \ z$ e# Q" W
2
" i8 U6 m! A5 n% w- p( v# k3 Z0 P( D
结果如图:
2 g* w% V( p& S# N$ i: w8 [# K6 i5 C( s
2 W [: _4 Y. n+ I/ Q
8 X! v+ n/ `% l) ?8 c
$
# H# b3 w& P2 ], u1 {, t
6 U t- D* a3 a) k
匹配字符串的结束位置,每当遇到换行符也会离开进行匹配。
3 V2 F4 X; E9 S# d
4 N7 z) n& g* k2 J b
print(re.search('}$', '{block}'))
3 k5 `6 R5 ?* z3 _; V2 `' x5 w
' Z% G' c2 B# @3 t5 d
print(re.search('}$', '{block} '))
. \) M1 w1 \' ^* \$ {
* P0 v3 J+ x( ?1 p9 u+ s( K
print(re.search('}$', '{block}\n'))
/ _/ T; W2 e2 w& H8 K8 N" c
1
: c: W' K- F! N
2
' ^8 Z/ Y' R$ W- \- M# U- S
3
5 D+ ?( k, B' i
4
. B0 T b B' P7 e# Q
5
1 q2 r. b# r4 ~; e% W6 ?0 s7 @
结果如图:
+ k& j! r4 V" E
+ y7 s9 I$ V5 W
+ |( B$ c& ~* V
% Z! p9 m, D1 U8 o& T
同样,我们使用 $ 来匹配 $字符本身;或者包含在一个字符类中,像这样 [$]。
( ]1 a# ]6 c4 J- O3 c/ r
* c; ?0 A' S k1 W( L* e* y
\A
* o. H" x b. h" d6 ?: E' s
- v$ v, g$ d- o& l/ ]2 ~
只匹配字符串的起始位置。如果没有设置 MULTILINE 标志的时候,\A 和 ^ 的功能是一样的;但如果设置了 MULTILINE 标志,则会有一些不同:\A 还是匹配字符串的起始位置,但 ^ 会对字符串中的每一行都进行匹配。
8 R7 q2 z/ `) `1 Z9 c1 ~2 r8 ]
9 o i/ {( |; V0 H; C9 O$ d
\b
6 p: Z. T0 Y& ?* T: l& {
2 r, T; @7 ? Q0 c7 Q) S
单词边界,这是一个只匹配单词的开始和结尾的零宽断言。“单词”定义为一个字母数字的序列,所以单词的结束指的是空格或者非字母数字的字符。
/ r' l7 J x6 @4 b% p" O
2 [0 J( F x5 G3 v) [8 A
零宽断言相关信息请点击零宽断言查看。
: v. B' w& y( d1 F9 g+ ~
0 l: s* J. P% `: o
下边例子中,class 只有在出现一个完整的单词 class 时才匹配;如果出现在别的单词中,并不会匹配。
/ u- B" Y5 w3 g" V. r
5 g' m% n8 s5 ]% R" c
p = re.compile(r'\bclass\b')
. \" {1 v) O o) N- |4 r
print(p.search('no class at all'))
( M5 E; ?$ i0 f6 J# z* W
8 {, e; K, h% ^3 I, c
print(p.search('the declassified algorithm'))
5 A9 P a# b0 J6 w5 m$ k2 z4 |
0 F* H' l p2 I9 b1 {' t( ^+ T
print(p.search('one subclass is'))
$ ]4 j1 u2 J0 Z6 g
1
; G0 u- A5 Y4 \: R6 F
2
" `$ v5 b9 E; v- w2 y1 W i8 i8 S
3
; d7 I' t/ p4 i% b- z/ a1 K
4
5 \3 G2 i1 x. v5 N2 J& R
5
2 H- ?& q. i3 x Q% U
6
4 q/ `' D2 x! U
结果如图:
( G4 Q4 o. F: ?
; Z: d" {2 S B# U
在使用这些特殊的序列的时候,有两点是需要注意的:
* r! C# q7 _0 t+ a% z* V
8 g) I! b& l/ W) \" E# N
第一点是,Python 的字符串跟正则表达式在有些字符上是有冲突的。比如说在 Python 中,\b 表示的是退格符(ASCII 码值是 8)。所以,你如果不使用原始字符串,Python 会将 \b 转换成退格符处理,这样就肯定跟你的预期不一样了。
' I8 V/ K2 i4 ]: {7 {: w
相关原理和解决方法点击详情查看。
& q. |& ?! G: l' @+ y
1 Y7 P3 X) f" ^# s5 f' Q
第二点需要注意的是,在字符类中不能使用这个断言。跟 Python 一样,在字符类中,\b 只是用来表示退格符。
( B5 C: q8 p7 m q
" m# P/ j2 J: _6 w7 a- t) d4 b5 x
\B
0 z- |6 M3 s0 E, M
( r0 w- z8 ]( Q4 H# u
另一个零宽断言,与 \b 的含义相反,\B 表示非单词边界的位置。
5 ?- N, p/ J+ o
2 K# R; o. t3 b, Z. U' F
3. 正则表达式实例
+ L. n% y2 D! M) r
! c0 D# ~& a* o
0 x0 s8 L' j8 V- Z5 j/ J
经典正则表达式实例
2 Y \* q3 g u. ]: W
$ f: c0 ?* m) s6 x0 D- e
匹配IP地址的正则表达式
& c0 _* w* ~7 e) E* |
5 g$ P" D2 ?( ^$ w! K
IP地址字符串形式的正则表达式(IP地址分分4段,每段0-255) \d+.\d+.\d+.\d+ \d{1,3}.\d{1,3}.\d{1,3}.\d{1,3} 不精确
$ H. G4 `8 o/ g* a' m9 r
7 g; {2 a0 B! @) q
精确写法
4 a' X/ s9 C3 m2 ^0 B K. m
, l1 H3 B$ }3 l' l5 k
0--99: [1--9]?\d 100--199: 1\d{2} 200--249: 2[0--4]\d 250--255: 25[0--5]
0 \( l" r0 F) A- x+ G; \
(([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])
' u1 I6 `. F7 D* Q2 e1 M
原文链接:https://blog.csdn.net/qq_44867435/article/details/105104177
! F. t4 s; Z' x
3 ]7 ~. Z; V: T/ n
) `: z W; X4 z- A4 Y' V8 h8 f& L
欢迎光临 数学建模社区-数学中国 (http://www.madio.net/)
Powered by Discuz! X2.5