猫眼电影top100正则表达式编写详解

猫眼电影top100正则表达式编写详解

精选文章moguli202025-07-09 17:35:171A+A-

正则表达式是处理字符串的强大工具,它有自己特定的语法结构,有了它,实现字符串的检索、替换、匹配验证都不在话下。

当然,对于爬虫来说,有了它,从 HTML 里提取想要的信息就非常方便了。

在这里我们着重讲解一下通用匹配 .*

复杂的例子:

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)

可以看到,group 方法输出了匹配的全部字符串,也就是说我们写的正则表达式匹配到了目标字符串的全部内容;span 方法输出 (0, 41),这是整个字符串的长度。

因此,我们可以使用 .* 简化正则表达式的书写。

贪婪与非贪婪

使用上面的通用匹配 .* 时,可能有时候匹配到的并不是我们想要的结果。看下面的例子:

import re

content = 'Hello 1234567 World_This is a Regex Demo'

result = re.match('^He.*(\d+).*Demo

, content)print(result)print(result.group(1))

这里我们依然想获取中间的数字,所以中间依然写的是 (\d+)。而数字两侧由于内容比较杂乱,所以想省略来写,都写成 .。最后,组成 ^He.(\d+).*Demo$,看样子并没有什么问题。我们看下运行结果:

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

奇怪的事情发生了,我们只得到了 7 这个数字,这是怎么回事呢?

这里就涉及一个贪婪匹配与非贪婪匹配的问题了。在贪婪匹配下,.* 会匹配尽可能多的字符。正则表达式中.* 后面是 \d+,也就是至少一个数字,并没有指定具体多少个数字,因此,.* 就尽可能匹配多的字符,这里就把 123456 匹配了,给 \d + 留下一个可满足条件的数字 7,最后得到的内容就只有数字 7 了。

但这很明显会给我们带来很大的不便。有时候,匹配结果会莫名其妙少了一部分内容。其实,这里只需要使用非贪婪匹配就好了。非贪婪匹配的写法是 .*?,多了一个 ?,那么它可以达到怎样的效果?我们再用实例看一下:

import re

content = 'Hello 1234567 World_This is a Regex Demo'

result = re.match('^He.*?(\d+).*Demo

, content)print(result)print(result.group(1))

这里我们只是将第一个 .* 改成了 .*?,转变为非贪婪匹配。结果如下:

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

此时就可以成功获取 1234567 了。原因可想而知,贪婪匹配是尽可能匹配多的字符,非贪婪匹配就是尽可能匹配少的字符。当 .? 匹配到 Hello 后面的空白字符时,再往后的字符就是数字了,而 \d + 恰好可以匹配,那么这里 .? 就不再进行匹配,交给 \d+ 去匹配后面的数字。所以这样 .*? 匹配了尽可能少的字符,\d+ 的结果就是 1234567 了。

所以说,在做匹配的时候,字符串中间尽量使用非贪婪匹配,也就是用 .? 来代替 .,以免出现匹配结果缺失的情况。

但这里需要注意,如果匹配的结果在字符串结尾,.*? 就有可能匹配不到任何内容了,因为它会匹配尽可能少的字符。例如:

import re

content = 'http://weibo.com/comment/kEraCN'

result1 = re.match('http.*?comment/(.*?)', content)

result2 = re.match('http.*?comment/(.*)', content)print('result1', result1.group(1))print('result2', result2.group(1))

运行结果如下:

result1

result2 kEraCN

可以观察到,.? 没有匹配到任何结果,而 . 则尽量匹配多的内容,成功得到了匹配结果

\

其中 (点)可以匹配任意字符(换行符除外),*代表匹配前面的字符无数次,他们组合在一起就可以匹配任意字符了

这里我们直接以猫眼榜单100为实例

使用谷歌浏览器打开页面,右键检查

网址:

我们肯定是要爬取里面文章的信息,把鼠标挪动看看在哪里文章变蓝了,文章的内容就在那里

再一一点开

发现我们要爬取的都在

标签里,我们随便点开一个

我们想要提取的信息按照顺序有:排名信息,电影图片,电影名字,主演,上映时间

我们也按照顺序来构造正则表达式

1.首先是排名信息,首标签是

,中间的部分用.*?略过,我们可以知道排名信息"1"在clas标签里,于是给他个定位bord-index,中间的用.*?略过,"1"前面有个指向性的唯一符号">",我们加上,需要爬取的内容用(.*?)括起来,最后附上尾标签

这样我们的第一部分正则表达式就出来了:

.*?board-index.*?>(.*?)

需要提取电影的图片。可以看到,后面有 a 节点,其内部有两个 img 节点。经过检查后发现,第二个 img 节点的 data-src 属性是图片的链接。这里提取第二个 img 节点的 data-src 属性,正则表达式可以改写如下:

.*?board-index.*?>(.*?).*?data-src="(.*?)"

3.

需要提取电影的名称,它在后面的 p 节点内,class 为 name。所以,可以用 name 做一个标志位,然后进一步提取到其内 a 节点的正文内容,此时正则表达式改写如下:

.*?board-index.*?>(.*?).*?data-src="(.*?)".*?name.*?a.*?>(.*?)

再提取主演、发布时间、评分等内容时,都是同样的原理。最后,正则表达式写为:

.*?board-index.*?>(.*?).*?data-src="(.*?)".*?name.*?a.*?>(.*?).*?star.*?>(.*?)

.*?releasetime.*?>(.*?)

.*?integer.*?>(.*?).*?fraction.*?>(.*?).*?

点击这里复制本文地址 以上内容由莫古技术网整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!
qrcode

莫古技术网 © All Rights Reserved.  滇ICP备2024046894号-2