模塊一(re模塊)
一、re模塊
首先說一下什麽是模塊,模塊就是一組功能的集合。你要和某個東西打交道,而這個東西本身和python沒關系,這個東西本身就存在,所以python提供了一個功能的集合專門負責和這個東西打交道。
模塊的類型:
內置模塊:不需要我們自己安裝,解釋器自帶的;
第三方模塊:需要我們自己安裝的模塊;
自定義模塊:我們自己寫的模塊;
為什麽要有模塊?先舉一個例子:我們都知道是操作系統把所有硬件管理起來的,文件是在硬盤上存儲的,python想從硬盤上進行文件的操作和刪除時就需要引入os模塊,說白了,模塊實際上就是給我們提供功能,這個要操作的內容本身就存在,模塊只不過是python提供給我們去操作這個內容的方法。
註意:永遠不要起一個和你已知的模塊同名的py文件的名字!
今天我們就來學習一下re模塊的幾個基礎方法,在python中使用正則表達式就要引入re模塊。
1,查找
findall:表示匹配每一項都是列表中的一個元素。 (重要程度*****)
語法規則:re.findall(‘正則表達式’, 待匹配字符串 , flag),具體示例如下:
import re ret = re.findall(‘\d+‘, ‘sjkhk172按實際花費928‘) print(ret) # 結果為:[‘172‘, ‘928‘] ret= re.findall(‘\d‘, ‘sjkhk172按實際花費928‘) print(ret) # 結果為:[‘1‘, ‘7‘, ‘2‘, ‘9‘, ‘2‘, ‘8‘]
search:只匹配從左到右的第一個,得到的不是直接的結果,而是一個變量,通過這個變量的group方法來獲取結果,如果沒有匹配到,會返回None,使用group會報錯。(重要程度*****)
語法規則:re.search(‘正則表達式’, 待匹配字符串 , flag),具體示例如下:
ret = re.search(‘\d+‘, ‘sjkhk172按實際花費928‘) print(ret) # 結果為:<_sre.SRE_Match object; span=(5, 8), match=‘172‘> print(ret.group()) # 結果為:172 ret = re.search(‘\d‘,‘owghabDJLBNdgv‘) print(ret) # 結果為:None print(ret.group()) # 會報錯 # 因為search方法查找的時候,若待匹配的字符串中沒有能匹配到的結果時, # 用group會報錯,所以通常我們寫成下面這樣 ret = re.search(‘\d+‘,‘sjkhk172按實際花費928‘) if ret : # 內存地址,這是一個正則匹配的結果 print(ret.group()) # 通過ret.group()獲取真正的結果
match:從頭開始匹配,相當於search中的正則表達式加上一個^。(重要程度**)
語法規則:re.match(‘正則表達式’, 待匹配字符串 , flag),具體示例如下:
ret = re.match(‘\d+$‘,‘sjkhk172按實際花費928‘) print(ret) # 結果為:None ret = re.match(‘\d+‘,‘172sjkhk按實際花費928‘) print(ret) # 結果為:<_sre.SRE_Match object; span=(0, 3), match=‘172‘> print(ret.group()) # 結果為:172 ret = re.match(‘\d+$‘,‘172sjkhk按實際花費928‘) print(ret) # 結果為:None
2,字符串處理的擴展
切割:re.split(‘正則表達式’, 待匹配字符串),用正則表達式匹配出來的結果對待匹配字符串切割。如下:
s = ‘alex83taibai40egon25‘ ret = re.split(‘\d+‘,s) print(ret) # 結果為:[‘alex‘, ‘taibai‘, ‘egon‘, ‘‘]
替換:sub和subn
re.sub(‘正則表達式’, ‘新內容’, 待匹配字符串 , 替換次數)
re.subn(‘正則表達式’, ‘新內容’, 待匹配字符串 , 替換次數) ,示例如下:
ret = re.sub(‘\d+‘,‘H‘,‘alex83taibai40egon25‘) print(ret) # 結果為:alexHtaibaiHegonH ret = re.sub(‘\d+‘,‘H‘,‘alex83taibai40egon25‘,1) print(ret) # 結果為:alexHtaibai40egon25 ret = re.subn(‘\d+‘,‘H‘,‘alex83taibai40egon25‘) print(ret) # 結果為:(‘alexHtaibaiHegonH‘, 3) ret = re.subn(‘\d+‘,‘H‘,‘alex83taibai40egon25‘, 2) print(ret) # 結果為:(‘alexHtaibaiHegonH‘, 2) # 我們可以看出sub和subn的區別是subn返回一個元組,元組第二個元素是替換次數。
3,re模塊的進階:時間和空間上更優化
compile:節省使用正則表達式解決問題的時間(編譯,就是將正則表達式編譯成字節碼,這樣在多次使用的過程中不會多次編譯,可以用這個結果去直接search、match、findall、finditer),具體示例如下:
ret = re.compile(‘\d+‘) # 編譯 print(ret) # 結果為:re.compile(‘\\d+‘) res = ret.findall(‘alex83taibai40egon25‘) # 編譯後直接使用 print(res) res = ret.search(‘sjkhk172按實際花費928‘) # 編譯後直接使用 print(res.group())
finditer:節省使用正則表達式解決問題的空間/內存(返回一個叠代器,所有的結果都在這個叠代器中,可以通過循環和group取出來),具體示例如下:
ret = re.finditer(‘\d+‘,‘alex83taibai40egon25‘) print(ret) # 結果為:<callable_iterator object at 0x00000000029EFDA0> for i in ret: print(i.group()) # 結果為: # 83 # 40 # 25
二、在python中使用正則表達式的特點和問題
1,分組在re模塊中的使用,分析如下幾段代碼,理解並總結規則:
# 1 search方法中對正則分組,通過group(n)取出相應內容 s = ‘<a>wahaha</a>‘ ret = re.search(‘<(\w+)>(\w+)</(\w+)>‘,s) print(ret.group()) # 結果為:<a>wahaha</a>,默認取出所有匹配內容 print(ret.group(1)) # 數字參數代表的是取對應分組中的內容,結果為:a print(ret.group(2)) # 結果為:wahaha print(ret.group(3)) # 結果為:a # 2 findall也可以順利取到分組中的內容,因為它有一個特殊的語法,就是優先顯示分組中的內容 ret = re.findall(‘(\w+)‘,s) print(ret) # 結果為:[‘a‘, ‘wahaha‘, ‘a‘] ret = re.findall(‘>(\w+)<‘,s) print(ret) # 結果為:[‘wahaha‘] # 3 取消分組優先(?:正則表達式) ret = re.findall(‘>(?:\w+)<‘,s) print(ret) # 結果為:[‘>wahaha<‘] ret = re.findall(‘\d+(?:\.\d+)?‘,‘1.234*4‘) print(ret) # 結果為:[‘1.234‘, ‘4‘] # 當你想用()表示正則裏的分組,而不想表示優先顯示的時候可以用?:取消分組
綜上: 對於正則表達式來說,有些時候我們需要進行分組,來整體約束某一組字符出現的次數;對於python語言來說,分組可以幫助你更好更精準的找到你真正需要的內容;具體想表示哪種分組,要看情況決定。
# 4 split方法中可以對正則加括號表示使切割的字符不丟失 ret = re.split(‘\d+‘,‘alex83taibai40egon25‘) print(ret) # 結果為:[‘alex‘, ‘taibai‘, ‘egon‘, ‘‘] ret = re.split(‘(\d+)‘,‘alex83taibai40egon25‘) print(ret) # 結果為:[‘alex‘, ‘83‘, ‘taibai‘, ‘40‘, ‘egon‘, ‘25‘, ‘‘] # 分組命名 (?P<組名>正則表達式) s = ‘<a>wahaha</a>‘ ret = re.search(‘>(?P<con>\w+)<‘,s) print(ret.group(1)) # 結果為:wahaha print(ret.group(‘con‘)) # 結果為:wahaha # 使用前面的分組 要求使用這個名字的分組和前面同名分組中的內容匹配的必須一致 pattern = ‘<(?P<tab>\w+)>(\w+)</(?P=tab)>‘ ret = re.search(pattern,s) print(ret.group()) # 結果為:<a>wahaha</a> # 可以練習下列的匹配: # 2018-12-06 # 2018.12.6 # 2018 12 06 # 12:30:30
三、使用正則表達式的技巧
當你要匹配的內容太沒有特點,容易和你不想匹配的內容混在一起的時候,就可以把不想匹配的也取出來,然後通過python過濾掉,具體示例如下:
# 想只取整數,但是會帶上小數,那麽把整數和小數都取出來,然後再過濾掉小數 ret=re.findall(r"\d+\.\d+|\d+","1-2*(60+(-40.35/5)-(-4*3))") print(ret) # 結果為:[‘1‘, ‘2‘, ‘60‘, ‘40.35‘, ‘5‘, ‘4‘, ‘3‘] ret=re.findall(r"\d+\.\d+|(\d+)","1-2*(60+(-40.35/5)-(-4*3))") ret.remove(‘‘) print(ret) # 結果為:[‘1‘, ‘2‘, ‘60‘, ‘5‘, ‘4‘, ‘3‘]
四、爬蟲的例子
預備知識:如何獲取一個頁面的源代碼,如下可以做到:
from urllib import request ret = request.urlopen(‘https://movie.douban.com/top250? start=50&filter=‘) res = ret.read().decode(‘utf-8‘) print(res)
分析並掌握如下爬蟲的小例子:
import re from urllib.request import urlopen def getPage(url): # 獲取網頁的字符串 response = urlopen(url) return response.read().decode(‘utf-8‘) def parsePage(s): ret = com.finditer(s) # 從s這個網頁源碼中 找到所有符合com正則表達式規則的內容 並且以叠代器的形式返回 for i in ret: yield { "id": i.group("id"), "title": i.group("title"), "rating_num": i.group("rating_num"), "comment_num": i.group("comment_num"), } def main(num): # 0 25 50 # 這個函數執行10次,每次爬取一頁的內容 url = ‘https://movie.douban.com/top250?start=%s&filter=‘ % num response_html = getPage(url) # response_html就是這個url對應的html代碼 就是 str ret = parsePage(response_html) # ret是一個生成器 print(ret) f = open("move_info7", "a", encoding="utf8") for obj in ret: print(obj) data = str(obj) f.write(data + "\n") f.close() com = re.compile( ‘<div class="item">.*?<div class="pic">.*?<em .*?>(?P<id>\d+).*?<span class="title">(?P<title>.*?)</span>‘ ‘.*?<span class="rating_num" .*?>(?P<rating_num>.*?)</span>.*?<span>(?P<comment_num>.*?)評價</span>‘, re.S) count = 0 for i in range(10): main(count) count += 25
寫在最後:
正則表達式到底重要到什麽程度?
掌握作業中的所有內容
能夠看懂常用的正則表達式
並且能夠做出一些公司特異性要求的修改
模塊一(re模塊)