Qingquan-Li / blog

My Blog
https://Qingquan-Li.github.io/blog/
132 stars 16 forks source link

Python正则表达式 #117

Open Qingquan-Li opened 5 years ago

Qingquan-Li commented 5 years ago

Python 正则表达式操作-文档:https://docs.python.org/zh-cn/3/library/re.html


正则表达式常用符号:

符号 含义 例子 匹配结果
* 匹配前面的字符、子表达式或括号里的字符 0 次或多次 a*b* aaaaaaaa,aaabbbbb,bbbbbb
+ 匹配前面的字符、子表达式或括号里的字符至少 1 次 a+b+ aaaaaaab,aaabbbbb,abbbbbb
[] 匹配任意一个字符(相当于“任选一个”) [A-Z]* APPLE,CAPITALS,QWERTY
() 表达式编组(在正则表达式的规则里编组会优先运行) (a*b)* aaabaab,abaaab,ababaaaaab
{m,n} 匹配前面的字符、子表达式或括号里的字符 m 到 n次(包含m或n) a{2,3}b{2,3} aabbb,aaabbb,aabb
[^] 匹配任意一个不在中括号里的字符 [^A-Z]* apple,lowercase,qwerty
| 匹配任意一个由竖线分割的字符、子表达式 b(a|i|e)d bad,bid,bed
. 匹配任意单个字符(包括符号、数字和空格等) b.d bad,bzd,b$d,b d
^ 指字符串开始位置的字符或子表达式 ^a apple,asdf,a
\ 转义字符(把有特殊含义的字符转换成字面形式) \.\|\\ .|\
$ 经常用在正则表达式的末尾,表示“从字符串的末端匹配”。如果不用它,每个正则表达式实际都带着“.*”模式,只会从字符串开头进行匹配。这 个符号可以看成是 ^ 符号的反义词 [A-Z]*[a-z]*$ ABCabc,zzzyx,Bob
?! “不包含”。这个奇怪的组合通常放在字符或正则表达式前面,表示字符不能出现在目标字符串里。 这个符号比较难用,字符通常会在字符串的不同部位出现。如果要在整个字符串中全部排除某个字符,就加上^和$符号 ^((?![A-Z]).)*$ no-caps-here,$ymb0ls
a4e f!ne


正则表达式并非处处正则!

正则表达式的标准版(此处的版本)是基于 Perl 语法演变而来的。绝大多数主流编程语言都使用与之相同或近似的版本。但是,在其他语言中使用这些正则表达式时需要当心,否则可能会出问 题。有些语言,比如 Java ,其正则表达式就和 Python 不太一样。总之,遇 到问题时看文档!




附:正则表达式和BeautifulSoup

在抓取网页的时候,BeautifulSoup 和正则表达式总是配合使用的。其实,大多数支持字符串参数的函数(比如, find(id="aTagIdHere") )都可以用正则表达式实现。

实例:

抓取的网页是 http://www.pythonscraping.com/pages/page3.html 。注意观察网页上有几个商品图片——它们的源代码形式如下:

<img src="../img/gifts/img3.jpg">

如果我们想抓取所有图片的 URL 链接,非常直接的做法就是用 find_all("img") 抓取所有图片,对吗?但是,有个问题。除了那些明显“多余的”图片(比如,LOGO)之外,新式的网站里都有一些隐藏图片,用于网页布局留白和元素对齐的空白图片,以及一些不容易察觉到的图片标签。总之,你不能仅用商品图片来统计网页上所有的图片。

而且网页的布局也可能会变化,或者,因为某些原因,我们不想通过图片在网页中的位置来查找标签。那么当你想抓取随机分布在网站里的某个元素或数据时,就会出现问题。例如,一些网页的最上面可能有一张商品图片,但是在另一些网页上没有。

解决这类问题的办法,就是直接定位那些标签来查找信息。在本例中,我们直接通过商品图片的文件路径来查找:

from urllib.request import urlopen 
import re 

from bs4 import BeautifulSoup 

html = urlopen("http://www.pythonscraping.com/pages/page3.html")
bsObj = BeautifulSoup(html, 'html.parser')
images = bsObj.find_all("img", {"src":re.compile("\.\.\/img\/gifts/img.*\.jpg")}) 
for image in images: 
    print(image["src"])

这段代码会打印出图片的相对路径,都是以 ../img/gifts/img 开头,以 .jpg 结尾,其结果如下所示:

../img/gifts/img1.jpg
../img/gifts/img2.jpg
../img/gifts/img3.jpg
../img/gifts/img4.jpg
../img/gifts/img6.jpg

正则表达式可以作为 BeautifulSoup 语句的任意一个参数,让你的目标元素查找工作极具灵活性。


获取属性

前面已经介绍过如何获取和过滤标签,以及获取标签里的内容。

但是,在网络数据采集时你经常不需要查找标签的内容,而是需要查找标签属性。比如标签 <a> 指向的 URL 链接包含在 href 属性中,或者 <img> 标签的图片文件包含在 src 属性中,这时获取标签属性就变得非常有用了。

对于一个标签对象,可以用下面的代码获取它的全部属性:

myTag.attrs 

要注意这行代码返回的是一个 Python 字典对象,可以获取和操作这些属性。比如要获取图片的资源位置 src ,可以用下面这行代码:

myImgTag.attrs["src"]




附:Lambda表达式

Lambda 表达式本质上就是一个函数,可以作为其他函数的变量使用;也就是说,一个函数不是定义成 f(x, y) ,而是定义成 f(g(x), y) ,或 f(g(x), h(x)) 的形式。 BeautifulSoup 允许我们把特定函数类型当作 find_all() 函数的参数。唯一的限制条件是这些函数必须把一个标签作为参数且返回结果是布尔类型。BeautifulSoup 用这个函数来评估它遇到的每个标签对象,最后把评估结果为“真”的标签保留,把其他标签剔除。

例如,下面的代码就是获取有两个属性的标签:

soup.find_all(lambda tag: len(tag.attrs) == 2)

这行代码会在 http://www.pythonscraping.com/pages/page3.html 找出下面的标签:

<div class="body" id="content"></div>
<span style="color:red" class="title"></span>

如果你愿意多写一点儿代码,那么在 BeautifulSoup 里用 Lambda 表达式选择标签,将是正则表达式的完美替代方案。


以上参考或摘自:《Web Scraping with Python》



再说Lambda表达式

lambda 表达式(有时称为 lambda 构型)被用于创建匿名函数。 表达式 lambda parameters: expression 会产生一个函数对象 。 该未命名对象的行为类似于用以下方式定义的函数:

def <lambda>(parameters):
    return expression

Lambda 只是简单函数定义的一种简化写法;在 def 语句中定义的函数也可以像用 lambda 表达式定义的函数一样被传递或赋值给其他名称。 def 形式实际上更为强大,因为它允许执行多条语句和使用标注。

更多参考:https://www.w3schools.com/python/python_lambda.asp