正则表达式匹配

正则表达式

正则表达式(Regular Expression,简称Regex或RE)又称为正规表示法或常规表示法,常常用来检索、替换那些符合某个模式的文本,它首先设定好了一些特殊的字及字符组合,通过组合的“规则字符串”来对表达式进行过滤,从而获取或匹配我们想要的特定内容。它具有灵活、逻辑性和功能性非常的强,能迅速地通过表达式从字符串中找到所需信息的优点。

re模块

Python通过 re 模块提供对正则表达式的支持,使用正则表达式之前需要导入该库。

import re

其基本步骤是先将正则表达式的字符串形式编译为Pattern实例,然后使用Pattern实例处理文本并获得一个匹配(Match)实例,再使用Match实例获得所需信息。常用的函数是 findall,原型如下:

findall(string[, pos[, endpos]]) | re.findall(pattern, string[, flags])

该函数表示搜索字符串string,以列表形式返回全部能匹配的子串。 其中参数re包括三个常见值:

  1. re.I(re.IGNORECASE):忽略大小写(括号内是完整写法)
  2. re.M(re.MULTILINE):允许多行模式
  3. re.S(re.DOTALL):支持点任意匹配模式

Pattern对象是一个编译好的正则表达式,通过Pattern提供的一系列方法可以对文本进行匹配查找。Pattern不能直接实例化,必须使用re.compile()进行构造。

complie方法

re正则表达式模块包括一些常用的操作函数,比如complie()函数。其原型如下

compile(pattern[,flags] )

该函数根据包含正则表达式的字符串创建模式对象,返回一个pattern对象。参数flags是匹配模式,可以使用按位或“|”表示同时生效,也可以在正则表达式字符串中指定。Pattern对象是不能直接实例化的,只能通过compile方法得到。

简单举个实例,使用正则表达式获取字符串中的数字内容,如下所示:

>>> import re
>>> string="A1.45,b5,6.45,8.82"
>>> regex = re.compile(r"\d+\.?\d*")
>>> print regex.findall(string)
['1.45', '5', '6.45', '8.82']
>>>

match方法

match方法是从字符串的 pos 下标处起开始匹配 pattern,如果pattern结束时已经匹配,则返回一个Match对象;如果匹配过程中pattern无法匹配,或者匹配未结束就已到达endpos,则返回None。该方法原型如下:

match(string[, pos[, endpos]]) | re.match(pattern, string[, flags])

参数string表示字符串;pos表示下标,pos和endpos的默认值分别为0和len(string);参数flags用于编译pattern时指定匹配模式。

search方法

search方法用于查找字符串中可以匹配成功的子串。从字符串的pos下标处起尝试匹配pattern,如果pattern结束时仍可匹配,则返回一个Match对象;若无法匹配,则将pos加1后重新尝试匹配;直到pos=endpos时仍无法匹配则返回None。 函数原型如下:

search(string[, pos[, endpos]]) | re.search(pattern, string[, flags])

参数string表示字符串;pos表示下标,pos和endpos的默认值分别为0和len(string));参数flags用于编译pattern时指定匹配模式。

group和groups方法

group([group1, …])方法用于获得一个或多个分组截获的字符串,当它指定多个参数时将以元组形式返回。groups([default])方法以元组形式返回全部分组截获的字符串,相当于调用group(1,2,…last)。default表示没有截获字符串的组以这个值替代,默认为None。

正则表达式抓取网络数据常见方法

HTML语言是采用标签对的形式来编写网站的,包括起始标签和结束标签,比如<head></head><tr></tr><script><script>等。下面讲解抓取标签对之间的文本内容。

抓取title标签间的内容

首先爬取网页的标题,采用的正则表达式为<title>(.*?)</title>,爬取百度标题代码如下:

# coding=utf-8  
import re  
import urllib  
url = "http://www.baidu.com/"  
content = urllib.urlopen(url).read()  
title = re.findall(r'<title>(.*?)</title>', content)
print title[0]
# 百度一下,你就知道

抓取超链接标签间的内容

在HTML中,<a href=URL></a>用于标识超链接,获取完整的超链接和超链接<a></a>之间的内容

# coding=utf-8  
import re  
import urllib  
url = "http://www.baidu.com/"  
content = urllib.urlopen(url).read()

#获取完整超链接
res = r"<a.*?href=.*?<\/a>"
urls = re.findall(res, content)
for u in urls:
    print unicode(u,'utf-8')

#获取超链接<a>和</a>之间内容
res = r'<a .*?>(.*?)</a>'  
texts = re.findall(res, content, re.S|re.M)  
for t in texts:
    print unicode(t,'utf-8')

输出结果部分内容如下所示,这里如果直接输出print u或print t可能会乱码,需要调用函数unicode(u,'utf-8')进行转码

#获取完整超链接
<a href="http://news.baidu.com" name="tj_trnews" class="mnav">新闻</a>
<a href="http://www.hao123.com" name="tj_trhao123" class="mnav">hao123</a>
<a href="http://map.baidu.com" name="tj_trmap" class="mnav">地图</a>
<a href="http://v.baidu.com" name="tj_trvideo" class="mnav">视频</a>
...
#获取超链接<a>和</a>之间内容
新闻
hao123
地图
视频
...

抓取tr\td标签间的内容

网页中常用的布局包括table布局或div布局,其中table表格布局中常见的标签包括tr、th和td,表格行为tr(table row),表格数据为td(table data),表格表头th(table heading)。那么如何抓取这些标签之间的内容呢?下面代码是获取它们之间内容。

假设存在HTML代码如下所示:

<html>
<head><title>表格</title></head>
<body>
    <table  border=1>
        <tr><th>学号</th><th>姓名</th></tr>
        <tr><td>1001</td><td>杨秀璋</td></tr>
        <tr><td>1002</td><td>严娜</td></tr>
    </table>
</body>
</html>

则爬取对应值的Python代码如下:

# coding=utf-8  
import re  
import urllib
content = urllib.urlopen("test.html").read() #打开本地文件

#获取<tr></tr>间内容
res = r'<tr>(.*?)</tr>'
texts = re.findall(res, content, re.S|re.M)
for m in texts:
    print m
"""
texts:
['<th>学号</th><th>姓名</th>',
 '<td>1001</td><td>杨秀璋</td>',
 '<td>1002</td><td>严娜</td>']
"""




#获取<th></th>间内容
for m in texts:
    res_th = r'<th>(.*?)</th>'
    m_th = re.findall(res_th, m, re.S|re.M)
    for t in m_th:
        print t

#直接获取<td></td>间内容
res = r'<td>(.*?)</td><td>(.*?)</td>'    
texts = re.findall(res, content, re.S|re.M)
"""
texts:
[('1001', '杨秀璋'), ('1002', '严娜')]
"""
for m in texts:
    print m[0],m[1]

输出结果如下,首先获取tr之间的内容,然后再在tr之间内容中获取<th></th>之间值,即“学号”、“姓名”,最后讲述直接获取两个<td>之间的内容方法。

>>> 
<th>学号</th><th>姓名</th>
<td>1001</td><td>杨秀璋</td>
<td>1002</td><td>严娜</td>

学号
姓名

1001 杨秀璋
1002 严娜
>>>

抓取标签中的参数

抓取超链接标签的URL

HTML超链接的基本格式为<a href=URL>链接内容</a>,现在需要获取其中的URL链接地址,方法如下:

# coding=utf-8  
import re

content = '''
<a href="http://news.baidu.com" name="tj_trnews" class="mnav">新闻</a>
<a href="http://www.hao123.com" name="tj_trhao123" class="mnav">hao123</a>
<a href="http://map.baidu.com" name="tj_trmap" class="mnav">地图</a>
<a href="http://v.baidu.com" name="tj_trvideo" class="mnav">视频</a>
'''

res = r"(?<=href=\").+?(?=\")|(?<=href=\').+?(?=\')"
urls = re.findall(res, content, re.I|re.S|re.M)
for url in urls:
    print url

输出内容如下:

>>> 
http://news.baidu.com
http://www.hao123.com
http://map.baidu.com
http://v.baidu.com
>>>

(?<=)

解释 如果表达式为“(?<=800-)”,意思是:字符串之前为“800-”才做匹配,假定为电话号码,同样,并不使用任何输入字符串

(?=)

解释 如果表达式为“(?=.com)”,意思是:一个字符串后面跟着“.com”才做匹配操作,并不使用任何目标字符串

抓取图片超链接标签的URL

HTML插入图片使用标签的基本格式为<img src=图片地址 />,则需要获取图片URL链接地址的方法如下:

content = '''<img alt="Python" src="http://www..csdn.net/eastmount.jpg" />'''
urls = re.findall('src="(.*?)"', content, re.I|re.S|re.M)
print urls
# ['http://www..csdn.net/eastmount.jpg']

其中图片对应的超链接为http://www..csdn.net/eastmount.jpg,这些资源通常存储在服务器端,最后一个“/”后面的字段即为资源的名称,该图片名称为“eastmount.jpg”。那么如何获取URL中最后一个参数呢?

获取URL中最后一个参数

通常在使用Python爬取图片过程中,会遇到图片对应的URL最后一个字段通常用于命名图片,如前面的“eastmount.jpg”,需要通过URL“/”后面的参数获取图片。

content = '''<img alt="Python" src="http://www..csdn.net/eastmount.jpg" />'''
urls = 'http://www..csdn.net/eastmount.jpg'
name = urls.split('/')[-1]  
print name
# eastmount.jpg

该段代码表示采用字符“/”分割字符串,并且获取最后一个获取的值,即为图片名称。

字符串处理及替换

在使用正则表达式爬取网页文本时,通常需要调用find() 函数找到指定的位置,再进行进一步爬取,比如获取class属性为“infobox”的表格table,再进行定位爬取。

start = content.find(r'<table class="infobox"')  #起点位置    
end = content.find(r'</table>')              #重点点位置
infobox = text[start:end]    
print infobox

同时爬取过程中可能会爬取到无关变量,此时需要对无关内容进行过滤,这里推荐使用replace函数和正则表达式进行处理。比如,爬取内容如下:

# coding=utf-8  
import re

content = '''
<tr><td>1001</td><td>杨秀璋<br /></td></tr>
<tr><td>1002</td><td>颜 娜</td></tr>
<tr><td>1003</td><td><B>Python</B></td></tr>
'''

res = r'<td>(.*?)</td><td>(.*?)</td>'    
texts = re.findall(res, content, re.S|re.M)
for m in texts:
    print m[0],m[1]

输出如下所示:

>>> 
1001 杨秀璋<br />
1002 颜 娜
1003 <B>Python</B>
>>>

此时需要过滤多余字符串,如换行<br />空格( )、加粗<B></B>。 过滤代码如下:

# coding=utf-8  
import re

content = '''
<tr><td>1001</td><td>杨秀璋<br /></td></tr>
<tr><td>1002</td><td>颜 娜</td></tr>
<tr><td>1003</td><td><B>Python</B></td></tr>
'''

res = r'<td>(.*?)</td><td>(.*?)</td>'    
texts = re.findall(res, content, re.S|re.M)
for m in texts:
    value0 = m[0].replace('<br />', '').replace(' ', '')
    value1 = m[1].replace('<br />', '').replace(' ', '')
    if '<B>' in  value1:
        m_value = re.findall(r'<B>(.*?)</B>', value1, re.S|re.M)
        print value0, m_value[0]
    else:
        print value0, value1

采用replace将字符串“<br />”或“' ”替换成空白,实现过滤,而加粗(<B></B>)需要使用正则表达式过滤,输出结果如下:

>>> 
1001 杨秀璋
1002 颜娜
1003 Python
>>>

参考

  1. [python爬虫] 正则表达式使用技巧及爬取个人博客实例
Update time: 2020-05-26

results matching ""

    No results matching ""