關於正則表達式(爬蟲)

一.什麼是正則表達式?

    正则表达式是对字符串操作的一种逻辑公式,就是 事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符”,这个“规则字符” 来表达对字符的一种过滤逻辑。

正则并不是python独有的,其他语言也都有正则
python中的正则,封装了re模块

二.常見匹配模式

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

re.match()

尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配的话,match()就会返回None
语法格式:
re.match(pattern,string,flags=0)

最常見的匹配

import re

content= "hello 123 4567 World_This is a regex Demo"
result = re.match(‘^hello\s\d\d\d\s\d{4}\s\w{10}.*Demo$‘,content)
print(result)
print(result.group())
print(result.span())


運行結果如下:

/usr/bin/python3.5 /home/eric/PycharmProjects/untitled10/zhenze.py
<_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)

Process finished with exit code 0

result.group()获取匹配的结果
result.span()获去匹配字符串的长度范围

泛匹配

其实相对来说上面的方式并不是非常方便,其实可以将上述的正则规则进行更改

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())
其運行結果和上面的是一樣的。


匹配目标

如果为了匹配字符串中具体的目标,则需要通过()括起来,例子如下:

import re
content= "hello 1234567 World_This is a regex Demo"
result = re.match(‘^hello\s(\d+)\sWorld.*Demo$‘,content)
print(result)
print(result.group())
print(result.group(1))
print(result.span())

運行結果如下:

/usr/bin/python3.5 /home/eric/PycharmProjects/untitled10/ff.py
<_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
(0, 40)

Process finished with exit code 0
这里需要说一下的是通过re.group()获得结果后,如果正则表达式中有括号,则re.group(1)获取的就是第一个括号中匹配的结果

贪婪匹配


import re

content= "hello 1234567 World_This is a regex Demo"
result= re.match(‘^hello.*(\d+).*Demo‘,content)
print(result)
print(result.group(1))
運行結果是:

/usr/bin/python3.5 /home/eric/PycharmProjects/untitled10/ff.py
<_sre.SRE_Match object; span=(0, 40), match='hello 1234567 World_This is a regex Demo'>
7

Process finished with exit code 0

从结果中可以看出只匹配到了7,并没有匹配到1234567,出现这种情况的原因是前面的.* 给匹配掉了, .*在这里会尽可能的匹配多的内容,也就是我们所说的贪婪匹配,

如果我们想要匹配到1234567则需要将正则表达式改为:

result= re.match(‘^he.*?(\d+).*Demo‘,content)

这样结果就可以匹配到1234567


匹配模式

很多时候匹配的内容是存在换行的问题的,这个时候的就需要用到匹配模式re.S来匹配换行的内容

import re


content = """hello 123456 world_this
my name is zhaofan
"""

result =re.match(‘^he.*?(\d+).*?zhaofan$‘,content,re.S)
print(result)
print(result.group())
print(result.group(1))

運行結果如下:

/usr/bin/python3.5 /home/eric/PycharmProjects/untitled10/ff.py
<_sre.SRE_Match object; span=(0, 42), match='hello 123456 world_this\nmy name is zhaofan'>
hello 123456 world_this
my name is zhaofan
123456

Process finished with exit code 0

转义

当我们要匹配的内容中存在特殊字符的时候,就需要用到转移符号\,例子如下:

import re

content= "price is $5.00"

result = re.match(‘price is \$5\.00‘,content)
print(result)
print(result.group())

運行結果:

/usr/bin/python3.5 /home/eric/PycharmProjects/untitled10/ff.py
<_sre.SRE_Match object; span=(0, 14), match='price is $5.00'>
price is $5.00

Process finished with exit code 0

对上面的一个小结:
尽量使用泛匹配,使用括号得到匹配目标,尽量使用非贪婪模式,有换行符就用re.S
强调re.match是从字符串的起始位置匹配一个模式

re.search

re.search扫描整个字符串返回第一个成功匹配的结果

import re

content = "extra things hello 123455 world_this is a Re Extra things"

result = re.search("hello.*?(\d+).*?Re",content)
print(result)
print(result.group())
print(result.group(1))

運行結果:

/usr/bin/python3.5 /home/eric/PycharmProjects/untitled10/ff.py
<_sre.SRE_Match object; span=(13, 44), match='hello 123455 world_this is a Re'>
hello 123455 world_this is a Re
123455

Process finished with exit code 0

其实这个时候我们就不需要在写^以及$,因为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="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.*?"6".*?singer="(.*?)">(.*?)</a>',html,re.S)
print(result)
print(result.groups())
print(result.group(1))
print(result.group(2))

運行結果如下:

/usr/bin/python3.5 /home/eric/PycharmProjects/untitled10/ff.py
<_sre.SRE_Match object; span=(153, 448), match='<li data-view="2">一路上有你</li>\n        <li data-vi>
('beyond', '光辉岁月')
beyond
光辉岁月

Process finished with exit code 0

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))
for result in results:
    print(result)
    print(result[0], result[1], result[2])

運行結果如下;

/usr/bin/python3.5 /home/eric/PycharmProjects/untitled10/ff.py
[('/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 邓丽君 但愿人长久

Process finished with exit code 0

例2.

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.*?>\s*?(<a.*?>)?(\w+)(</a>)?\s*?</li>',html,re.S)
print(results)
for result in results:
    print(result[1])


運行結果:

/usr/bin/python3.5 /home/eric/PycharmProjects/untitled10/ff.py
[('', '一路上有你', ''), ('<a href="/2.mp3" singer="任贤齐">', '沧海一声笑', '</a>'), ('<a href="/3.mp3" singer="齐秦">', '往事随风', '</a>'), ('<a href="/4.mp3" singer="beyond">', '光辉岁月', '</a>'), ('<a href="/5.mp3" singer="陈慧琳">', '记事本', '</a>'), ('<a href="/6.mp3" singer="邓丽君">', '但愿人长久', '</a>')]
一路上有你
沧海一声笑
往事随风
光辉岁月
记事本
但愿人长久

Process finished with exit code 0

其实这里我们就可以看出

\s*? 这种用法其实就是为了解决有的有换行,有的没有换行的问题

(<a.*?>)? 这种用法是因为html中有的有a标签,有的没有的,?表示匹配一个或0个,正好可以用于匹配

re.sub

替换字符串中每一个匹配的子串后返回替换后的字符串

re.sub(正则表达式,替换成的字符串,原字符串)

例1:

import re

content = "Extra things hello 123455 World_this is a regex Demo extra things"

content = re.sub('\d+','',content)
print(content)
運行結果:

/usr/bin/python3.5 /home/eric/PycharmProjects/untitled10/ff.py
Extra things hello  World_this is a regex Demo extra things

Process finished with exit code 0

例子2,在有些情况下我们替换字符的时候,还想获取我们匹配的字符串,然后在后面添加一些内容,可以通过下面方式实现

import re

content = "Extra things hello 123455 World_this is a regex Demo extra things"

content = re.sub('(\d+)',r'\1 7890',content)
print(content)

運行結果:

/usr/bin/python3.5 /home/eric/PycharmProjects/untitled10/ff.py
Extra things hello 123455 7890 World_this is a regex Demo extra things

Process finished with exit code 0
这里需要注意的一个问题是\1是获取第一个匹配的结果,为了防止转义字符的问题,我们需要在前面加上r


re.compile

将正则表达式编译成正则表达式对象,方便复用该正则表达式

import re
content= """hello 12345 world_this
123 fan
"""

pattern =re.compile("hello.*fan",re.S)

result = re.match(pattern,content)
print(result)
print(result.group())

運行結果:

/usr/bin/python3.5 /home/eric/PycharmProjects/untitled10/ff.py
<_sre.SRE_Match object; span=(0, 30), match='hello 12345 world_this\n123 fan'>
hello 12345 world_this
123 fan

Process finished with exit code 0












  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java正则表达式虫是一种使用正则表达式来匹配和提取网页中的数据的虫程序。正则表达式是一种强大的文本匹配工具,可以用来描述和匹配字符串的模式。在Java中,可以使用java.util.regex包提供的类来实现正则表达式的功能。 以下是使用Java正则表达式虫的基本步骤: 1. 导入java.util.regex包:在Java程序中,首先需要导入java.util.regex包,以便使用正则表达式相关的类和方法。 2. 创建正则表达式模式:使用Pattern类的compile方法创建一个正则表达式模式。该模式描述了要匹配的字符串的规则。 3. 创建匹配器:使用Pattern类的matcher方法创建一个Matcher对象。Matcher对象用于对输入字符串进行匹配操作。 4. 进行匹配操作:使用Matcher对象的find、matches或replaceAll等方法进行匹配操作。find方法用于查找输入字符串中与模式匹配的子序列;matches方法用于判断整个输入字符串是否与模式匹配;replaceAll方法用于将输入字符串中与模式匹配的部分替换为指定的字符串。 5. 提取匹配结果:使用Matcher对象的group方法提取与模式匹配的子序列。group方法返回一个字符串,表示与模式匹配的子序列。 6. 循环匹配:如果需要提取多个匹配结果,可以使用循环结构来重复进行匹配操作。 下面是一个简单的示例代码,演示了如何使用Java正则表达式虫来提取网页中的链接: ```java import java.util.regex.Matcher; import java.util.regex.Pattern; public class RegexCrawler { public static void main(String[] args) { String html = "<a href=\"https://www.example.com\">Example</a>"; String pattern = "<a\\s+href=\"([^\"]+)\">([^<]+)</a>"; Pattern p = Pattern.compile(pattern); Matcher m = p.matcher(html); while (m.find()) { String url = m.group(1); String text = m.group(2); System.out.println("URL: " + url); System.out.println("Text: " + text); } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值