-
什么是正则表达式
正则表达式是对字符串操作的一种逻辑公式,就是用实现定义好的一些特定的字符、及这些特定的字符的组合,组成一个“规则字符串“,这个“规则字符串“用来表达对字符串的一种过滤逻辑。
注意: 正则表达式并不是Python独有的,Python中使用re模块实现。元字符 描述 \w 匹配字母数字及下划线 \W 匹配非字母数字下划线 \s 匹配任意的空白符 \S 匹配任意非空白符 \d 匹配数字 \D 匹配任意非数字的字符 . 匹配除换行符以外的任意字符 ^ 匹配字符串的开始 $ 匹配字符串的结束 * 重复零次或更多次 + 重复一次或更多次 ? 重复零次或一次 {n} 重复n次 {n,} 重复n次或更多次 {n,m} 重复n到m次 a b () 匹配括号内的表达式,也表示一个组
3. re.match()
尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配的话,match()就会返回None
语法: re.match(正则表达式,要匹配的字符串,匹配方式)
常用匹配方式: re.I 使匹配对大小写不敏感 re.S 使 . 匹配包括换行在内的所有字符
import re
str='www.kaikeba'
result=re.match('www',str)
#获取匹配的结果
print(result.group())
#获取匹配字符串的长度范围
print(result.span())
#re.match() 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配的话,match()就会返回None
#不在起始位置匹配,返回None
print(re.match('kaikeba',str))
#默认大小写是敏感的
print(re.match('WWW',str))
#设置匹配模式,忽略大小写
print(re.match('WWW',str,re.I))
#多种匹配方式
str2='abc 123 def'
#常规匹配
print(re.match('^abc\s\d\d\d\sdef$',str2).group())
print(re.match('^abc\s\d+\sdef$',str2).group())
print(re.match('^abc\s\d{3}\sdef$',str2).group())
#范式匹配
print(re.match('^abc\s.*\sdef$',str2).group())
print(re.match('^.*$',str2).group())
#获取指定的字符
print(re.match('^abc\s(.*)\s(def)$',str2).group(1)) #正则表达式中出现括号就表示你取你想取得内容
# 通过re.group()获得结果后,如果正则表达式中有括号,则re.group(1)获取的就是第一个括号中匹配的结果
abc 123 def
abc 123 def
abc 123 def
abc 123 def
abc 123 def
('123', 'def')
#贪婪匹配和非贪婪匹配
#贪婪匹配
str3='hello 1234567 world Demo'
result=re.match('^hello.*(\d+).*Demo',str3)#首先满足前面的.*
print(result)
print(result.group(1))
# 这种情况的原因是前面的.*给匹配掉了,前面的.*在这里会尽可能的匹配多的内容,也就是我们所说的贪婪匹配
result=re.match('^hello.*?(\d+).*Demo',str3)#首先满足括号中的(\d+)
print(result)
print(result.group(1))
<re.Match object; span=(0, 24), match='hello 1234567 world Demo'>
7
<re.Match object; span=(0, 24), match='hello 1234567 world Demo'>
1234567
#匹配模式 re.S re.I (严格大写S、I)
# 很多时候匹配的内容是存在换行的问题的,这个时候的就需要用到匹配模式re.S来匹配换行的内容
content = """hello 123456 world
demo
"""
result =re.match('^he.*?(\d+).*?demo$',content,re.S)
print(result)
print(result.group())
print(result.group(1))
<re.Match object; span=(0, 23), match='hello 123456 world\ndemo'>
hello 123456 world
demo
123456
#转义字符\ (严格'\',不是'/')
# 当我们要匹配的内容中存在特殊字符的时候,就需要用到转义符号\
content= "price is $5.00"
result = re.match('price is \$5\.00',content)
print(result)
print(result.group())
<re.Match object; span=(0, 14), match='price is $5.00'>
price is $5.00
- re.search()
re.search扫描整个字符串返回第一个成功匹配的结果
#re.search()
#re.search扫描整个字符串返回第一个成功匹配的结果,只返回一个结果。
# 所以为了匹配方便,我们会更多的用search,不用match,match必须匹配头部,所以很多时候不是特别方便
import re
html = '''<div id="songs-list">
<h2 class="title">经典老歌</h2>
<p class="introduction">
经典老歌列表
</p>
<ul id="list" class="list-group">
<li data-view="2">一路上有你</li>
<li data-view="7">
<a href="/2.mp3" singer="任贤齐">沧海一声笑</a>
</li>
<li data-view="4" class="active">
<a href="/3.mp3" singer="齐秦">往事随风</a>
</li>
<li data-view="4" class="active">
<a href="/3.mp3" singer="齐秦">往事随风</a>
</li>
<li data-view="6"><a href="/4.mp3" singer="beyond">光辉岁月</a></li>
<li data-view="5"><a href="/5.mp3" singer="陈慧琳">记事本</a></li>
<li data-view="5">
<a href="/6.mp3" singer="邓丽君">但愿人长久</a>
</li>
</ul>
</div>'''
result = re.search('<li.*?active.*?singer="(.*?)">(.*?)</a>',html,re.S)
print(result)
print(result.group())
# print(result.group(1))
# print(result.group(2))
<re.Match object; span=(121, 286), match='<li data-view="2">一路上有你</li>\n<li data-view="7">\>
<li data-view="2">一路上有你</li>
<li data-view="7">
<a href="/2.mp3" singer="任贤齐">沧海一声笑</a>
</li>
<li data-view="4" class="active">
<a href="/3.mp3" singer="齐秦">往事随风</a>
import re
html = '''<div id="songs-list">
<h2 class="title">经典老歌</h2>
<p class="introduction">
经典老歌列表
</p>
<ul id="list" class="list-group">
<li data-view="2">一路上有你</li>
<li data-view="7">
<a href="/2.mp3" singer="任贤齐">沧海一声笑</a>
</li>
<li data-view="4" class="active">
<a href="/3.mp3" singer="齐秦">往事随风</a>
</li>
<li data-view="6"><a href="/4.mp3" singer="beyond">光辉岁月</a></li>
<li data-view="5"><a href="/5.mp3" singer="陈慧琳">记事本</a></li>
<li data-view="5">
<a href="/6.mp3" singer="邓丽君">但愿人长久</a>
</li>
</ul>
</div>'''
result = re.search('<li.*?active.*?singer="(.*?)">(.*?)</a>',html,re.S)
print(result)
print(result.groups())
print(result.group(1))
print(result.group(2))
<re.Match object; span=(121, 286), match='<li data-view="2">一路上有你</li>\n<li data-view="7">\>
('齐秦', '往事随风')
齐秦
往事随风
- re.findall()
搜索字符串,以列表的形式返回全部匹配的子串
#re.findall()
#搜索字符串,以列表的形式返回全部能匹配的字符串
import re
html = '''<div id="songs-list">
<h2 class="title">经典老歌</h2>
<p class="introduction">
经典老歌列表
</p>
<ul id="list" class="list-group">
<li data-view="2">一路上有你</li>
<li data-view="7">
<a href="/2.mp3" singer="任贤齐">沧海一声笑</a>
</li>
<li data-view="4" class="active">
<a href="/3.mp3" singer="齐秦">往事随风</a>
</li>
<li data-view="6"><a href="/4.mp3" singer="beyond">光辉岁月</a></li>
<li data-view="5"><a href="/5.mp3" singer="陈慧琳">记事本</a></li>
<li data-view="5">
<a href="/6.mp3" singer="邓丽君">但愿人长久</a>
</li>
</ul>
</div>'''
results=re.findall('<li.*?href="(.*?)".*?singer="(.*?)">(.*?)</a>',html,re.S)
print(results)
print(type(results))
# print(results.group()) 错误,列表没有group()P
# print(results.group(1))
# print(results.group(2))
print(results[0])
for value in results:
print(value)#输出了元组
print(value[0], value[1], value[2])
[('/2.mp3', '任贤齐', '沧海一声笑'), ('/3.mp3', '齐秦', '往事随风'), ('/4.mp3', 'beyond', '光辉岁月'), ('/5.mp3', '陈慧琳', '记事本'), ('/6.mp3', '邓丽君', '但愿人长久')]
<class 'list'>
('/2.mp3', '任贤齐', '沧海一声笑')
('/2.mp3', '任贤齐', '沧海一声笑')
/2.mp3 任贤齐 沧海一声笑
('/3.mp3', '齐秦', '往事随风')
/3.mp3 齐秦 往事随风
('/4.mp3', 'beyond', '光辉岁月')
/4.mp3 beyond 光辉岁月
('/5.mp3', '陈慧琳', '记事本')
/5.mp3 陈慧琳 记事本
('/6.mp3', '邓丽君', '但愿人长久')
/6.mp3 邓丽君 但愿人长久
- re.compile()
将正则字符串编译成正则表达式对象,以便于复用该匹配模式。
# re.compile()
# 将正则字符串编译成正则表达式对象,以便于复用该匹配模式
import re
html = '''<div id="songs-list">
<h2 class="title">经典老歌</h2>
<p class="introduction">
经典老歌列表
</p>
<ul id="list" class="list-group">
<li data-view="2">一路上有你</li>
<li data-view="7">
<a href="/2.mp3" singer="任贤齐">沧海一声笑</a>
</li>
<li data-view="4" class="active">
<a href="/3.mp3" singer="齐秦">往事随风</a>
</li>
<li data-view="6"><a href="/4.mp3" singer="beyond">光辉岁月</a></li>
<li data-view="5"><a href="/5.mp3" singer="陈慧琳">记事本</a></li>
<li data-view="5">
<a href="/6.mp3" singer="邓丽君">但愿人长久</a>
</li>
</ul>
</div>'''
pattern = re.compile('<li.*?href="(.*?)".*?singer="(.*?)">(.*?)</a>',re.S)#将正则字符串编译成正则表达式对象
results=re.findall(pattern,html)
print(results)
print(type(results))
for result in results:
print(result)
print(result[0], result[1],result[2])
[('/2.mp3', '任贤齐', '沧海一声笑'), ('/3.mp3', '齐秦', '往事随风'), ('/4.mp3', 'beyond', '光辉岁月'), ('/5.mp3', '陈慧琳', '记事本'), ('/6.mp3', '邓丽君', '但愿人长久')]
<class 'list'>
('/2.mp3', '任贤齐', '沧海一声笑')
/2.mp3 任贤齐 沧海一声笑
('/3.mp3', '齐秦', '往事随风')
/3.mp3 齐秦 往事随风
('/4.mp3', 'beyond', '光辉岁月')
/4.mp3 beyond 光辉岁月
('/5.mp3', '陈慧琳', '记事本')
/5.mp3 陈慧琳 记事本
('/6.mp3', '邓丽君', '但愿人长久')
/6.mp3 邓丽君 但愿人长久
- re.sub
替换字符串中每一个匹配的子串后返回替换后的字符串
语法:re.sub(正则表达式,替换成的字符串,原字符串)
#re.sub
# 替换字符串中每一个匹配的子串后返回替换后的字符串
# 语法:re.sub(正则表达式,替换成的字符串,原字符串)
import re
content='hello 123466 world'
content=re.sub('\d+','',content)
print(content)
hello world
#有些情况下我们替换字符的时候,还想获取我们匹配的字符串,然后在后面添加一些内容
#需要注意的一个问题是\1是获取第一个匹配的结果,为了防止转义字符的问题,我们需要在前面加上r
import re
content='hello 123466 world'
# content = re.sub('(\d+)','\1 7890',content)
# content = re.sub('(\d+)',r' 7890',content)
content = re.sub('(\d+)',r'\1 7890',content)
print(content)
hello 123466 7890 world
#贴吧爬虫
#tiebaSpider
import requests
import re
import csv
import pymysql
class TiebaSpider(object):
def __init__(self,tibaName):
self.tibaName=tibaName
self.base_url='https://tieba.baidu.com/f?kw='+tibaName+'&ie=utf-8&pn={}'
self.headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36'
}
#构建请求链接实现翻页
def get_url_list(self):
url_list=[]
for i in range(1):
url_list.append(self.base_url.format(i*50)) #format
return url_list
#请求页面信息
def get_pageInfo(self,url):
response=requests.get(url=url,headers=self.headers)
#print(response.content.decode('utf-8'))
return self.parse_pageInfo(response.content.decode('utf-8'))
#解析界面
def parse_pageInfo(self,html):
pattern=re.compile('<li class=" j_thread_list clearfix".*?<a.*? href="(.*?)".*?title="(.*?)".*?</a>',re.S)
# print(re.findall(pattern,html))
return (re.findall(pattern,html))
#存储到txt中
def save_to_txt(selfself,info):
for tuple_value in info:
info_str='贴子的信息:'+tuple_value[1]+'贴子的链接:https://tieba.baidu.com'+tuple_value[0]+'\n'
#print(info_str)
#
with open('./tieba.txt','a',encoding='utf-8') as f:
f.write(info_str)
'''
#写入到csv中,导入import csv
def save_to_csv(self,info):
for tuple_value in info:
#newline默认会有'\r\n'换行符
#encoding='utf-8-sig,解决中文乱码
with open('./tieba.csv','a',newline='',encoding='utf-8-sig') as f:
writer=csv.writer(f)
writer.writerow(list(tuple_value)) #writerow一行一行去写
#写入到数据库,导入pymysql
def save_to_database(self,info):
#链接数据库
conn=pymysql.connect(host='localhost',user='root',passwd='123',db='tieba',port=3306,charset='utf8mb4')
#游标对象(内部包含了很多操作数据库的方法)
cursor=conn.cursor()
#info={('链接'),(文字)...}
for tuple_value in info:
#插入数据,构造SQL语句
sql="insert into tieba_info (info,url) values('{}','{}')".format(tuple_value[1])
#执行SQL
cursor.execute(sql)
#提交事务
conn.commit()
#关闭游标
cursor.close()
#关闭数据库连接
conn.close()
'''
#所有的逻辑结构都放在这里面,封装及调用
def run(self):
#1.获取链接
url_list=self.get_url_list()#
#2.发送请求
for url in url_list:
info=self.get_pageInfo(url)
#self.save_to_txt(info)
self.save_to_csv(info)
#self.save_to_database(info)
if __name__=="__main__":
tiebaspider=TiebaSpider('lol')
tiebaspider.run()