发布于2020-02-24 22:18 阅读(1128) 评论(0) 点赞(6) 收藏(2)
在前两节中我们已经了解了怎么下载html,发起请求,获取响应字符串了,那么剩下的就当然是从html中提取我们需要的数据了,在python中提取数据有几种方式,其中一种是最原始的正则表达式提取,这种方式比较麻烦,维护起来费劲,因为正则表达式不是很容易被理解,但我们还是能经常用到它,比如,在提取完大段数据后,有时候我们需要用正则来提取其中更简短的信息,总之肯定会经常用到,无论大型项目还是小的爬虫脚本。
正则表达式 | 配置内容 |
---|---|
\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 |
() | 匹配括号内的表达式,也表示一组 |
从字符串开头开始匹配,一旦开头不匹配,则失败
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)`
正则表达式中带圆括号的部分就是待提取的目标数据,我们可以利用 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
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)
在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
content = 'his username is ddd999!'
result= re.search(r'ddd(\d{3})', content, re.I | re.M)
print(result.group(1))
# 999
content = '(百度)www.baidu.com'
result = re.match('\(百度\)www\.baidu\.com', content)
print(result.group())
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))
# 齐秦 往事随风
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', '光辉岁月')]
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())
有时我们会先将固定不变的正则表达式编译成对象,再用这个对象来匹配不同的字符串,用以提高脚本的效率。
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)
作者:sdhjsdh
链接:https://www.pythonheidong.com/blog/article/232407/debbcb825c42c26d5098/
来源:python黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 python黑洞网 All Rights Reserved 版权所有,并保留所有权利。 京ICP备18063182号-1
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!