一.正则表达式语法和re模块
1.正则表达式的含义
正则表达式,又称规则表达式,通常被用来检索,替换那些符合某个模式(规则的文本)
通过正则表达式,从文本字符串中获取我们想要的特定部分(’ 过滤 ')
2.常见的元字符
元字符 | 含义 |
---|---|
^ | 匹配行首 |
$ | 匹配行尾 |
? | 重复匹配0次或一次 |
* | 重复匹配零次或者更多次 |
+ | 重复匹配一次或者更多次 |
{n} | 重复匹配n次 |
{n,} | 重复匹配n次或者更多次 |
{n,m} | 重复匹配n-m次 |
[a-z] | 任意a-z的一个字母 |
. | 匹配除\n之外的任意一个字符 |
\d | 匹配任意一个数字,相当于[0-9] |
\D | 匹配任意一个非数字,相当于[^0-9] |
\w | 匹配任意一个数字,字母,下划线 |
\W | 匹配任意一个非数字,字母,下划线 |
\s | 匹配任意一个空白,如:\t,\n,\r,空格等 |
\S | 匹配任意一个非空白 |
[] | 匹配括号中几个字符非任意一个 |
[abc] | 匹配abc中的任意一个字符 |
[a-z] | 匹配任意a-z的一个字符 |
[^123abc] | 匹配除了123abc这几个字符以外的任意字符 |
^[abc] | 匹配以a/b/c开头的任意一个字符 |
3.匹配的一些方法
方法 | 描述 |
---|---|
match | 从起始位置开始查找,一次匹配 |
search | 从任意位置开始查找,一次匹配 |
findall | 全部匹配,返回列表 |
finditer | 全部匹配,返回迭代器 |
split | 分割字符串,返回列表 |
sub | 替换 |
二.贪婪模式和非贪婪模式
含义
贪婪模式: 在整个表达式匹配成功的前提下,尽可能多的匹配 (.*)
非贪婪模式: 在整个表达式匹配成功的前提下,尽可能少的匹配 (.*?)
.
三.案例
1.正则匹配
#1.导入re模块
import re
#2.制定规则
# 使用compile()
# pattern=re.compile()
#定义字符窜
str='123hello789world'
#3.开始匹配
#3.1 match('待匹配字符串',[起始索引,结束索引])
#注:如果开头的字符不符合匹配规则,直接返回None
match_pattern=re.compile(r'\d+')
result=match_pattern.match(str)
# result=match_pattern.match(str,8,12)
print(result) #<re.Match object; span=(0, 3), match='123'>
print(result.group()) #123
#3.2 group() 分组
group_str='123hello123everybody'
# match_pattern=re.compile(r'\d+')
match_pattern=re.compile(r'(\d+)(\w+)(\d+)')
result=match_pattern.match(group_str)
print(result.group()) #123hello123
print(result.group(1)) #123
print(result.group(2)) #hello12
print(result.group(3)) #3
#分组的反向引用
# 注意:反向引用不代表分组,只是前面分组值的引用
html='<html><h1>helloworld</h1></html>'
pattern=re.compile(r'<(html)><(h1)>(.*)</h1></html>')
result=pattern.match(html)
print(result)
print(result.group()) #<html><h1>helloworld</h1></html>
print(result.group(1)) #html
print(result.group(2)) #h1
print(result.group(3)) #helloworld
print(result.group(4)) # 报错
# 3.3 span()方法 作用:查看匹配成功的子串的索引范围
# 支持分组查看
span_str = '1h2e3lloworld'
pattern = re.compile(r'(\d)h(\d)e(\d)')
result = pattern.match(span_str)
print(result.span()) # (0, 5)
print(result.span(2)) # (2, 3)
# 3.4 search('待匹配的字符串'[,起始索引,结束索引]) 全局匹配,只匹配成功一次
# 如果匹配成功,返回match对象
# 如果开头不符合匹配规则,继续向下匹配
# 直到整个字符串中都没有找到符合规则的时候,返回None
search_str = '1h2e3lloworld'
search_str = 'h2e3lloworld'
pattern = re.compile(r'\d')
result = pattern.search(search_str)
print(result) # <_sre.SRE_Match object; span=(0, 1), match='1'>
print(result.group())
# 3.5 findall()方法 全局匹配,和match、search放均不同
# 所有符合条件的子串,全部返回,返回的是一个列表,列表中的元素是匹配成功的内容
# 列表中元素不是match对象
# 如果没有符合条件的子串,返回的是一个空列表
findall_str = '1h2e3lloworld'
findall_str2 = 'helloworld'
pattern = re.compile('\d')
result = pattern.findall(findall_str)
result2 = pattern.findall(findall_str2)
print(result) # ['1', '2', '3']
print(result2) # []
# 3.6 finditer() 全局匹配 和findall()相似
# 如果匹配成功,返回的是可迭代的对象,可迭代对象中,包含所有匹配成功的match对象
finditer_str = '1h2e3lloworld'
pattern = re.compile('\d')
result = pattern.finditer(finditer_str)
# print(result) # <callable_iterator object at 0x000000000288E710>
for i in result:
print(i) # match对象
print(i.group())
# 3.7 split() 切割方法,返回列表
# split('待切割的字符串'[,maxsplit])
split_str = 'a,b,c;d e'
pattern = re.compile(r'[,; ]')
result = pattern.split(split_str)
print(result) # ['a', 'b', 'c', 'd', 'e']
# 可以使用maxsplit指定最大的切割次数
result = pattern.split(split_str,maxsplit=2)
print(result) # ['a', 'b', 'c;d e']
# 3.8 sub('新的字符串','旧的字符串') 替换方法
# 第一种:直接替换
sub_str = 'hello 123,hello 456'
pattern = re.compile(r'(\w+) (\d+)')
result = pattern.sub('hi world',sub_str)
print(result) # hi world,hi world
# 第二种:使用函数
# sub('函数名','旧的字符串')
# 对函数的要求:
# 1. 函数必须要有形式参数,参数作用:代表匹配到的子串
# 2. 函数必须要有返回值,返回值必须是字符串类型,返回值作用:代表新的字符串
sub_str = 'hello 123,hello 456'
pattern = re.compile(r'(\w+) (\d+)')
def func(m):
print(m)
return 'hi ' + m.group(2)
result = pattern.sub(func,sub_str)
print(result) # hi 123,hi 456
# 3.9 贪婪模式和非贪婪模式
html = '<div>hello</div><div>world</div><div>python</div><div>java</div>'
# 贪婪模式:尽可能多的获取 .*
pattern = re.compile(r'<div>(.*)</div>')
result = pattern.findall(html)
print(result) # ['hello</div><div>world</div><div>python</div><div>java']
# 非贪婪模式:尽可能少的获取 .*?
pattern = re.compile(r'<div>(.*?)</div>')
result = pattern.findall(html)
print(result) # ['hello', 'world', 'python', 'java']
# 爬虫的万能表达式:
# .*?(非贪婪模式) 需要配合边界值使用
# re.compile(r'<边界>(.*?)</边界>',re.S) 无敌表达式
# re.S:代表能够匹配到换行
# re.I:代表忽略大小写
# 3.10 匹配中文
# 中文编码:[\u4e00-\u9fa5]
cn_str = 'hello 你好 world 世界'
pattern = re.compile(r'[\u4e00-\u9fa5]+')
res = pattern.findall(cn_str)
print(res) # ['你好', '世界']
2.猫眼电影数据获取
需求:
获取猫眼电影TOP100榜下,所有电影的排名、电影名、主演、上映时间以及评分
#导入模块
import requests,re
from openpyxl import Workbook
# 实例化
wb=Workbook()
ws=wb.active
#增加表头
ws.append(['排名','电影名','主演','上映时间','评分'])
#前十页
# https://maoyan.com/board/4?offset=0
# https://maoyan.com/board/4?offset=10
# https://maoyan.com/board/4?offset=20
# https://maoyan.com/board/4?offset=90
#请求头
headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.193 Safari/537.36',
'Cookie': '__mta=150426505.1606116724430.1606117565266.1606117568203.9; uuid_n_v=v1; uuid=08EB82C02D5E11EB99C45D5F1D6B3FD73CC5BE51B95B4B94AAA710EBF00F3C1A; _csrf=8fb4ebdaf3ccae31ee526bd29ca8ebe3d23f2aca4ee441202909f5bb492dc01d; Hm_lvt_703e94591e87be68cc8da0da7cbd0be2=1606116724; _lx_utm=utm_source%3Dgoogle%26utm_medium%3Dorganic; _lxsdk_cuid=175f4044e32c8-04430bacb412b9-45410f29-100200-175f4044e32c8; _lxsdk=08EB82C02D5E11EB99C45D5F1D6B3FD73CC5BE51B95B4B94AAA710EBF00F3C1A; __mta=150426505.1606116724430.1606116724430.1606116794282.2; Hm_lpvt_703e94591e87be68cc8da0da7cbd0be2=1606117568; _lxsdk_s=175f4044e33-553-b50-970%7C%7C22'
}
#请求参数
params={}
#制定dd规则
dd_pattern=re.compile(r'<dd>(.*?)</dd>',re.S)
#制定获取排名规则
num_pattern=re.compile(r'<i class="board-index board-index-\d+">(.*?)</i>')
#制定获取电影名规则
name_pattern=re.compile(r'<p class="name"><a .*?>(.*?)</a></p>',re.S)
#制定获取主演规则
star_pattern=re.compile(r'<p class="star">(.*?)</p>',re.S)
#制定上映时间规则
time_pattern=re.compile(r'<p class="releasetime">(.*?)</p>',re.S)
#制定评分规则
score_pattern=re.compile(r'<p class="score"><i class="integer">(.*?)</i><i class="fraction">(.*?)</i></p>',re.S)
for offset in range(0,10):
params['offset']=offset*10
#获取数据
response=requests.get(url='https://maoyan.com/board/4?requestCode=aef9e9979cb175bc7a3411c975b7304es6gxn',headers=headers,params=params)
result=response.text
# print(result)
# 获取全部
dd_list=dd_pattern.findall(result)
# print(dd_list)
for i in range(0,10):
lst=[]
#获取排名
num_list=num_pattern.findall(result)[i]
#获取电影名
name_list=name_pattern.findall(result)[i]
#获取主演名
star_list=star_pattern.findall(result)[i].strip()
#获取上映时间
time_list=time_pattern.findall(result)[i]
#获取评分数据
score_list=score_pattern.findall(result)[i]
score_list=score_list[0]+score_list[1]
# lst.append(num_list)
# lst.append(name_list)
# lst.append(star_list)
# lst.append(time_list)
# lst.append(score_list)
# ws.append(lst)
print(num_list,name_list,star_list,time_list,score_list)
# wb.save('猫眼电影TOP100.xlsx')
3.股吧数据获取
#导入模块
import requests,re
from openpyxl import Workbook
# 股吧网址:https://guba.eastmoney.com/
wb=Workbook()
ws=wb.active
ws.append(['阅读量','评论','标题','作者','更新时间'])
#请求头
headers={
'Cookie': '_adsame_fullscreen_18009=1; st_si=53143075311765; qgqp_b_id=d5a77337368c32115885450aef22d4cd; st_pvi=69749492952227; st_sp=2020-11-23%2023%3A36%3A15; st_inirUrl=https%3A%2F%2Fguba.eastmoney.com%2F; st_sn=36; st_psi=20201123234954591-0-5745969454; st_asi=20201123234954212-117001301773-9755240893-gb_xgbsy_lbqy_qydj-1',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.193 Safari/537.36',
'X-Requested-With': 'XMLHttpRequest'
}
#请求参数
params={}
#制定规则
gb_pattern=re.compile(r'<ul class="newlist" tracker-eventcode="gb_xgbsy_ lbqy_rmlbdj">(.*?)</ul>',re.S)
#规则2
gb_list1_pattern=re.compile(r'<li.*?>(.*?)</li>',re.S)
# gb_list2_pattern=re.compile(r'<li class="even">(.*?)</li>',re.S)
#制定阅读,评论,标题,作者,更新时间的规则
cite_pattern=re.compile(r'<cite>(.*?)</cite>',re.S)
#制定标题的规则
title_pattern=re.compile(r'<a .*? title="(.*?)" class="note">.*?</a>',re.S)
#制定作者的规则
author_pattern=re.compile(r'<font>(.*?)</font>',re.S)
#指定更新时间的规则
time_pattern=re.compile(r'<cite class="last">(.*?)</cite>',re.S)
#制定总页码规则
page_pattern=re.compile(r'<span class="sumpage">(.*?)</span>')
response=requests.get(url='https://guba.eastmoney.com/default,99_2.html',params=params,headers=headers)
result=response.text
#获取总页码
total_page=page_pattern.findall(result)[0]
print(total_page)
for page in range(1,int(total_page)+1):
response=requests.get(url=f'https://guba.eastmoney.com/default,99_{page}.html',params=params,headers=headers)
result=response.text
# print(result)
#获取列表
gb_list=gb_pattern.findall(result)[0]
# print(gb_list)
#获取li的内容
gb_list1=gb_list1_pattern.findall(gb_list)
# print(gb_list1)
for gb in gb_list1:
#获取阅读,评论的数据
lst=[]
cite_list=cite_pattern.findall(gb)
read_list=cite_list[0].strip()
comment_list=cite_list[1].strip()
#获取标题内容
title_list=title_pattern.findall(gb)[0]
#获取作者数据
author_list=author_pattern.findall(gb)[0]
#获取更新时间的数据
time_list=time_pattern.findall(gb)[0]
#保存数据
lst.append(read_list)
lst.append(comment_list)
lst.append(title_list)
lst.append(author_list)
lst.append(time_list)
print(read_list,comment_list,title_list,author_list,time_list)
ws.append(lst)
wb.save('股吧数据.xlsx')