python re正則表達式實例


re模塊

Python中通過re模塊使用正則表達式,該模塊提供的幾個常用方法:

img

2.檢索與替換

img

3.編譯成Pattern對象

對於會多次用到的正則表達式,我們可以調用re的compile()方法編譯成

Pattern對象,調用的時候直接Pattern對象.xxx即可,從而提高運行效率。

附:flags(可選標志位)表

多個標志可通過按位OR(|)進行連接,比如:re.I|re.M

img

2.正則規則詳解

1.加在正則字符串前的'r'

為了告訴編譯器這個string是個raw string(原字符串),不要轉義反斜杠!

比如在raw string里\n是兩個字符,''和'n',不是換行!

python有趣嗎?好玩嗎?想學嗎?這里小編創建了一個python學習交流群:308754087 里面也會不定時分享關於Python的免費學習資料,歡迎想學習的小伙伴的加入,python有你更精彩!!嘿嘿!

2.字符

img

3.數量

img

4.邊界

img

5.分組

用()表示的就是要提取的分組,一般用於提取子串,

比如:^(\d)-(\d)$:從匹配的字符串中提取出區號和本地號碼

img

附:group()方法與其他方法詳解

不引入括號,增個表達式作為一個組,是group(0)

不引入()的話,代表整個表達式作為一個組,group = group(0)

如果引入()的話,會把表達式分為多個分組,比如下面的例子:

img

輸出結果:

img

img

貪婪與非貪婪

正則匹配默認是貪婪匹配,也就是匹配盡可能多的字符。

比如:ret = re.match(r'^(\d+)(0*)$','12345000').groups()ß

我們的原意是想得到('12345','000')這樣的結果,但是輸出

ret我們看到的卻是:

,由於貪婪,直接把后面的

0全給匹配了,結果0只能匹配空字符串了,如果想盡可能少的

匹配,可以在\d+后加上一個?問號采用非貪婪匹配,改成:

r'^(\d+?)(0)$',輸出結果就變成了:

3.正則練習

例子1:簡單驗證手機號碼格式

流程分析:

1.開頭可能是帶0(長途),86(天朝國際區號),17951(國際電話)中的一個或者一個也沒有:

2.接着1xx,有13x,14x,15x,17x,18x,然后這個x也是取值范圍也是不一樣的:

14x:579

17x:01678

然后修改下正則表達式,可以隨便輸個字符串驗證下:

3.最后就是剩下部分的8個數字了,很簡單:[0-9] 加上:

^(0|86|17951)?(13[0-9]|14[579]|15[0-35-9]|17[01678]|18[0-9])[0-9]$

例子2:驗證身份證

流程分析:

身份證號碼分為一代和二代,一代由15位號碼組成,而二代則是由18個號碼組成:

十五位:xxxxxx yy mm dd pp s

十八位:xxxxxx yyyy mm dd ppp s

為了方便了解,把這兩種情況分開,先是十八位的:

img

[1]\d(18|19|20)\d(0[1-9]|10|11|12)([012][1-9]|10|20|30|31)\d[0-9Xx]|[1-9]\d\d(0[1-9]|10|11|12)([012][1-9]|10|20|30|31)\d[0-9Xx]$

另外,這里的正則匹配出的身份證不一定是合法的,判斷身份是否

合法還需要通過程序進行校驗,校驗最后的校驗碼是否正確。

擴展閱讀:身份證的最后一位是怎么算出來的?

更多可見:第二代身份證號碼編排規則

首先有個加權因子的表:(沒弄懂怎么算出來的..)

[7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]

然后位和值想乘,結果相加,最后除11求余,比如我隨便網上找的

sum = 47 + 19 + 110 + 35 +88 + 1 4 ... + 6 * 2 = 282

sum % 11 = 7,所以這個是一個合法的身份證號。

例子3:驗證ip是否正確

流程分析:

所以我們把第一段和后面三段分開,然后分析下ip的結構,可能是這幾種情況:

一位數:[1-9]

兩位數:[1-9][0-9]

三位數(100-199):1[0-9][0-9]

三位數(200-249):2[0-4][0-9]

三位數(250-255): 25[0-5]

理清了第一段的正則怎么寫就一清二楚了:

img

^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(.([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]))$

img

4.正則實戰

實戰:抓一波城市編碼列表

本來想着就抓抓中國氣象局的天氣就好了,然后呢,比如深圳天氣的網頁是:

然后這個101280601是城市編碼,然后網上搜了下城市編碼列表,發現要么

很多是錯的,要么就缺失很多,或者鏈接失效,想想自己想辦法寫一個采集

的,先搞一份城市編碼的列表,不過我去哪里找數據來源呢?中國氣象局

肯定是會有的,只是應該不會直接全部暴露出來,想想能不能通過一些間接

操作來實現。對着中國氣象局的網站瞎點,結果不負有心人,我在這里:

img

發現了這個:

img

然后,我覺得這可能是入手點:

img

這里有個超鏈接,難不成是北京所有的地區的列表,點擊下進去看看:

img

卧槽,果然是北京所有的地區,然后每個地區的名字貌似都有一個超鏈接

F12看下指向哪里?

img

到這里就豁(huo)然開朗了,我們來捋一捋實現的流程:

1.先拿到第一層的城市列表鏈接用列表存起來

2.接着遍歷列表去訪問不同的城市列表鏈接,截取不同城市的城市名,城市編碼存起來

流程看上去很簡單,接着來實操一波。

先是拿城市列表url

img

接着隨便點開一個,比如beijing.shtml,頁面結構是這樣的:

想要的內容是這里的超鏈接:

img

F12看下頁面結構,層次有點多,不過沒關系,這樣更能夠鍛煉我們

img

入手點一般都是離我們想要數據最近地方下手,我看上了:conMidtab3

全局搜了一下,也就八個:

第一個直接就可以排除了:

img

img

是我們想要的內容,接着里面的tr是我們需要內容,找一波:

輸出下:

img

img

重復出現了一堆詳情,很明顯是我們不想要的,我們可以在循環的時候

執行一波判斷,重復的不加入到列表中:

img

城市的話還好,直接調用tag對象的string直接就能拿到,

而城市編碼的話,按照以前的套路,我們需要先['href']拿到

再做字符串裁剪,挺繁瑣的,既然本節學習了正則,為何不用

正則來一步到位,不難寫出這樣的正則:

img

卧槽,就是我們想要的結果,美滋滋,接着把之前拿到所有

的城市列表都跑一波,存字典里返回,最后賽到一個大字典

里,然后寫入到文件中,完成。

========= BUG的分割線 =========

最后把數據打印出來發現只有428條數據,后面才發現conMidtab3那里處理有些

問題,漏掉了一些,限於篇幅,就不重新解釋了,直接貼上修正完后的代碼把...

import urllib.request

from urllib import error

from bs4 import BeautifulSoup

import os.path

import re

import operator

# 通過中國氣象局抓取到所有的城市編碼

# 中國氣象網基地址

# 華北天氣預報url

weather_hb_url = "http://www.weather.com.cn/textFC/hb.shtml#"

# 獲得城市列表鏈接

def get_city_list_url():

city_list_url = []

weather_hb_html = weather_hb_resp.read().decode('utf-8')

weather_hb_soup = BeautifulSoup(weather_hb_html, 'html.parser')

weather_box = weather_hb_soup.find(attrs={'class': 'lqcontentBoxheader'})

weather_a_list = weather_box.findAll('a')

for i in weather_a_list:

city_list_url.append(weather_base_url + i['href'])

return city_list_url

# 根據傳入的城市列表url獲取對應城市編碼

def get_city_code(city_list_url):

city_code_dict = {} # 創建一個空字典

city_pattern = re.compile(r'^$') # 獲取城市編碼的正則

weather_hb_html = weather_hb_resp.read().decode('utf-8')

weather_hb_soup = BeautifulSoup(weather_hb_html, 'html.parser')

# 需要過濾一波無效的

div_conMidtab = weather_hb_soup.find_all(attrs={'class': 'conMidtab', 'style': ''})

for mid in div_conMidtab:

tab3 = mid.find_all(attrs={'class': 'conMidtab3'})

for tab in tab3:

trs = tab.findAll('tr')

for tr in trs:

a_list = tr.findAll('a')

for a in a_list:

if a.get_text() != "詳情":

# 正則拿到城市編碼

city_code = city_pattern.match(str(a)).group(1)

city_name = a.string

city_code_dict[city_code] = city_name

return city_code_dict

# 寫入文件中

def write_to_file(city_code_list):

try:

with open('city_code.txt', "w+") as f:

for city in city_code_list:

f.write(city[0] + ":" + city[1] + "\n")

except OSError as reason:

print(str(reason))

else:

print("文件寫入完畢!")

if name == 'main':

city_result = {} # 創建一個空字典,用來存所有的字典

city_list = get_city_list_url()

# get_city_code("http://www.weather.com.cn/textFC/guangdong.shtml")

for i in city_list:

print("開始查詢:" + i)

city_result.update(get_city_code(i))

# 根據編碼從升序排列一波

sort_list = sorted(city_result.items(), key=operator.itemgetter(0))

# 保存到文件中

write_to_file(sort_list)

img


  1. 1-9 ↩︎


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM