python爬蟲(二)----正則表示式
阿新 • • 發佈:2018-12-09
正則表示式
本部落格主要講正則表示式在爬蟲網頁解析中的作用
需要的是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)