python爬蟲從入門到放棄(五)之 正則的基本使用


 什么是正則表達式

正則表達式是對字符串操作的一種邏輯公式,就是 事先定義好的一些特定字符、及這些特定字符的組合,組成一個“規則字符”,這個“規則字符” 來表達對字符的一種過濾邏輯。

正則並不是python獨有的,其他語言也都有正則
python中的正則,封裝了re模塊

python正則的詳細講解

常用的匹配模式

\w      匹配字母數字及下划線
\W      匹配f非字母數字下划線
\s      匹配任意空白字符,等價於[\t\n\r\f]
\S      匹配任意非空字符
\d      匹配任意數字
\D      匹配任意非數字
\A      匹配字符串開始
\Z      匹配字符串結束,如果存在換行,只匹配換行前的結束字符串
\z      匹配字符串結束
\G      匹配最后匹配完成的位置
\n      匹配一個換行符
\t      匹配一個制表符
^       匹配字符串的開頭
$       匹配字符串的末尾
.       匹配任意字符,除了換行符,re.DOTALL標記被指定時,則可以匹配包括換行符的任意字符
[....]  用來表示一組字符,單獨列出:[amk]匹配a,m或k
[^...]  不在[]中的字符:[^abc]匹配除了a,b,c之外的字符
*       匹配0個或多個的表達式
+       匹配1個或者多個的表達式
?       匹配0個或1個由前面的正則表達式定義的片段,非貪婪方式
{n}     精確匹配n前面的表示
{m,m}   匹配n到m次由前面的正則表達式定義片段,貪婪模式
a|b     匹配a或者b
()      匹配括號內的表達式,也表示一個組

re.match()

嘗試從字符串的起始位置匹配一個模式,如果不是起始位置匹配的話,match()就會返回None
語法格式:
re.match(pattern,string,flags=0)

最常規的匹配

import re

content= "hello 123 4567 World_This is a regex Demo"
result = re.match('^hello\s\d\d\d\s\d{4}\s\w{10}.*Demo$',content)
print(result)
print(result.group())
print(result.span())

結果如下:

result.group()獲取匹配的結果
result.span()獲去匹配字符串的長度范圍
泛匹配

其實相對來說上面的方式並不是非常方便,其實可以將上述的正則規則進行更改

import re

content= "hello 123 4567 World_This is a regex Demo"
result = re.match("^hello.*Demo$",content)
print(result)
print(result.group())
print(result.span())

這段代碼的結果和上面常規匹配的結果是一樣的,但是寫起來會方便很多

匹配目標

如果為了匹配字符串中具體的目標,則需要通過()括起來,例子如下:

import re
content= "hello 1234567 World_This is a regex Demo"
result = re.match('^hello\s(\d+)\sWorld.*Demo$',content)
print(result)
print(result.group())
print(result.group(1))
print(result.span())

結果如下:

這里需要說一下的是通過re.group()獲得結果后,如果正則表達式中有括號,則re.group(1)獲取的就是第一個括號中匹配的結果

貪婪匹配

先看下面代碼:

import re

content= "hello 1234567 World_This is a regex Demo"
result= re.match('^hello.*(\d+).*Demo',content)
print(result)
print(result.group(1))

這段代碼的結果是

從結果中可以看出只匹配到了7,並沒有匹配到1234567,出現這種情況的原因是前面的.* 給匹配掉了, .*在這里會盡可能的匹配多的內容,也就是我們所說的貪婪匹配,

如果我們想要匹配到1234567則需要將正則表達式改為:

result= re.match('^he.*?(\d+).*Demo',content)

這樣結果就可以匹配到1234567

匹配模式

很多時候匹配的內容是存在換行的問題的,這個時候的就需要用到匹配模式re.S來匹配換行的內容

import re


content = """hello 123456 world_this
my name is zhaofan
"""

result =re.match('^he.*?(\d+).*?zhaofan$',content,re.S)
print(result)
print(result.group())
print(result.group(1))

結果如下

轉義

當我們要匹配的內容中存在特殊字符的時候,就需要用到轉移符號\,例子如下:

import re

content= "price is $5.00"

result = re.match('price is \$5\.00',content)
print(result)
print(result.group())

對上面的一個小結:
盡量使用泛匹配,使用括號得到匹配目標,盡量使用非貪婪模式,有換行符就用re.S
強調re.match是從字符串的起始位置匹配一個模式

re.search

re.search掃描整個字符串返回第一個成功匹配的結果

 

import re

content = "extra things hello 123455 world_this is a Re Extra things"

result = re.search("hello.*?(\d+).*?Re",content)
print(result)
print(result.group())
print(result.group(1))

結果如下:

其實這個時候我們就不需要在寫^以及$,因為search是掃描整個字符串

 

注意:所以為了匹配方便,我們會更多的用search,不用match,match必須匹配頭部,所以很多時候不是特別方便

匹配演練

例子1:

 

import re

html = '''<div id="songs-list">
    <h2 class="title">經典老歌</h2>
    <p class="introduction">
        經典老歌列表
    </p>
    <ul id="list" class="list-group">
        <li data-view="2">一路上有你</li>
        <li data-view="7">
            <a href="/2.mp3" singer="任賢齊">滄海一聲笑</a>
        </li>
        <li data-view="4" class="active">
            <a href="/3.mp3" singer="齊秦">往事隨風</a>
        </li>
        <li data-view="6"><a href="/4.mp3" singer="beyond">光輝歲月</a></li>
        <li data-view="5"><a href="/5.mp3" singer="陳慧琳">記事本</a></li>
        <li data-view="5">
            <a href="/6.mp3" singer="鄧麗君">但願人長久</a>
        </li>
    </ul>
</div>'''

result = re.search('<li.*?active.*?singer="(.*?)">(.*?)</a>',html,re.S)
print(result)
print(result.groups())
print(result.group(1))
print(result.group(2))

結果為:

re.findall

搜索字符串,以列表的形式返回全部能匹配的子串

代碼例子如下:

import re

html = '''<div id="songs-list">
    <h2 class="title">經典老歌</h2>
    <p class="introduction">
        經典老歌列表
    </p>
    <ul id="list" class="list-group">
        <li data-view="2">一路上有你</li>
        <li data-view="7">
            <a href="/2.mp3" singer="任賢齊">滄海一聲笑</a>
        </li>
        <li data-view="4" class="active">
            <a href="/3.mp3" singer="齊秦">往事隨風</a>
        </li>
        <li data-view="6"><a href="/4.mp3" singer="beyond">光輝歲月</a></li>
        <li data-view="5"><a href="/5.mp3" singer="陳慧琳">記事本</a></li>
        <li data-view="5">
            <a href="/6.mp3" singer="鄧麗君">但願人長久</a>
        </li>
    </ul>
</div>'''

results = re.findall('<li.*?href="(.*?)".*?singer="(.*?)">(.*?)</a>', html, re.S)
print(results)
print(type(results))
for result in results:
    print(result)
    print(result[0], result[1], result[2])

結果如下:

例子2:

import re

html = '''<div id="songs-list">
    <h2 class="title">經典老歌</h2>
    <p class="introduction">
        經典老歌列表
    </p>
    <ul id="list" class="list-group">
        <li data-view="2">一路上有你</li>
        <li data-view="7">
            <a href="/2.mp3" singer="任賢齊">滄海一聲笑</a>
        </li>
        <li data-view="4" class="active">
            <a href="/3.mp3" singer="齊秦">往事隨風</a>
        </li>
        <li data-view="6"><a href="/4.mp3" singer="beyond">光輝歲月</a></li>
        <li data-view="5"><a href="/5.mp3" singer="陳慧琳">記事本</a></li>
        <li data-view="5">
            <a href="/6.mp3" singer="鄧麗君">但願人長久</a>
        </li>
    </ul>
</div>'''

results = re.findall('<li.*?>\s*?(<a.*?>)?(\w+)(</a>)?\s*?</li>',html,re.S)
print(results)
for result in results:
    print(result[1])

結果如下:

其實這里我們就可以看出

\s*? 這種用法其實就是為了解決有的有換行,有的沒有換行的問題

(<a.*?>)? 這種用法是因為html中有的有a標簽,有的沒有的,?表示匹配一個或0個,正好可以用於匹配

re.sub

替換字符串中每一個匹配的子串后返回替換后的字符串

re.sub(正則表達式,替換成的字符串,原字符串)

例子1

import re

content = "Extra things hello 123455 World_this is a regex Demo extra things"

content = re.sub('\d+','',content)
print(content)

結果會講數字替換為為空:

例子2,在有些情況下我們替換字符的時候,還想獲取我們匹配的字符串,然后在后面添加一些內容,可以通過下面方式實現:

import re

content = "Extra things hello 123455 World_this is a regex Demo extra things"

content = re.sub('(\d+)',r'\1 7890',content)
print(content)

結果如下:

 

這里需要注意的一個問題是\1是獲取第一個匹配的結果,為了防止轉義字符的問題,我們需要在前面加上r

re.compile

將正則表達式編譯成正則表達式對象,方便復用該正則表達式

 

import re
content= """hello 12345 world_this
123 fan
"""

pattern =re.compile("hello.*fan",re.S)

result = re.match(pattern,content)
print(result)
print(result.group())

正則的綜合練習

獲取豆瓣網書籍的頁面的書籍信息,通過正則實現

 

 

 

 

import requests
import re
content = requests.get('https://book.douban.com/').text
pattern = re.compile('<li.*?cover.*?href="(.*?)".*?title="(.*?)".*?more-meta.*?author">(.*?)</span>.*?year">(.*?)</span>.*?</li>', re.S)
results = re.findall(pattern, content)
print(results)

for result in results:
    url,name,author,date = result
    author = re.sub('\s','',author)
    date = re.sub('\s','',date)
    print(url,name,author,date)

結果如下:

 


免責聲明!

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



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