python3 2018分布式爬虫教程 -5 正则表达式

1.正则表达式常见匹配模式:

模式                          描述
\w                      匹配字母数字及下划线
\W                      匹配非字母数字下划线
\s                      匹配任意空白字符,等价于 [\t\n\r\f].
\S                      匹配任意非空字符
\d                      匹配任意数字,等价于 [0-9]
\D                      匹配任意非数字
\A                      匹配字符串开始
\Z                      匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串
\z                      匹配字符串结束
\G                      匹配最后匹配完成的位置
\n                      匹配一个换行符
\t                      匹配一个制表符
^                       匹配字符串的开头
$                       匹配字符串的末尾。
.                       匹配任意字符,除了换行符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符。
[...]                   用来表示一组字符,单独列出:[amk] 匹配 'a','m'或'k'
[^...]                  不在[]中的字符:[^abc] 匹配除了a,b,c之外的字符。
*                       匹配0个或多个的表达式。
+                       匹配1个或多个的表达式。
?                       匹配0个或1个由前面的正则表达式定义的片段,非贪婪方式
{n}                     精确匹配n个前面表达式。
{n,m}                   匹配 n 到 m 次由前面的正则表达式定义的片段,贪婪方式
a|b                     匹配a或b
( )                     匹配括号内的表达式,也表示一个组

1.re.match:尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none。

re.match(pattern, string, flags=0)

pattern:正则表达式

string:被匹配的字符串

flags:匹配模式,编译标志位,用于修改正则表达式的匹配方式,如:是否区分大小写,多行匹配等。(多条件匹配可以使用或运算符'|'表示,例如: flags=re.I | re.S)

注意: “|”两边不能有空格

常用的flags有:

标志

含义

re.S(DOTALL)

使.匹配包括换行在内的所有字符

re.I(IGNORECASE)

使匹配对大小写不敏感

re.L(LOCALE)

做本地化识别(locale-aware)匹配,法语等

re.M(MULTILINE)

多行匹配,影响^和$

re.X(VERBOSE)

该标志通过给予更灵活的格式以便将正则表达式写得更易于理解

re.U

根据Unicode字符集解析字符,这个标志影响\w,\W,\b,\B

获取匹配结果字符:

re.match(pattern,string,flags).group()

获取匹配结果字符长度:

re.match(pattern,string,flags).span()

1)常规匹配:

import re

content = 'Hello 123 4567 World_This is a Regex Demo'
print(len(content))
result = re.match('^Hello\s\d\d\d\s\d{4}\s\w{10}.*Demo$', content)
print(result)
print(result.group())
print(result.span())


'''
41
<_sre.SRE_Match object; span=(0, 41), match='Hello 123 4567 World_This is a Regex Demo'>
Hello 123 4567 World_This is a Regex Demo
(0, 41)
'''

2)泛匹配: " .* "   (匹配任意字符)

import re

content = 'Hello 123 4567 World_This is a Regex Demo'
result = re.match('^Hello.*Demo$', content)
print(result)
print(result.group())
print(result.span())

'''
<_sre.SRE_Match object; span=(0, 41), match='Hello 123 4567 World_This is a Regex Demo'>
Hello 123 4567 World_This is a Regex Demo
(0, 41)
'''

3)匹配目标(获取指定位置的字符)

import re

content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^Hello\s(\d+)\sWorld_This\s(\w+)\sa.*Demo$', content)
print(result)
print(result.group())
print(result.group(1))
print(result.group(2))
print(result.span())

'''
<_sre.SRE_Match object; span=(0, 40), match='Hello 1234567 World_This is a Regex Demo'>
Hello 1234567 World_This is a Regex Demo
1234567
is
(0, 40)
'''

4)贪婪匹配 (左边的泛匹配会尽可能多的匹配字符)

import re

content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^Hello\s\d+(\d+).*Demo$', content)
print(result)
print(result.group())
print(result.group(1))


'''
<_sre.SRE_Match object; span=(0, 40), match='Hello 1234567 World_This is a Regex Demo'>
Hello 1234567 World_This is a Regex Demo
7
'''

5)非贪婪匹配 "?" (左边的泛匹配会尽可能少的匹配字符)

import re

content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^Hell.*?(\d+).*Demo$', content)
print(result)
print(result.group())
print(result.group(1))

'''
<_sre.SRE_Match object; span=(0, 40), match='Hello 1234567 World_This is a Regex Demo'>
Hello 1234567 World_This is a Regex Demo
1234567
'''

6)flags 匹配模式

import re

content = '''Hello 1234567 World_This 
is a Regex Demo'''
result = re.match('^Hell.*?(\d+).*Demo$', content,flags=re.S)
print(result)
print(result.group())
print(result.group(1))

'''
<_sre.SRE_Match object; span=(0, 41), match='Hello 1234567 World_This \nis a Regex Demo'>
Hello 1234567 World_This 
is a Regex Demo
1234567
'''

多条件匹配,例如(同时匹配换行符并且忽略大小写)

import re

content = '''hello 1234567 World_This 
is a Regex Demo'''
result = re.match('^Hell.*?(\d+).*Demo$', content,flags=re.I | re.S)
print(result)
print(result.group())
print(result.group(1))

'''
<_sre.SRE_Match object; span=(0, 41), match='hello 1234567 World_This \nis a Regex Demo'>
hello 1234567 World_This 
is a Regex Demo
1234567
'''

7)转义 "\"

import re

content = 'price is $5.00'
result = re.match('price is $5.00', content)
print(result)

'''
None
'''

content = "value $1000.00"
result = re.match("^value\s(\$)\d{4}(\.)\d{2}", content, flags=re.I)
print(result)
print(result.group(1))
print(result.group(2))

'''
<_sre.SRE_Match object; span=(0, 14), match='value $1000.00'>
$
.
'''

2.re.search:扫描整个字符串并返回第一个成功的匹配。

总结:为匹配方便,能用search就不用match

re.search(pattern, string, flags=0)

匹配实例:

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.*?singer="(.*?)">(.*?)</a>', html, re.S)
if result:
    print(result.group(1), result.group(2))

'''
任贤齐 沧海一声笑
'''

2.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>'''
result = re.findall('''<li.*?<a.*?singer="(.*?)">(.*?)</a>''', html, flags=re.S)
print(result)

'''
[('任贤齐', '沧海一声笑'), ('齐秦', '往事随风'), ('beyond', '光辉岁月'), ('陈慧琳', '记事本'), ('邓丽君', '但愿人长久')]
'''

3.re.sub:替换字符串中每一个匹配的子串后返回替换后的字符串。

re.sub(pattern, repl, string, count=0)

注意: "|" 两边不能有空格

import re

content = '''not to 
          stop 123 until death'''
results = re.sub("\n\s*|\s\d+", "", content, re.I)
print(results)


'''
not to stop until death
'''

pattern 中的括号对应 repl 中的 '\1'   '\2'    '\3' ...

import re

content = "not to stop 123 until death"
results = re.sub("\s(stop)\s(\d+)", r" \2 \1", content, re.I)
print(results)


'''
not to 123 stop until death
'''

re.sub 和re.findall 联合使用

import re

htmls = '''<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>'''

htmls = re.sub("<a.*?>|</a>", "", htmls, re.S)
results = re.findall("<li.*?>\n?\s*(.*?)\n?\s*</li>", htmls, re.S)
for name in results:
    print("name: ", name)

'''
name:  一路上有你
name:  沧海一声笑
name:  往事随风
name:  光辉岁月
name:  记事本
name:  但愿人长久
'''

4.re.compile:将正则字符串编译成正则表达式对象,以便重复使用。

import re

content = '''be released 12345 only by death '''
pattern = re.compile('\d{5}', re.I)
result = re.search(pattern, content)
#result = re.search('\s\d+', content, re.I)
print(result.group()) if result != None else print("None")

'''
<_sre.SRE_Match object; span=(12, 17), match='12345'>
'''

5.实战练习

import requests
import re

url = "https://movie.douban.com/chart"
response = requests.get(url)
htmls = response.content.decode()
# html = re.sub('<span.*?>|</span>', '', htmls)
results = re.findall('''<a class="nbg" href="(.*?)".*? <a.*?>(.*?)</a>.*?<p.*?>(.*?)</p>.*?rating_nums">(.*?)</span>''', htmls, re.S)
for url, name, introduce, rating_nums in results:
    name = re.sub("\s*\n\s|<span.*?>|</span>|\s*", "", name)
    print("url: ", url)
    print("name: ", name)
    print("introduce: ", introduce)
    print("rating_nums: ", rating_nums)
    print("------------------------------------")


'''
url:  https://movie.douban.com/subject/27615441/
name:  网络谜踪/人肉搜寻(港)/人肉搜索(台)
introduce:  2018-01-20(圣丹斯电影节) / 2018-08-24(美国) / 2018-12-14(中国大陆) / 约翰·赵 / 米切尔·拉 / 黛博拉·梅辛 / 约瑟夫·李 / 萨拉·米博·孙 / 亚历克丝·杰恩·高 / 梅金·刘 / 刘卡雅 / 多米尼克·霍夫曼 / 西尔维亚·米纳西安 / 梅丽莎·迪斯尼...
rating_nums:  8.5
------------------------------------
url:  https://movie.douban.com/subject/27102569/
name:  悲伤逆流成河/悲伤逆流成河电影版/CryMeaSadRiver
introduce:  2018-09-21(中国大陆) / 赵英博 / 任敏 / 辛云来 / 章若楠 / 朱丹妮 / 中国大陆 / 落落 / 104分钟 / 剧情 / 爱情 / 落落 Luo Luo / 郭敬明 Jingming Guo / 汉语普通话
rating_nums:  5.8
------------------------------------
url:  https://movie.douban.com/subject/27172891/
name:  大象席地而坐/金羊毛/爱在樱花盛开时
introduce:  2018-02-16(柏林电影节) / 彭昱畅 / 章宇 / 王玉雯 / 李从喜 / 董向荣 / 王柠 / 赵燕国彰 / 朱颜曼滋 / 凌正辉 / 王超北 / 王雪洋 / 中国大陆 / 胡波 / 230分钟(导演剪辑版) / 剧情 / 胡迁 Qian Hu / 汉语普通话
rating_nums:  8.1
------------------------------------
url:  https://movie.douban.com/subject/26336252/
name:  碟中谍6:全面瓦解/碟中谍6/不可能的任务:全面瓦解(台)
introduce:  2018-07-27(美国) / 2018-08-31(中国大陆) / 汤姆·克鲁斯 / 亨利·卡维尔 / 文·瑞姆斯 / 西蒙·佩吉 / 丽贝卡·弗格森 / 西恩·哈里斯 / 安吉拉·贝塞特 / 凡妮莎·柯比 / 米歇尔·莫纳汉 / 韦斯·本特利 / 费雷德里克·施密特 / 亚历克·鲍德温...
rating_nums:  8.2
......
'''

猜你喜欢

转载自blog.csdn.net/QYmufeng/article/details/85007467
今日推荐