1. 程式人生 > >python爬蟲(二)----正則表示式

python爬蟲(二)----正則表示式

正則表示式

本部落格主要講正則表示式在爬蟲網頁解析中的作用
需要的是python的re模組
python版本:3.x

(一) 正則表示式的基本知識

1 匹配字元

  • 常見匹配模式—匹配字元
模式 描述
. 匹配任意除\n(換行符)之外的字元
\ 轉義字元
[…] 用來表示一組字元,匹配[…]內的任意字元
^[…] 匹配除了[…]內任意字元
  • 預定義字元
模式 描述
\d 匹配數字[0-9]
\D 匹配非數字
\s 匹配空白符
\S 匹配非空白符
\w 匹配26個字母 [a-z] [A-Z]
\W 匹配非26字母
a | b 匹配a或b
  • 數量詞
模式 描述
* 匹配*號前的字元 [0–多次]
+ 匹配+號前的字元 [1–多次]
匹配?前的字元 [0-1次]
{m} 匹配{}號前的字元m次
{m,n} 匹配{}前的字元 [m-n次]
  • 邊界匹配
模式 描述
^ 匹配字串開頭:^abc匹配abc開頭字串
$ 匹配字串結尾:xyz$匹配以xyz結尾的字串
\A 匹配字串開始
\z 匹配字串結束
\Z 匹配字串結束,如果存在換行,只匹配到換行前的結束字串
\G 匹配最後匹配完成的位置
(…) 表示一個表示式,也表示一個組,常見的是:(.*?)
  • 案例如下:
import re
content = 'Hello 123 4567 World_This is a Regex Demo'
# \s:匹配空白符
# \d:匹配數字
# \d{4}:匹配4個數字
# \w{10}:匹配10個單個字元
#.:匹配任意字元
#*:匹配0-多個表示式
result =re.match('^Hello\s\d\d\d\s\d{4}\s\w{10}.*',content)
# 改進 result =re.match('^He.*?(\d+)\s\d{4}\s\w{10}.*',content)
#因為沒有組,所以為0
print(result.group(0))
#範圍 輸出結果是從0匹配到41
print(result.span())

'''
輸出結果:
(0, 41)
Hello 123 4567 World_This is a Regex Demo
'''

2 匹配函式

  • 函式和描述
函式 描述
re.match(pattern,content) 從content字串的起點開始匹配
re.search(pattern,content) 對content做任意位置匹配
re.findall(pattern,content) 從滿足位置開始找出所有滿足正則表示式的字串,返回的是列表
re.finditer(pattern,content) 從滿足位置開始找出所有滿足正則表示式的字串,返回的是迭代器
  • 程式碼對比
import re
content = '''wo men Hello 1234567 World_This is
a Regex Demo
'''
result = re.match('He.*?(\d+).*?Demo',content,re.S)
result1 = re.search('He.*?(\d+).*?Demo',content,re.S)
print(result)
print(result1)

'''
輸出:
None
<_sre.SRE_Match object; span=(7, 47), match='Hello 1234567 World_This is\na Regex Demo'>

'''

注意:當遇到有換行的時候要用 : re.S

3 貪婪和非貪婪匹配

  • 貪婪匹配:.*
#貪婪匹配
import re
content = 'Hello 1234567 World_This is a Regex Demo'
#.*:儘可能匹配多,而後面有個(\d+)中的+至少匹配一個,所以(\d+)匹配了7
result = re.match('^He.*(\d+).*Demo$',content)
#例如(\d*),由於*是匹配0-無限個,導致(\d*)沒匹配到
result1 = re.match('^He.*(\d*).*Demo$',content)
print(result.group(1))
'''
輸出:7
注意result1沒有匹配到
'''
  • 非貪婪匹配:.*?
#非貪婪匹配: .*? : 匹配儘可能少的
import re 
content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^He.*?(\d+).*Demo$',content) 
print(result.group(1))

'''
輸出:1234567
'''

類似優先順序:當時貪婪時優先順序大於後面的匹配符
當時非貪婪時,優先順序小於後面的匹配符

(二)豆瓣實戰

  • 網頁部分主要程式碼
    在這裡插入圖片描述

在這裡插入圖片描述
對HTML程式碼分析

<li class="">
            <div class="cover">
              <a href="https://book.douban.com/subject/30370935/?icn=index-editionrecommend" title="海膽">
                <img src="https://img3.doubanio.com/view/subject/m/public/s29918393.jpg" class="" width="115px" height="172px" alt="海膽">
              </a>
            </div>
                <div class="intervenor-info">
                    <img src="https://img3.doubanio.com/f/book/ef040178fab1770d60e3f2f12ba4c7aa70714396/pics/book/partner/jd_recommend.png" class="jd-icon" width="16" height="16"> 
                    <span>推薦</span>
                </div>
            <div class="info">
              <div class="title">
                <a class="" href="https://book.douban.com/subject/30370935/?icn=index-editionrecommend" title="海膽">海膽</a>
              </div>
              <div class="author">
                雷曉宇
              </div>
              <div class="more-meta">
                <h4 class="title">
                  海膽
                </h4>
                <p>
                  <span class="author">
                    雷曉宇
                  </span>
                  /
                  <span class="year">
                    2018-11
                  </span>
                  /
                  <span class="publisher">
                    浙江文藝出版社
                  </span>
                </p>
                <p class="abstract">
                  
                  《海膽》是一本人物特寫集,收錄了十篇文章,寫出了十個人的祕密。
附贈朴樹親筆信。
之所以取名“海膽”,是因為這十個人都和海膽一樣:有尖利的刺,也有柔軟的心。
除了刷爆朋友圈的《和李安一起午餐》——對李安而言,電影的祕密可以講,生活的祕密不可說。但他把生活祕密藏在電影裡,看懂了,才是真正理解他了——還有:
《Hello,朴樹先生》:用兩萬字告訴你,一個4...
                </p>
              </div>
            </div>
          </li>

在這裡插入圖片描述

寫正則表示式:#從標籤<li>開始,要注意標籤閉合以防匹配失敗
'<li.*?cover.*?href="(.*?)".?title="(.*?)".*?author">(.*?)</div>.*?year">(.*?)</span>'

  • 完整程式碼如下:
import requests
import re
content = requests.get('https://book.douban.com/').text
#print(content)
#別忘記標籤閉合 不唯一
pattern = re.compile('<li.*?cover.*?href="(.*?)".*?title="(.*?)".*?more-meta.*?author">(.*?)</span>.*?year">(.*?)</span>.*?</li>',re.S)
result = re.findall(pattern,content)
#print(result)
for res in result:
    url,name,author,date = result
    author = re.sub('\s',''author)
    date = re.sub('\s',''date)
    print(url,name,author,date)