程序员最近都爱上了这个网站  程序员们快来瞅瞅吧!  it98k网:it98k.com

本站消息

站长简介/公众号

  出租广告位,需要合作请联系站长

+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

python爬虫必备-re库及正则表达式详解

发布于2020-02-24 22:18     阅读(1128)     评论(0)     点赞(6)     收藏(2)


re库及正则表达式详解

在前两节中我们已经了解了怎么下载html,发起请求,获取响应字符串了,那么剩下的就当然是从html中提取我们需要的数据了,在python中提取数据有几种方式,其中一种是最原始的正则表达式提取,这种方式比较麻烦,维护起来费劲,因为正则表达式不是很容易被理解,但我们还是能经常用到它,比如,在提取完大段数据后,有时候我们需要用正则来提取其中更简短的信息,总之肯定会经常用到,无论大型项目还是小的爬虫脚本。

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
[^…] 不在[]中的字符
* 匹配0个或多个表达式
+ 匹配1个或多个表达式
? 匹配0个或1个前面的正则表达式定义的片段,非贪婪模式
{n} 精确匹配n个前面的表达式
{n,m} 匹配n到m次由前面正则表达式定义的片段,贪婪模式
a b
() 匹配括号内的表达式,也表示一组

2. match()用法

从字符串开头开始匹配,一旦开头不匹配,则失败

content = 'Hello 123 4567 World_This is a Regex Demo'
print(len(content))
# 41
result = re.match('^Hello\s\d\d\d\\s\d{4}\s\w{10}', content)
print(result)
# <re.Match object; span=(0, 25), match='Hello 123 4567 World_This'>
print(result.group())
# Hello 123 4567 World_This
print(result.span())
# (0, 25)`
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

3. 提取目标数据

正则表达式中带圆括号的部分就是待提取的目标数据,我们可以利用 group(1) 表达式将它提取出来。
如果不引入括号,整个表达式作为一个组,是group(0),如果有括号,那么第一个括号的分组就是group(1) ,以此类推第二个括号的分组就是group(2)第二组匹配的数据。

# 匹配目标
content = 'Hello 123 4567 World_This is a Regex Demo'
result = re.match('^Hello\s(\d+)\s\d{4}\sWorld', content)
print(result.group(1))
# 123
  • 1
  • 2
  • 3
  • 4
  • 5

4. 通用匹配

content = 'Hello 123 4567 World_This is a Regex Demo'
result = re.match('^Hello\s.*Demo$', content)
print(result.group())
# Hello 123 4567 World_This is a Regex Demo
print(result.span())
# (0, 41)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

5. 贪婪与非贪婪

  • 贪婪模式:正则表达式一般趋向于最大长度匹配,也就是所谓的贪婪匹配。
  • 非贪婪模式:在整个表达式匹配成功的前提下,尽可能少的匹配。

在python中默认采用的是贪婪模式,使用非贪婪模式的话,只需要在量词后面直接加上一个问号”?”

# .*? 非贪婪模式
content = 'Hello 123 4567 World_This is a Regex Demo'
result = re.match('^Hello\s.*?(\d+).*Demo$', content)
print(result.group(1))
# 123
content = 'http://weibo.com/comment/kEraCN'
result1 = re.match('http.*?comment/(.*?)', content)
print('result1', result1.group(1))
# result1
result2 = re.match('http.*?comment/(.*)', content)
print('result2', result2.group(1))
# result2 kEraCN
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

6. 修饰符

  • re.I 匹配大小写不敏感
  • re.L 做本地化识别匹配
  • re.M 多行匹配,影响^和$
  • re.S 使.匹配包括换行在内的所有字符
  • re.U 根据Unicode字符集解析字符,这个标志影响\w \W \b \B
  • re.X 更灵活的格式
content = 'his  username is ddd999!'
result= re.search(r'ddd(\d{3})', content, re.I | re.M)
print(result.group(1))
# 999
  • 1
  • 2
  • 3
  • 4

7. 转义匹配

content = '(百度)www.baidu.com'
result = re.match('\(百度\)www\.baidu\.com', content)
print(result.group())
  • 1
  • 2
  • 3

8. search查找首次匹配

search用来扫描整个字符串并返回第一个成功的匹配,如果匹配失败search()就返回None。

html = '''
    <li class="active">
        <a href="/3.mp3" singer="齐秦">往事随风</a>
    </li>
    <li>
        <a href="/2.mp3" singer="任贤齐">沧海一声笑</a>
    </li>
    <li>
        <a href="/1.mp3" singer="beyond">光辉岁月</a>
    </li>
    '''
result = re.search('<li.*?singer="(.*?)">(.*?)</a>', html, re.S)
if result:
    print(result.group(1), result.group(2))
# 齐秦 往事随风
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

9. findall 查找匹配所有

findall可以遍历匹配,可以获取字符串中所有匹配的字符串,返回一个列表

results = re.findall('<li.*?href="(.*?)".*?singer="(.*?)">(.*?)</a>', html, re.S)
print(results)
print(type(results))
for result in results:
    print(result)
    print(result[0], result[1], result[2])
    
# [('/3.mp3', '齐秦', '往事随风'), ('/2.mp3', '任贤齐', '沧海一声笑'), ('/1.mp3', 'beyond', '光辉岁月')]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

11. sub替换匹配字符串

sub用来替换匹配的字符串,在解析复杂的html时,可以用sub先来删除那些没有用的字符串,常用语简化复杂的原始字符串的场景。

content = "87fsdfss87f878asda76d78090ads897a8s"
content = re.sub('\d+', '', content)
print(content)
# fsdfssfasdadadsas

# 可以用来先删除节点,再提取内容,比较简单
html = re.sub('<a.*?>|</a>', '', html)
print(html)
results = re.findall('<li.*?>(.*?)</li>', html, re.S)
for result in results:
    print(result.strip())
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

12. compile编译正则表达式

有时我们会先将固定不变的正则表达式编译成对象,再用这个对象来匹配不同的字符串,用以提高脚本的效率。

content1 = '2016-10-11 12:00'
content2 = '2017-12-08 12:00'
content3 = '2018-06-18 12:00'
pattern = re.compile('\d{2}:\d{2}')
result1 = re.sub(pattern, '', content1)
result2 = re.sub(pattern, '', content2)
result3 = re.sub(pattern, '', content3)
print(result1,result2,result3)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
发布了34 篇原创文章 · 获赞 5 · 访问量 3万+


所属网站分类: 技术文章 > 博客

作者:sdhjsdh

链接:https://www.pythonheidong.com/blog/article/232407/debbcb825c42c26d5098/

来源:python黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

6 0
收藏该文
已收藏

评论内容:(最多支持255个字符)