数据分析——Python网络爬虫(四){正则表达式}

avatar
作者
猴君
阅读量:0

爬虫库的使用

爬虫的步骤

获取网页源代码-urllib或者request等 信息提取--正则表达式或者bs或者lmxl等 保存本地数据库

正则表达式

  正则表达式,简称为regex,是文本模式的描述方法,用于描述一组字符串特征的模式,用来匹配特定的字符串。通过特殊字符+普通字符来进行模式描述,从而达到文本匹配目的工具。

	我们举一个例子,比如说我们要判断电话号码,我们可以编写出这样的一个函数代码 
def isPhoneNumber(text):     if len(text) != 12:         return False     for i in range(0, 3):         if not text[i].isdecimal():             return False     if text[3] != '-':             return False     for i in range(4, 7):         if not text[i].isdecimal():                 return False     if text[7] != '-':                 return False     for i in range(8, 12):         if not text[i].isdecimal():             return False     return True isPhoneNumber('425-434-3434') #刚好匹配正确 isPhoneNumber('4325-434-3434') #匹配不正确 
	那么我们继续从一长串字符中查找电话号码 
message = 'Call me at 415-555-1011 tomorrow. 415-555-9999 is my office.' for i in range(len(message)):     chunk = message[i:i+12]     if isPhoneNumber(chunk):         print('Phone number found: ' + chunk) print('Done') 
	通过运行代码,我们可以得到结果: 	Phone number found: 415-555-1011 	Phone number found: 415-555-9999 	Done 

  我们通过代码逻辑,可以发现到的是,这样的函数代码去匹配电话号码,其实效率很低,我们需要从一长串字符中,12个字符为一组,然后对字符串进行切片,然后直到12个字符完全符合isPhoneNumber()函数。

	那么如果我们采用正则表达式呢? 
import re phoneNumRegex = re.compile('\d\d\d-\d\d\d-\d\d\d\d') mo = phoneNumRegex.search('My number is 441-545-4242.') #返回首次出现 mo.group()#通过group返回匹配结果 
	运行结果:'441-545-4242' 	※	\d是一个正则表达式中的特殊字符,表示一位数字字符,即任何一位0到9的数字 

  那么其实我们很明显的看到的就是 正则表达式在匹配文本时,要比去敲写一段代码,效率更高了。
  我们来根据上述代码来分析一下正则表达式的流程。

正则表达式的流程

  1. 首先,Python中所有正则表达式的函数都在re模块

  2. 然后会向re.compile()传入一个字符串值,表示正则表达式,它将返回一个regex模式对象
    在这里插入图片描述

    那么正则表达式是如何匹配regex对象的呢? 
    1. regex对象的search()方法查找传入的字符串,寻找该正则表达式的 所有匹配
    2. 如果字符串中没有找到该正则表达式模式,search()方法将None。如果找到了该模式,search()方法将返回一个match对
    3. search对象有一个group()方法,它返回被查找字符串中实际匹配的文本,如果没有实际匹配的文本,就会报错,所以一般来说,代码会这么写。
phoneNumRegex = re.compile('\d\d\d-\d\d\d-\d\d\d\d')#raw mo = phoneNumRegex.search('My number is 34-555-4242.')#首次出现 if mo:     print(mo.group())#通过group返回匹配结果 

正则表达式的使用

  这里将介绍正则表达式中不同的匹配的方式

括号的使用

   利用括号进行分组

   比如将区号从电话号码中分离,添加括号将在正则表达式中创建“分组” —— (\d\d\d)-(\d\d\d-\d\d\d\d)
   然后可以使用group()匹配对象方法,从一个分组中获取匹配的文本
   第一对括号是第1组。第二对括号是第2组。向group()传入整数1或2,可以取得匹配文本的不同部分。向group()方法传入0或不传入参数,将返回整个匹配的文本。

import re phoneNumRegex = re.compile('(\d\d\d)-(\d\d\d-\d\d\d\d)') mo = phoneNumRegex.search('My number is 341-555-4242.') mo.group(0)# 返回所有的匹配结果 mo.group(1)# 返回第一个括号的匹配结果 mo.groups()# 返回元组 
返回结果:'341-555-4242'          '341'          ('341', '555-4242') 

管道匹配

   利用管道进行分组

   字符|称为“管道”。希望匹配许多表达式中的一个时,就可以使用它 。 例 如 , 正则表达式 ‘Batman|Spiderman’ 将匹配 ‘Batman’ ‘Spiderman’
   如果Batman和Spiderman都出现在被查找的字符串中,第一次出现的匹配文本,将作为match对象返回

mport re heroRegex = re.compile ('Batman|Spiderman') mo1 = heroRegex.search('Batman Spiderman Batman') mo1.group()#第一次出现的匹配文本 
	运行结果:'Batman' 
batRegex = re.compile('Bat(man|mobile|copter|bat)') #可以匹配'Batman'、'Batmobile'、'Batcopter'和'Batbat'中任意一个。因为所有这些字符串都以Bat开始 mo = batRegex.search('Batmobile lost a wheel') mo.group() 
	运行结果:'Batmobile' 

问号匹配

  用问号实现可选匹配

  不论这段文本在不在,正则表达式都会认为匹配。字符?表明它前面的分组在这个模式中是可选

import re batRegex = re.compile('Bat(wo)?man') # 既可以匹配Batman ,也可以匹配Batwomen mo1 = batRegex.search('The Adventures of Batman') mo1.group() 
	运行结果:'Batwoman' 
phoneRegex = re.compile('(\d\d\d-)?\d\d\d-\d\d\d\d') #包含或者不包含区号 mo1 = phoneRegex.search('My number is 415-555-4242') print(mo1.group()) mo2 = phoneRegex.search('My number is 555-4242') print(mo2.group()) 
运行结果:415-555-4242  		 555-4242 

星号匹配

  用星号匹配零次或多次

   *(称为星号)意味着“匹配零次或多次”,即星号之前的分组,可以在文本中出现任意次。它可以完全不存在,或一次又一次地重复

import re batRegex = re.compile('Bat(wo)*man') mo1 = batRegex.search('The Adventures of Batwowoman') mo2 = batRegex.search('The Adventures of Batman') mo1.group() mo2.group() 
	运行结果:'Batwowoman' 	         'Batman' 

加号匹配

  用加号匹配一次或多次

  +(加号)则意味着“匹配一次或多次”。星号不要求分组出现在匹 配的字符串中,但加号不同,加号前面的分组必须“至少出现一次”

import re batRegex = re.compile('Bat(wo)+man') mo1 = batRegex.search('The Adventures of Batwowoman') mo1.group() 
	运行结果:'Batwowoman' 

花括号匹配

   花括号匹配特定次数

   如果想要一个分组重复特定次数,就在正则表达式中该分组的后面,跟上花括号包围的数字。例如,正则表达式(Ha){3}将匹配字符串’HaHaHa’,但不会匹配’HaHa’
   可以指定一个范围,即在花括号中写下一个最小值、一个逗号和一个最大值 。 例 如 , 正则表达式 (Ha){3,5} 将匹配 ‘HaHaHa’ 、‘HaHaHaHa’和’HaHaHaHaHa’ 即可以匹配Ha3次到5次。

#花括号匹配特定次数 haRegex = re.compile('(ha){3}') mo1 = haRegex.search('hahahahha') mo1.group() 
 	运行结果:'hahaha' 

   正则表达式默认是贪婪的,尽可能匹配最长的字符串
   非贪婪:加问号,尽可能匹配最短的字符

#匹配特定次数,指定范围 haRegex = re.compile('(ha){2,4}')#贪婪匹配。 mo1 = haRegex.search('hahahaha') mo1.group() 
	运行结果:'hahahaha' 
#匹配特定次数, haRegex = re.compile('(ha){2,4}?')#非贪婪匹配 mo1 = haRegex.search('hahahahha') mo1.group() 
	运行结果:'haha' 

用点-星匹配所有字符

   .:匹配任意字符,除非换行
   *:匹配零个或者多个表达式

#点匹配任意一个字符 haRegex = re.compile('<.>') mo2 = haRegex.search('fdf<4>kkkfk') mo2.group() 
	运行结果:'<4>' 
#点星匹配任意字符 haRegex = re.compile('<.*>') mo2 = haRegex.search('fdf<4fd809475049758094gg>kkkfk') mo2.group() 
	运行结果:'<4fd809475049758094gg>' 
#点星匹配任意字符 haRegex = re.compile('<.*?>')#非贪婪模式,用得最多 mo2 = haRegex.search('fdf<hahaha>haha>kkkfk') mo2.group() 
	运行结果:'<hahaha>' 

跨行匹配

   re.DOTALL匹配跨行

haRegex = re.compile('<.*>',re.DOTALL) text='''weret<ttt fdfd>fdf''' mo2 = haRegex.search(text) mo2.group() 
	运行结果:'<ttt\nfdfd>' 

findall方法

   匹配表达式的所有内容(包括首次出现)

#findall import re kk = re.compile('\d+') kk.findall('one1two2three34four4444') #匹配所有数字,加表示一个或者多个 
	运行结果:['1', '2', '34', '4444'] 

   关于findall方法,还可以写第二种方法

import re patt='[1-5][0-9]' lis=[10,20,30,40,2,3,59,60,'aa','3aaa'] match=re.findall(patt,str(lis)) 
	运行结果:['10', '20', '30', '40','59','60'] 

其他常用字符匹配

在这里插入图片描述

注意:^表示的是匹配字符串的开头;[ ^ 字符串 ]表示匹配方括号内字符串以外的字符串。

例子

#例子一 #匹配哪些字符 import re words=['gold',' Google','Sogu','Guess'] patt=re.compile('.*g[^u]')   for w in words:    m=patt.findall(w)    if m: #条件判断中,只要不为0,不为none,不为空的值均和Ture等价       print(w) 
	运行结果:gold 			 Google 
#例子二 #把字符中,10至59取出来 lis=[10,20,30,40,2,3,59,60,'aa','3aaa'] import re patt='[1-5][0-9]' # 正则表达式 lis=[10,20,30,40,2,3,59,60,'aa','3aaa'] match=re.findall(patt,str(lis)) # 转换成字符串 if match:   print(match) 
	运行结果:['10', '20', '30', '40', '59'] 
#例子三 #匹配电话号码和邮箱 import re import pyperclip #为电话创建一个正则表达式 phoneRegex = re.compile('\d{8,11}')#8位 #为E-mail 地址创建一个正则表达式 emailRegex = re.compile('''( [a-zA-Z0-9_%+-]+ # username @  # @symbol [a-zA-Z0-9-]+ # domain name \. [a-zA-Z]{2,4}  #dot-something )''', re.VERBOSE) 				#管理复杂文本模式,忽略空白符和注释  # Find matches in clipboard text. text = str(pyperclip.paste())		#从粘贴板过来的字符串 matches = [] for groups in phoneRegex.findall(text):     matches.append(groups)    for groups in emailRegex.findall(text):     matches.append(groups) # Copy results to the clipboard. if len(matches) > 0:     print('Copied to clipboard:')     print('\n'.join(matches)) else:     print('No phone numbers or email addresses found.') 

注:
  因为Text文本过长,所以我不粘贴到这里,其实text文本不重要,大家自己找一个text文本就可以运行。代码里同学们可能陌生的是pyperclip模块和matchs.append(groups)
  下面这是链接解释
    pyperclip模块
    append的使用

正则表达式在线测试

  在线测试

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!