要想做爬虫,不可避免的要用到正则表达式,如果是简单的字符串处理,类似于split,substring等等就足够了,可是涉及到比较复杂的匹配,当然是正则的天下,不过正则好像好烦人的样子,那么如何做呢,熟记正则元字符和语法,找个在线匹配测试网站随时测试(其实在正则上我也是个菜逼。。。一直在慢(询)慢(问)测(大)试(牛)中得到正解),不过要相信,用熟了自然就巧了!
首先,推荐两篇博客,分别介绍了python自带的正则标准库re以及regex模块:Python正则表达式指南(re) Python的regex模块——更强大的正则表达式引擎。而我呢,最不擅长总结各种库各种语法之类的了,本篇博客就稍微简单介绍常用的以及爬虫程序开发过程中的小例子!先说说比较常用的6个re中的函数:
re.compile(pattern,flag)#根据正则匹配字符串以及附加条件,返回一个pattern对象
re.search(pattern,string)#搜索整个字符串,知道发现符合正则表达式的字符串
re.match(pattern,string)#从头开始检测字符串是否符合正则表达式,必须从字符串的第一个字符开始
re.sub(pattern,replacement,string)#将字符串中根据正则匹配到的字符串用replacement替换
re.split(pattern,string)#根据正则表达式分割字符串,将分割后的字符串放到list中返回
re.findall(pattern,string)#根据正则表达式分割字符串,将找到的所有结果放到list中返回
python中的匹配默认是贪婪的,所谓贪婪就是尝试尽可能的匹配更多的字符,比如:正则表达式"ab*"如果用于查找字符串"abbbc",将找到"abbb",如果是非贪婪的呢,得到的结果就是"a"。同样有时候我们时刻要注意转义字符等等,在net中我们有@,在python中我们有r,用法一样哦。让我们先来看一段代码:
1 >>> import re 2 >>> 3 >>> pattern = re.compile(r'hello',re.I) 4 >>> match = pattern.match('Hello World@!') 5 >>> if match: 6 ... print match.group() 7 ... 8 Hello 9 >>>
在上面的代码中,我们先生成了一个pattern对象,然后进行了匹配,其中re.compile函数中,我们的re.I就是附带条件:忽略大小写。其他模式可以自行搜索之,各种模式之间可以互相配合。其实我们可以放弃用re.compile函数而直接这么写:
1 >>> match = re.match('hello','hello world!') 2 >>> print match.group() 3 hello
这样做少了一行re.compile(pattern,flags)代码,但是也少了pattern的对象,各位如何使用之就仁者见仁智者见智吧。
python中还可以对正则匹配的返回结果进行进一步的控制,如:
1 >>> import re 2 >>> m = re.search("output_(d{4})","output_2016.txt") 3 >>> print m.group() 4 output_2016 5 >>> print m.group(1) 6 2016 7 >>> print m.groups() 8 ('2016',)
可以看到,我们的正则表达式output_(d{4}) 其中包含一个正则表达式(d{4}),像这样被括号圈起来的正则表达式的一部分,我们称之为群(group),我们可以用m.group(index)来查询,group(0)是整个正则表达式的搜索结果,group(1)是第一个群,以此类推。。。。也许这样看着并不方便,我们可以对群起名字:
>>> import re >>> m = re.search("(?P<year>d{4}).(?P<mon>d{2}).(?P<day>d{2})","output_2016.01.18.txt") >>> m.groups() ('2016', '01', '18') >>> m.groupdict() {'year': '2016', 'mon': '01', 'day': '18'} >>> m.group("year") '2016' >>> m.group("mon") '01' >>> m.group("day") '18'
让我们看个实例:有一个文件,文件名为output_2016.01.18.txt。请读取文件名中的日期时间信息,计算出当日是星期几,并将文件名修改为output_yyyy-mm-dd-w.txt,其中w为星期几。
1 import os,re,datetime 2 filename="output_1981.10.21.txt" 3 get_time=re.search("(?P<year>d{4}).(?P<month>d{2}).(?P<day>d{2}).",filename) 4 year=get_time.group("year") 5 month=get_time.group("month") 6 day=get_time.group("day") 7 date=datetime.date(int(year),int(month),int(day)) 8 wd=date.weekday()+1 9 os.rename(filename,"output_"+year+"-"+month+"-"+day+"-"+str(wd)+".txt")
好了,正则基础就介绍到这里了,接下来让我们试着进行一下爬虫中的正则表达式。讲个小例子:什么值得买的白菜价包邮信息。
什么值得买——白菜价
要爬取网页信息,除了我们要得到网页信息外最重要的就是把我们需要的信息提取出来,我们f12来看一下要提取的html代码:
我们看到我们想要得到的信息都在<h2 class="itemName">...</h2>之中。我们的正则表达式如下:
1 content = response.read().decode('utf-8') 2 pattern = re.compile('<h2 .*?itemName"><a.*?<span .*?black">(.*?)</span><span .*?red">(.*?)</span></a></h2>',re.S) 3 items = re.findall(pattern,content) 4 for item in items: 5 print item[0],item[1]
.*?是一个固定搭配,.和*可以匹配任意多个字符,加上?就是最小匹配,也就是我们上面说的非贪婪模式。直白的说就是匹配尽可能短的字符串。
(.*?)这个上面我们讲了,他是正则匹配时的一个群。re.S标志在正则匹配的时候为点任意匹配模式,即点可以代表任意字符比如换行符。这样我们就获得了每个商品的名称和价格。(整个爬虫源码在下一篇博客)