Python爬虫(二)正则表达式

目录

正则表达式语法规则

字符

预定义字符集

数量词

贪婪和非贪婪

边界匹配(不消耗匹配字符串中的字符)

逻辑、分组

Python re模块介绍

引入模块

正则检索

正则分割字符串

字符串替换

分组引用

匹配中文


正则表达式语法规则

百度百科简介:正则表达式是对字符串(包括普通字符(例如,a 到 z 之间的字母)和特殊字符(称为“元字符”))操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。正则表达式是一种文本模式,该模式描述在搜索文本时要匹配的一个或多个字符串。

字符

字符
.匹配一个任意字符,换行符除外
\ 转义字符,把带有特殊含义的字符转换成无意义字符
[...] 字符集,匹配其中的任意一位。a[012]b,可以匹配a0b,a1b,a2b;可以指定范围,a[0-9]b;a[0-9a-zA-Z]
^取反,需要放在[]里面的最前面,a[^0-9]b 表示匹配一个非数字的任意字符
 如果要匹配数字或者^字符,a[0-9^]b或者写成a[\^0-9]b

 

预定义字符集

\d匹配数字,等同于[0-9]
\D匹配非数字,等同于[^0-9]
\s匹配空白字符,等同于[\n\t\r\f\v] ,换行、空格、\f换页符,\v 垂直制表符
\S匹配非空白字符
\w匹配单词字符(数字、字母、下划线),等同于[0-9a-zA-Z_]
\W匹配非单词字符

 

数量词

*匹配前一个字符0或者无限次
+匹配前一个字符1或者无限次
? 匹配前一个字符0次或者1次,一般和括号()组合使用
{M}匹配前一个字符M次,{N,M}匹配N-M次,{M,} 最少M次,无上限

 

贪婪和非贪婪

贪婪:再整个表达式匹配成功的前提下,尽可能多的匹配

非贪婪:在整个表达式匹配成功的前提下,尽可能少的匹配

贪婪.*或者\s* 贪婪匹配,会一直匹配到最后不能匹配的位置
非贪婪.*? 非贪婪匹配,会匹配每一次出现的结果

例:<p>123</p><p>abcde</p> ,使用贪婪和非贪婪模式匹配这个字符串。

<p>.*</p> 贪婪匹配,*号会匹配到尽可能多的东西,匹配整个123</p><p>abcde,最后匹配结果只有一个结果集,就是整个字符串。
<p>.*?</p> 非贪婪匹配,会匹配每一次出现的结果。匹配的结果有两个:<p>123</p>和<p>abcde</p>。

 

边界匹配(不消耗匹配字符串中的字符)

^匹配字符串的开头
$匹配字符串的结尾,空格回车也会参与匹配
\A字符串的开头(Python中独有的写法)
\Z字符串的结尾(Python中独有的写法)
\b匹配单词和非单词的边界,单词和非单词的交界。(单词字符包括数字、字母、下划线、汉字)
    tom,do you have time tomorrow
    匹配tom人名,tom\b
    tomorrow tom后面o是单词,不满足\b的要求
\B匹配要么都是单词,要么都是非单词

 

逻辑、分组

|左右表达式任意匹配一个。尝试先匹配左边再匹配右边。经常和括号配合使用,hello (aaa|bbb)
( )括号代表分组,或者一个整体。
\num

引用第num个分组

    分组示例: Anni like Anni

                      John like Jerry
    正则表达式:(.+?) like \1     

                          \1代表引用第一个分组的值,做搜索。

                          意思是把like前面的字符串用到后面\1的地方,a like b,其中b的值是和a一样的,

                          结果是检索出 Anni like Anni

 

正则练习

在线练习正则表达式的网址: http://tool.oschina.net/regex/

1、用正则匹配如下网址
http://www.baidu.com
https://www.sina.com.cn
https://www.baidu.com/s?wd=python&name=anni
ftp://www.antvv.com
https://www.antvv.com?cate=3

(http|https|ftp)://www\.\w+\.(com\.cn|com|cn|net|gov)(/\w+)*(\?\w+=\w+)?


2、电话号码匹配(11位)
+86 13456789012
18999245678
12341134
 

(\B(\+86 )?|\b)1[3-9]\d{9}


3、身份证 (18位,最后一位可能是X)
368756483729876657
36875648372987665X
3687564837298766571
3687564837298766573X

\b\d{17}(\d|X)\b

4、匹配年份1990-2019
1990
2019
1989
2020
2010
20101
22010

\b(199|20(0|1))\d\b

Python re模块介绍

引入模块

import re

reg=re.compile('正则')    编译正则表达式,之后就可以通过该对象匹配

正则检索

result=reg.match()    从文本中匹配正则表达式,从字符串第一个位置开始匹配,只匹配一次,匹配到了就返回match对象,否则返回None。
result.group()    从匹配到的对象中取出分组,如果有分组则传入分组编号取出相应组的返回值,如果没有分组不需要传或者传0。

#-*- coding: UTF-8 -*-
import re

# 取出手机号前三位和后四位
phone="13123456789"
phone_reg=re.compile("(1[3-9]\d)(\d{4})(\d{4})")
result=phone_reg.match(phone)
print(result.group(1))
print(result.group(3))

# 打印结果
# 131
# 6789 

正则表达式:(1[3-9]\d)(\d{4})(\d{4}),把手机号分成了三组,每个()是一个分组,如果取第一分组就用group(1)。

如果不取分组的信息,取整个正则匹配的数据,则group不需要传参数,或者group(0)。

#-*- coding: UTF-8 -*-
import re
phone="13123456789"
phone_reg=re.compile("(1[3-9]\d)(\d{4})(\d{4})")
result=phone_reg.match(phone)
print(result.group())
print(result.group(0))

# 打印结果:
# 13123456789
# 13123456789


reg.search()    从字符串的任意位置开始搜索,match的升级版,只匹配一次。

如果上个例子中,把手机号改掉,让 phone="我的手机号是13123456789",用match函数是无法检索出来的。

#-*- coding: UTF-8 -*-
import re
phone="我的手机号是13123456789"
phone_reg=re.compile("(1[3-9]\d)(\d{4})(\d{4})")
result=phone_reg.match(phone)
print(result)

# 打印结果
# None

改成用search就可以了

#-*- coding: UTF-8 -*-
import re
phone="我的手机号是13123456789"
phone_reg=re.compile("(1[3-9]\d)(\d{4})(\d{4})")
result=phone_reg.search(phone)
print(result.group())

# 打印结果
# 13123456789

reg.findall()    任意位置搜索,匹配多次。匹配所有满足条件的字符。
                      返回的是列表,如果正则里面有分组,返回元组形式包装的分组返回信息;
                      如果没有分组,列表里面直接是返回值。
                      在分组开始的括号后面加上?:代表该括号不作为一个分组

str='''
    我的名字是王小明,我的手机号是13114567890,我的身份证号是330721197010040515。
    我的名字是孙其绥,我的手机号是13114567890,我的身份证号是330702197108020812。
    我的名字是孙群领,我的手机号是13114567890,我的身份证号是33072419770516031X。
'''

如何检索出上面str的所有手机号码呢?

#-*- coding: UTF-8 -*-
import re
str='''
    我的名字是王小明,我的手机号是13114567890,我的身份证号是330721197010040515。
    我的名字是孙其绥,我的手机号是13114567890,我的身份证号是330702197108020812。
    我的名字是孙群领,我的手机号是13114567890,我的身份证号是33072419770516031X。
'''
phone_reg = re.compile("手机号是(1[3-9]\d{9}),我的")
result = phone_reg.findall(str)
print(result)

# 打印结果
# ['13114567890', '13114567890', '13114567890']

现在可以检索出手机号码了,那么思考下,怎么检索出每个号码的前3位和后四位呢?结合上面的例子思考3秒钟。

#-*- coding: UTF-8 -*-
import re
str='''
    我的名字是王小明,我的手机号是13114567890,我的身份证号是330721197010040515。
    我的名字是孙其绥,我的手机号是13114567890,我的身份证号是330702197108020812。
    我的名字是孙群领,我的手机号是13114567890,我的身份证号是33072419770516031X。
'''
# 使用分组,如果不想让中间四位检索出来,就加?:使第二个不作为一个分组
phone_reg = re.compile("手机号是(1[3-9]\d)(?:\d{4})(\d{4}),我的")
result = phone_reg.findall(str)
print(result)

# 打印结果
# [('131', '7890'), ('131', '7890'), ('131', '7890')]

reg.finditer()    匹配所有满足条件的,返回一个可迭代对象
    遍历返回的是match对象,用group获取值

#-*- coding: UTF-8 -*-
import re
str='''
    我的名字是王小明,我的手机号是13114567890,我的身份证号是330721197010040515。
    我的名字是孙其绥,我的手机号是13114567890,我的身份证号是330702197108020812。
    我的名字是孙群领,我的手机号是13114567890,我的身份证号是33072419770516031X。
'''
phone_reg = re.compile("手机号是(1[3-9]\d)(?:\d{4})(\d{4}),我的")
result = phone_reg.finditer(str)
for once in result:
    print(once.group(1)+"***"+once.group(2))

# 打印结果
# 131***7890
# 131***7890
# 131***7890

 

正则分割字符串

split()    通过正则表达式分割字符串,结果返回一个list。

#-*- coding: UTF-8 -*-
import re
str2="唱_跳,rap_篮球"
# 同时用多种字符进行分割
regex_sp = re.compile(",|_")
result = regex_sp.split(str2)
print(result)

# 返回结果
# ['唱', '跳', 'rap', '篮球']

字符串替换

sub("替换字符",目标str,替换次数)    字符串替换,替换次数不设置的话,默认替换所有。
bad_str_reg = re.compile("[><\?\"/\|\\\\:\*]")
bad_str_reg.sub("目标字符",str)
subn()    字符串替换后返回替换次数和替换过的字符串

用re去调用的话:
re.sub(正则表达式,"替换字符",目标str,替换次数)

#-*- coding: UTF-8 -*-
import re
filename = "/清\华|大<学:校*花>校?花\"名.jpg"
result = re.sub("[><\?\"/\|\\\\:\*]","",filename)
print(result)
result2 = re.sub("[><\?\"/\|\\\\:\*]","",filename,5)
print(result2)
result3 = re.subn("[><\?\"/\|\\\\:\*]","",filename)
print(result3)

# 打印结果
# 清华大学校花校花名.jpg
# 清华大学校*花>校?花"名.jpg
# ('清华大学校花校花名.jpg', 9)

分组引用

\num 引用分组

#-*- coding: UTF-8 -*-
import re
phone_num="13114567890"
phone_reg=re.compile("(1[3-9]\d)(\d{4})(\d{4})")
result=phone_reg.sub("\\1****\\3",phone_num)
#            第一分组+****+第三分组
print(result)

# 打印结果
# 131****7890

匹配中文

如何获取一段字符串中的所有中文内容。
[\u4e00-\u9fa5]

或者

[一-龥]

(从第一个中文“一”匹配到最后一个中文“龥”(yù))

#-*- coding: UTF-8 -*-
import re
str3="我的名字是王小明,我的手机号是13114567890,我的身份证号是330721197010040515。"
print(re.findall("[\u4e00-\u9fa5]+",str3))
print(re.findall("[一-龥]+",str3))

# 打印结果
# ['我的名字是王小明', '我的手机号是', '我的身份证号是']
# ['我的名字是王小明', '我的手机号是', '我的身份证号是']

 


 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值