美文网首页python
[Pt_09] Python数据清洗之正则表达式应用

[Pt_09] Python数据清洗之正则表达式应用

作者: Fighting_001 | 来源:发表于2019-04-04 00:44 被阅读19次

目录结构

一、Python正则表达式
    1. 匹配普通字符
    2. 匹配通用字符
    3. 匹配数字、中文、英文(通用字符)
    4. 原子表
    5. 常用元字符
    6. 匹配字符出现的次数
    7. 匹配多个正则表达式
    8. 分组
    9. 贪婪模式 & 非贪婪模式
    10. compile函数
    11. match函数、search函数
    12. findall()函数、finditer()函数
    13. split()函数、sub()函数
二、Python爬虫实践
    1. 爬取网站电话号码
    2. 爬取电影排名列表

<关联1> JavaScript正则表达式
<关联2> Shell编程-正则 & 文本字符处理命令

一、Python正则表达式

原子:正则表达式中实现匹配的基本单位(被匹配的对象)
元字符:正则表达式中具有特殊含义的字符

1. 匹配普通字符

以普通字符作为原子(匹配一个普通字符)

search函数:搜寻字符串中是否包含所匹配的字符

# 从st字符串中搜寻符合pat正则匹配规则的字符
re.search(pat,st)

normalMatch.py

import re

st="春天夏天秋天冬天"
pat="夏天"
result=re.search(pat,st)

print(result)

2. 匹配通用字符

常见通用字符:

字符 等价类 含义
\d [0-9] 数字字符
\D [^0-9] 非数字字符
\s [\t\n\x0B\f\r] 空白符
\S [^\t\n\x0B\f\r] 非空白符
\w [a-zA-Z_0-9] 任意单词字符
(字母、数字、下划线)
\W [^a-zA-Z_0-9] 非单词字符

结合英文原意记忆:
d ==> digit(数字)
s ==> space(空白)
w ==> word(单词)

generalMatch.py

import re

st="13800138000@@***.@163.com"
pat1=r"\d\d\d"  # r表示取消转义
pat2=r"\d\d\D"
pat3=r"\w\w\w"
pat4=r"\w\W\W"

i=1
for pat in pat1,pat2,pat3,pat4:
    result=re.search(pat,st)
    print("result"+str(i)+":",result)
    i=i+1

3. 匹配数字、中文、英文(通用字符)

数字:[0-9]
英文:[a-zA-Z]
中文:[\u4e00-\u9fa5]

generalMatch2.py

import re

st="asd2019f0@Python@***正则.@.com"
pat1=r"[0-9]{4}"
pat2=r"P[a-zA-Z]{5}"
pat3=r"[\u4e00-\u9fa5]{2}"

i=1
for pat in pat1,pat2,pat3:
    result=re.search(pat,st)
    print("result"+str(i)+":",result)
    i=i+1

4. 原子表

定义一组平等的原子,只要有一个满足条件,则表示匹配成功

phone.py

import re

st="13800138000"
pat=r"^1[35789]\d{9}$"

result=re.search(pat,st)
print(result)

5. 常用元字符

正则中具有特殊含义的字符

符号 含义
. 匹配任意字符(换行符"\n"除外)
^ 匹配字符串的开始位置
$ 匹配字符串的结束位置
* 重复任意次(≥0次)前面的原子
? 含义①:重复0或1次前面的原子
含义②:非贪婪匹配。应用:aaa(.*?)bbb
+ 重复1次及以上(≥1次)前面的原子

6. 匹配字符出现的次数

匹配一个出现n次的字符串,n=0,1,...,N

字符 含义
? 0或1 次
+ ≥1 次
* ≥0 次(任意次)
{n} n 次
{n,m} n到m 次
{n,} ≥n 次

7. 匹配多个正则表达式

多个正则之间用符号 | 连接,任意一个匹配成功则表示匹配ok

multiMatch.py

import re

st1="asd2019f0"
st2="@Python@*"
st3="**正则.@.com"
pat=r"\d{4}|P[a-zA-Z]{5}|[\u4e00-\u9fa5]{2}"

ls=[]
for st in st1,st2,st3:
    result=re.search(pat,st)
    print(result)

8. 分组

分组:使用符号()
输出分组内容:group(num)、groups();num表示第几个分组对应的数字

group.py

import re

st="asd2019f0@Python@***正则.@.com"
pat=r"(\d{4}).*(P[a-zA-Z]{5}).*([\u4e00-\u9fa5]{2})"

result=re.search(pat,st)
result1=result.group(1)
result2=result.group(1,2,3)
result3=result.groups()

for result in result1,result2,result3:
    print(result)

9. 贪婪模式 & 非贪婪模式

贪婪模式:尽可能多的匹配。Python默认贪婪模式
非贪婪模式:尽可能少的匹配(?

greedyModel.py

import re

st="<div>AAA</div>正则<div>BBB</div>"
pat1=r"<div>.*</div>"   # 贪婪模式
pat2=r"<div>(.*?)</div>"    # 非贪婪模式

for pat in pat1,pat2:
    result=re.search(pat,st)
    print(result)

10. compile函数

将正则表达式转换成内部格式,以提高正则执行效率,适用于匹配大量次数的场景

compile1.py

import re

st="111Python@@@123"

# 方式1:
# pat=r"\d+"
# result=re.search(pat,st)

# 方式2:
pat=re.compile(r"\d+")
result=pat.search(st)

print(result)

compile2.py

import re

st="111PyThon@@@123"

pat1=re.compile(r"python")  # 默认大小写严格区分
pat2=re.compile(r"python",re.I) # 模式修正符:忽略大小写
result1=pat1.search(st)
result2=pat2.search(st)

print(result1)
print(result2)

11. match函数、search函数

match函数:匹配开头位置
search函数:匹配任意位置
PS:以上2个函数都是一次匹配,匹配到一次后就不再往后继续匹配

match-search.py

import re

st1="111python@@@123"
st2="python@@@123"

pat=re.compile(r"python")

result1=pat.match(st1)
result2=pat.match(st2)

result3=pat.search(st1)
result4=pat.search(st2)

result5=pat.match(st2).group()
result6=pat.search(st2).group()

for result in result1,result2,result3,result4,result5,result6:
    print(result)

12. findall()函数、finditer()函数

findall()函数:查找所有匹配的内容,存放到列表中
finditer()函数:查找所有匹配的内容,存放到迭代器中

findall-finditer.py

import re

st="hi-------hi-----\
-------hi------\
hi-----hi2019hi----"

pat=re.compile(r"hi")

result1=pat.findall(st)
print(result1,"\n")

result2=pat.finditer(st)
print(result2,"\n")

ls=[]
for i in result2:
    ls.append(i.group())
print(ls)

13. split()函数、sub()函数

split()函数:将匹配的子串作为分隔符,对字符串进行分割,并返回列表
sub()函数:将匹配的子串替换为指定子串

split-sub.py

import re

st="AAA。。。BBB。。。。。。CCC...111---EEE"

pat1=re.compile(r"[。\.-]+")
result1=pat1.split(st)
print(result1,"\n")

pat2=re.compile(r"\d+")
result2=pat2.sub("DDD",st)
print(result2,"\n")

result3=pat1.split(result2)
print(result3)

二、Python爬虫实践

1. 爬取网站电话号码

目标:在某公开电话网站,利用爬虫获取常用电话的名称、电话号码信息

分析:

通过简单方式获取响应数据,分析其中的html响应数据结构,构造匹配所需内容的正则表达式

getPhoneNumber.py

import requests
import re

header={
    "user-agent":"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36"
}

url="https://changyongdianhuahaoma.51240.com/"

resp=requests.get(url,headers=header).text
print(resp)

构造正则匹配规则:
名称:
<tr bgcolor="#EFF7F0">[\s\S]*?<td>(.*?)</td>[\s\S]*?<td>[\s\S]*?</td>[\s\S]*?</tr>
电话:
<tr bgcolor="#EFF7F0">[\s\S]*?<td>[\s\S]*?</td>[\s\S]*?<td>(.*?)</td>[\s\S]*?</tr>

代码实现:
import requests
import re

header={
"user-agent":"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36"
}

# 发送GET请求,获取响应数据
# 若获取不到响应数据,根据需要关闭SSL验证
url="https://changyongdianhuahaoma.51240.com/"
resp=requests.get(url,headers=header,verify=False).text

# 正则规则
pat1=r'<tr bgcolor="#EFF7F0">[\s\S]*?<td>(.*?)</td>[\s\S]*?<td>[\s\S]*?</td>[\s\S]*?</tr>'  # 匹配电话名称
pat2=r'<tr bgcolor="#EFF7F0">[\s\S]*?<td>[\s\S]*?</td>[\s\S]*?<td>(.*?)</td>[\s\S]*?</tr>'  # 匹配电话号码

# 转换正则为内部格式
pattern1=re.compile(pat1)
pattern2=re.compile(pat2)

# 从响应数据中匹配数据(匹配结果为列表类型)
data1=pattern1.findall(resp)
data2=pattern2.findall(resp)

# 创建列表,存储"电话名称:电话号码"
result=[]

# 遍历每个电话
for i in range(0,len(data1)):
    result.append(data1[i]+": "+data2[i])   # 构造每一个电话号码

    # 打开指定文本文件,以追加方式写入数据
    f=open(r"D:\CI_Env\Python_Test\file\003.txt","a")
    f.write(result[i]+"\n")
    f.close()

执行结果:

2. 爬取电影排名列表

目标:访问某电影网站某类型电影排行榜,爬取对应电影名称、评分、排名数据

分析:

定位到排行榜页码,向下滑动页面的过程中,排行榜的电影每次以20个片名累积加载,采用JS异步请求(AJAX请求)方式加载数据,对应的数据请求url如下:

https://movie.douban.com/j/chart/top_list?type=11&interval_id=100%3A90&action=&start=0&limit=20
https://movie.douban.com/j/chart/top_list?type=11&interval_id=100%3A90&action=&start=20&limit=20
https://movie.douban.com/j/chart/top_list?type=11&interval_id=100%3A90&action=&start=40&limit=20
代码实现:

movieRank.py

import urllib.request
import re

header={
    "user-agent":"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36"
}

# 排名前20的请求链接
url="https://movie.douban.com/j/chart/top_list?type=11&interval_id=100%3A90&action=&start=0&limit=20"

# 创建请求对象
req=urllib.request.Request(url,headers=header)
# 发送请求,获取响应
data=urllib.request.urlopen(req).read().decode()

# 定义正则:匹配电影名称/评分/排名
pat1=r'"title":"(.*?)"'
pat2=r'"rating":\["(.*?)","\d+"\]'
pat3=r'"rank":(\d+)'

# 转换正则为内部格式
pattern1=re.compile(pat1)
pattern2=re.compile(pat2)
pattern3=re.compile(pat3)

# 从响应数据中匹配数据(匹配结果为列表类型)
data1=pattern1.findall(data)
data2=pattern2.findall(data)
data3=pattern3.findall(data)

for i in range(len(data1)):
    print("排名:",data3[i]+"\t\t"+"电影名:"+data1[i]+"\t\t"+"评分:"+data2[i])

执行结果:

相关文章

网友评论

    本文标题:[Pt_09] Python数据清洗之正则表达式应用

    本文链接:https://www.haomeiwen.com/subject/pbnebqtx.html