正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配。
Python 自1.5版本起增加了re 模块,它提供 Perl 风格的正则表达式模式。
re 模块使 Python 语言拥有全部的正则表达式功能。
compile 函数根据一个模式字符串和可选的标志参数生成一个正则表达式对象。该对象拥有一系列方法用于正则表达式匹配和替换。 >re 模块也提供了与这些方法功能完全一致的函数,这些函数使用一个模式字符串做为它们的第一个参数。(引用出处:菜鸟教程–正则表达式)
使用re.match()函数,必须导入re模块:从第一个字符开始匹配,且只返回一个匹配成功的字符串,不是第一个字符则失败。
import re
re.match(pattern, string, flags=0)
参数 | 说明 |
---|---|
pattern | 编写的正则表达式字符串 |
string | 要去匹配正则表达式的原始字符串或请求回来的网页源代码 |
flags | 标志位,用于控制正则表达式的匹配方式,如:re.S,re.I,re.DOTALL等 |
如果匹配成功,match()返回一个匹配对象,否则返回None。可以使用group(num=0)来获取匹配成功的字符串。
import re
text = 'hello world'
ret = re.match('he', text)
ret = re.match('world',text) # None
print(ret.group()) # he
text = 'hello'
ret = re.match('.', text)
print(ret.group()) # h
# text = '9'
# ret = re.match('\d', text)
# print(ret.group())
text = '9'
ret = re.match('\D', text)
print(ret.group()) # 'NoneType' object has no attribute 'group'
text = '\r'
ret = re.match('\D', text)
print(ret.group())
text = 'hello'
ret = re.match('\w', text)
print(ret.group())
text = 'a1234'
ret = re.match('[a1]', text)
print(ret.group())
配合通配符,能匹配多个字符,如"+,*,?"
匹配电话号码:
text = '0731-88888888aaaa'
ret = re.match('[\d\-]+', text)
print(ret.group()) # 0731-88888888
text = '0731-88888888aaaa'
ret = re.match('[0-9\-]+', text)
print(ret.group()) # 0731-88888888
text = '0731-88888888aaaa'
ret = re.match('[0-9a-zA-Z_\-]+', text)
print(ret.group()) # 0731-88888888aaaa
text = 'abcd'
ret = re.match('\w*', text)
print(ret.group()) # abcd
text = 'ab+cd'
ret = re.match('\w+', text)
print(ret.group()) # ab
text = 'abcd'
ret = re.match('\w?', text)
print(ret.group()) # 只返回"a"
text = 'abcd'
ret = re.match('\w{3}', text)
print(ret.group()) # 只返回"abc"
text = 'abcdefghijk'
ret = re.match('\w{1,5}', text)
print(ret.group()) # 只返回"abcde"
text = '13377005111'
ret = re.match('1[3456789]\d{9}', text)
print(ret)
text = '[email protected] hjm'
ret = re.match('\w*@[a-z0-9]*\.[a-z]*', text)
print(ret, ret)
text = 'http://www.baidu.com/'
ret = re.match('(http|https|ftp):[^\s]+', text)
print(ret)
text = '45233019750101001X'
ret = re.match('\d{17}[0xX]', text)
print(ret)
text = 'hello'
ret = re.match('^h', text)
print(ret)
* ”$“:表示以...结尾
```python
text = '[email protected]'
ret = re.match('\w+@163\.com$', text)
print(ret)
text = 'https'
ret = re.match('(ftp|http|https)$', text)
print(ret)
text = 'Title
'
ret = re.match('<.*>', text) # 贪婪模式
ret1 = re.match('<.*?>', text) # 非贪婪模式
print(ret)
print(ret1)
text = 'Apple price is $299'
ret = re.search('\$\d+', text)
print(ret)
text = r'\c'
ret = re.match(r'\\c', text)
print(ret.group())
text = "apple's price $299,orange's price $10"
ret = re.search('.*(\$\d+).*(\$\d+)', text)
print(ret.group())
print(ret.group(1))
print(ret.group(2))
print(ret.group(1, 2))
print(ret.groups())
text = '98'
ret = re.match('([1-9]\d?$|100$)', text)
print(ret)
re.search()函数扫描整个字符串并返回第一个成功的匹配。
函数语法:
re.search(pattern, string, flags=0)
re.match()与re.search()的区别:
re.match()只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回 None,而 re.search()匹配整个字符串,直到找到一个匹配。如:
text = 'hello world'
ret = re.match('hello', text) # hello
ret = re.match('world', text) # None 不是第一个,匹配失败
ret = re.search('world', text) # world
print(ret.group())
re.findall()函数,在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。
注意: re.match()和re.search()是匹配一次,re.findall()匹配所有。
函数语法:
re.findall(string[, pos[, endpos]])
参数:
参数 | 说明 |
---|---|
string | 待匹配的字符串 |
pos | 可选参数,指定字符串的起始位置,默认为 0 |
endpos | 可选参数,指定字符串的结束位置,默认为字符串的长度 |
text = "apple's price $299,orange's price $10"
rets = re.findall('\$\d+', text) # 返回列表
print(rets)
re.sub()用于替换字符串中的匹配项,经常用来替换提取出来的标签,如:”
床前明月光\n“。返回的是字符串。
re.sub(pattern, repl, string, count=0, flags=0)
参数:
参数 | 说明 |
---|---|
pattern | 正则中的模式字符串 |
repl | 替换的字符串,也可为一个函数(或lambda表达式) |
string | 要被查找替换的原始字符串 |
count | 模式匹配后替换的最大次数,默认0表示替换所有的匹配 |
flags | 编译时用的匹配模式,数字形式 |
text = "apple's price $299,orange's price $10"
ret = re.sub('\d+', '0', text)
print(ret)
html = '''
职位描述:
负责各类银行业务系统的设计、开发(JAVA方向)及团队管理工作。
应聘条件:
1、全日制大学本科及以上学历,计算机相关专业(应聘者需获得全日制统招本科毕业证、学位证);
2、精通Java语言,J2EE架构及重用轻量级开源架构,精通面向对象系统架构设计,并熟悉一种以上数据库;
3、1年以上开发工作经验,并参与过大型JAVA项目的设计、开发工作,具备项目管理或开发团队管理经验者优先;
4、具备良好的沟通力、表达力、团队协作力以及责任心;
5、熟悉金融或者企业财务相关的业务,有参与金融系统开发经验者优先。
'''
#
ret = re.sub('<.*?>', '', html)
r_list = re.split('<.*?>', html)
print(ret)
print(r_list)
用于编译正则表达式,生成一个正则表达式( Pattern )对象,供 match() 和 search()、findall()函数使用。
函数语法:
re.compile(pattern[, flags])
参数:
参数 | 说明 |
---|---|
pattern | 一个字符串形式的正则表达式 |
flags | 可选,表示匹配模式,比如忽略大小写,多行模式等,具体参数为: |
re.I | 忽略大小写 |
re.L | 表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境 |
re.M | 多行模式 |
re.S | 即为’ . ‘并且包括换行符在内的任意字符(’ . '不包括换行符) |
re.U | 表示特殊字符集 \w, \W, \b, \B, \d, \D, \s, \S 依赖于 Unicode 字符属性数据库 |
re.X/re.VERBOSE | 为了增加可读性,忽略空格和’ # '后面的注释 |
示例:
text = 'the number is 20.50'
# r = re.compile('\d+\.\d+')
r = re.compile(r'''
\d+ # 小数点前面的数字
\. # 小数点本身
\d+ # 小数点后面的数字
''',re.VERBOSE)
ret = re.search(r, text)
print(ret.group())
# -*- coding: utf-8 -*-
'''正则表达式学习'''
import re, requests, json
import pandas as pd
def parse_page(url):
headers = {
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36'
}
resp = requests.get(url, headers=headers)
html = resp.text
# 初学正则表达式,分段获取所需信息不易出错
# 获取诗词标题
titles = re.findall('(.*?)', html, re.S)
# 获取作者
authors = re.findall('.*?(.*?).*?(.*?)'
, html, re.S)
# 获取诗词正文
content_tags = re.findall('(.*?)', html, re.S)
contents = []
for i in range(len(content_tags)):
x = re.sub('<.*?>', '', content_tags[i])
contents.append(x.split())
poems = []
for value in zip(titles, authors, contents):
title, author, content = value
poem = {
'title': title,
'author': author,
'content': content
}
poems.append(poem)
print(poems)
print('-'*40)
def main():
for i in range(1, 11):
url = 'https://www.gushiwen.org/default_%s.aspx' % i
poems = parse_page(url)
if __name__ == '__main__':
main()
三、正则表达式实战练习:爬取古诗文网站唐诗三百首
- 代码如下:
# -*- conding: utf-8 -*-
"""
实战:爬取古诗文网唐诗三百首,学习使用正则表达式解析提取网页
1.使用浏览器开发者工具,从唐诗三百首全集页面'https://so.gushiwen.org/gushi/tangshi.aspx'
获取每首诗的网址包含id的后半部分,从而整合得到完整网址。
2.进入新页面使用正则表达式获取唐诗的诗句、作者、诗句、译注。
3.使用pandas将数据保存到CSV文件中。
说明:古诗文网站属于静态html,比较简单,练习正则表达式正合适
"""
import requests, re, time, random
import pandas as pd
headers = {
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36'
}
def get_poem(poem_url):
"""获取每首唐诗标题、作者、正文等信息"""
resp = requests.get(poem_url, headers=headers)
resp.encoding = 'utf-8'
text = resp.text
# 获取唐诗标题,全为唐诗,作者都是唐朝的,故不再提取朝代
title = re.findall('h1 style.*?>(.*?)', text, re.S)[0]
# 获取作者姓名,后面列有1-3首其他作者的诗,所以只取第一位
author = re.findall(
'.*?(.*?)'
, text, re.S)[0]
# 获取诗句正文
content = re.findall(
'(.*?)', text, re.S)[0]
content = re.sub('\s', '', re.sub('
', '', content)) # 清除标签、空白符
# 获取诗文翻译、注释
target_texts = re.findall('.*?(.*?)
', text, re.S)
for i in range(len(target_texts)): # 清除标签、空白符
target_texts[i] = re.sub(
'\s', '', re.sub('<.*?>', '', target_texts[i]))
poem_info = {
'诗名': title,
'作者': author,
'诗文': content,
'译注': target_texts
}
# print(poem_info)
return poem_info
def get_url(base_url, tangshi_url):
"""获取每首唐诗的url"""
resp = requests.get(tangshi_url, headers=headers)
resp.encoding = 'utf-8'
r = re.compile('', re.S)
poem_urls = re.findall(r, resp.text) # 获取诗文id后半部分地址
for i in range(len(poem_urls)):
poem_urls[i] = base_url + poem_urls[i] # 合成完整url
# print(poem_urls[0:4])
return poem_urls
def save_poems(poem_infos):
"""保存数据"""
df = pd.DataFrame(poem_infos, columns=['诗名', '作者', '诗文', '译注'])
print(df)
df.to_csv('tangshi300.csv')
def main():
"""主运行函数"""
base_url = 'https://so.gushiwen.org/' # 整合每首诗的网址用基址
tangshi_url = 'https://so.gushiwen.org/gushi/tangshi.aspx'
poem_urls = get_url(base_url, tangshi_url)
poem_infos = []
i = 1
for poem_url in poem_urls:
poem_infos.append(get_poem(poem_url))
print('', end='') # 大佬说要多加这行,没整明白
time.sleep(random.randint(1, 8)) # 随机休息一会,缓解服务器压力
# 不换行在同一行显示进度,”\r“表示回到行首覆盖输出
print('\r' + '数据采集完成进度--> %.2f%%' % (i / len(poem_urls) * 100), end='')
i += 1
save_poems(poem_infos)
if __name__ == "__main__":
main()