python(4): regular expression正則表達式/re庫/爬蟲基礎

python 獲取網絡數據也很方便html

抓取python

requests 第三方庫適合作中小型網絡爬蟲的開發, 大型的爬蟲須要用到 scrapy 框架正則表達式

解析express

BeautifulSoup 庫, re 模塊json

(一) requests 庫網絡

基本方法: requests.get() : 請求獲取指定URL位置的資源, 對應http 協議的get方法框架

注意: 在抓取網頁前要看一看這個網站是否是有爬蟲協議, scrapy

如何看網站的爬蟲協議? 有的網站會提供robots.txt函數

例如豆瓣的 www.douban.com/robots.txt學習

實例: 抓取豆瓣上小王子的一個書評

咱們要抓取subject 目錄, 從上述協議中看到它沒有被禁止

抓取多個頁面要注意他的延時, 這裏是5s

import requests
r=requests.get('http://book.douban.com/subject/1084336/comments/')
print(r.status_code)  # 200 則說明一切正常
print(r.text) # 獲取頁面內容

除了上述r.text 解碼, 還有r.content, r.json 等

上述抓取的數據有不少如下結構

<p class="comment-content">
<span class="short">痛苦迷茫不是由於成爲了「好笑」的大人,而是成爲大人卻沒有真正長大。因此回過頭來想要從懷念童年中解脫緩解痛苦那是本末倒置的作法。若是你做爲一個成年人以爲痛苦,緣由不是由於你「成年」了,也不是由於是生而爲「人」,而是「你」中止了思考中止了學習</p>

能夠用beautifulsoup進行解析,  舉例來看

from bs4 import BeautifulSoup
markup='<p class="title"><b>The Little Prince</b></p>'
soup=BeautifulSoup(markup,'lxml') # 對於html使用lxml解析器較好
# soup 的對象有四種: tag , navigablestring, beautifulsoup, comment
#tag就是標籤, 相似</b>**</b> 對文字內容的修飾
#navigablestring就是tag 中的字符串, 好比這裏的The Little Prince
#comment 是navigablestring的子類
print(soup.b) # 標籤b的內容: <b>The Little Prince</b>
print(type(soup.b))  # <class 'bs4.element.Tag'>
# tag 也有兩個屬性 name ,attrs
tag=soup.p
print(tag.name) # p
print(tag.attrs) # {'class': ['title']}
print(tag.string) #  取到了tag中包含的非屬性的字符串:The Little Prince
print(type(tag.string)) # <class 'bs4.element.NavigableString'>

soup.find_all('b')  # 找到全部b標籤的內容
Out[24]: [<b>The Little Prince</b>]

小王子的解析

import requests
from bs4 import BeautifulSoup
r=requests.get('http://book.douban.com/subject/1084336/comments/')
soup=BeautifulSoup(r.text,'lxml') # 得到beautifulsoup 對象soup
pattern=soup.find_all('p','comment-content')
#評論的屬性是標籤p,屬性是comment-content, 返回列表
for item in pattern: print(item.string)

沒有結果, 全是none!!  爲啥??

(二)regular expression

正則表達式能夠簡化字符串, 'py','pyy','pyyy','pyyy....' 這些均可以用 正則表達式py+ 表示

經常使用表達式:

 補充: \D 表示非數字字符  {m,} 至少擴展m次,  {:m}擴展0-m次

\b  :匹配一個單詞邊界,也就是指單詞和空格間的位置(即正則表達式的「匹配」有兩種概念,一種是匹配字符,一種是匹配位置,這裏的\b就是匹配位置的)。例如,「er\b」能夠匹配「never」中的「er」,但不能匹配「verb」中的「er」。

\B :匹配非單詞邊界。「er\B」能匹配「verb」中的「er」,但不能匹配「never」中的「er」。

舉例:

p(y|yt|yth|ytho)?n 表示: ?表示擴展0次或者1次, 表示爲pn,pyn,pytn,pythn,python

python+ 表示: python ,pythonn,pythonnn,....

py[th]on  表示:pyton ,pyhon

py[^th]?on 表示:pyon,pyaon,pybon,....,其中排除 t h的字母進行0次或1次擴展

py{:3}on 表示pon  pyon pyyon pyyyon (擴展y 0 1 2 3次)

^[A-Za-z]+$ 匹配字符串開頭和結尾 ,表示 由26個字母組成的字符串

^[A-Za-z0-9]+$ 匹配字符串開頭和結尾, 表示 由26個字母和10個數字組成的字符串

^-?\d+$ 整數形式的字符串(多是負數)

^[0-9]*[1-9][0-9]*$ 正整數形式的字符串

[1-9]\d{5} 中國境內郵政編碼(6位數)

 [\u4e00-\u9fa5]  匹配中文字符

\d{3}-\d{8}   或者 \d{4}-\d{7} 表示國內電話號碼: 010-62914227

 

舉例: 匹配IP地址的正則表達式:

一個IP地址分爲 四段,每段是0-255

\d+.\d+.\d+.\d+  這個沒有限制位數 :+能夠擴展1次或者無限次

\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}  這個有限制位數 每次是1 2 3位 ,但仍是不精確 300.300.300.300也能夠匹配

0-99表示爲[0-9]?\d    100-199 表示爲 1\d{2}    200-249 表示爲2[0-4]\d   250-255 表示爲25[0-5]

所示0-255由上面四段取| (或)獲得,0-255表示爲(([0-9]?\d |1\d{2}|2[0-4]\d|25[0-4]).){3}([0-9]?\d |1\d{2}|2[0-4]\d|25[0-4])

 

(二)re庫介紹

re 是python的標準庫,主要功能是用於字符串的匹配

import re 調用

正則表達式的表示類型:re庫採用了raw string類型表示正則表達式,表示爲r'text'

舉例: r'[1-9]\d{5}'  大陸郵政編碼

r'\d{3}-\d{8}|\d{4}-\d{7}' 國內電話號碼

原生字符串與普通字符串不一樣在於 前面加一個r 

區別在於原生字符串不包含轉義符 \的 ,原生字符串中的\ 不解釋爲轉義符

r'[1-9]\d{5}' 用普通字符串表示爲:'[1-9]\\d{5}'  要用雙斜槓\\

具體介紹上述函數:

(1) re.search(pattern, string, flags=0), pattern 表示正則表達式的字符串或者原生字符串

string表示待匹配字符串 ,flags表示一些控制標記

 

舉例:

import re
match=re.search(r'[1-9]\d{5}','BIT 100081')
print(match)
print(match.group(0))

ans:
<_sre.SRE_Match object; span=(4, 10), match='100081'>
100081

(2)re.match(pattern, string, flags=0)

import re
match=re.match(r'[1-9]\d{5}','BIT 100081')
print(match)
print(match.group(0))

ans:AttributeError: 'NoneType' object has no attribute 'group'

報錯了,由於這個字符串的開頭不匹配

若要對匹配結果進行使用,爲了防止報錯,增長if 判斷

import re
match=re.match(r'[1-9]\d{5}','BIT 100081')
if match:    
    print(match.group(0))

此時不會報錯,可是也不會print 結果,由於匹配結果是空的!,如下正確!!能夠匹配

import re
match=re.match(r'[1-9]\d{5}','100081 BIT')
if match:    
    print(match.group(0)
ans:
100081

(3)re.findall(pattern, string, flags=0) 返回列表類型

import re
ls=re.findall(r'[1-9]\d{5}','BIT 100081 XYT 100099')
if ls:    
    print(ls)

ans:
['100081', '100099']

(4)re.split(pattern, string, maxsplit=0,flags=0) 返回列表類型,maxsplit最大分割數,超過它的做爲一個總體最後再輸出來.

import re
print(re.split(r'[0-9]\d{5}','BIT 100081 XYT 100099'))

ans:
['BIT ', ' XYT ', '']

上述將匹配的刪除,增長maxsplit=1,結果是:

import re
print(re.split(r'[0-9]\d{5}','BIT 100081 XYT 100099',maxsplit=1))

ans:
['BIT ', ' XYT 100099']

(5)re.finditer(pattern, string,flags=0)

import re
for m in re.finditer(r'[1-9]\d{5}','BIT 100081 XYT 100099'):
    if m: 
        print(m.group(0))

ans:
100081
100099

100081
100099

(6)re.sub(pattern,repl, string,count=0,flags=0):替換全部匹配的字符串,並返回替換後的字符串

 其中repl:表示替代匹配字符串的字符串(新的字符串)

count 表示匹配最大替換的次數

import re
subs=re.sub(r'[1-9]\d{5}',':zipcode','BIT 100081 XYT 100099')
print(subs)

ans:
BIT :zipcode XYT :zipcode

上述六個經常使用的概括:

其中re.search()  re.match()  返回match對象, re.finditer()每一個迭代元素是match對象

補充:re 的另外一種等價用法

import re
rst1=re.search(r'[1-9]\d{5}','BIT 100081 XYT 100099')
print(rst1.group(0))

pat=re.compile(r'[1-9]\d{5}')#先進行編譯,
rst2=pat.search('BIT 100089 XYT 100099')
print(rst2.group(0))

ans:
100081
100089

#re.compile能夠將正則表達式的字符串形式編譯成正則表達式對象

re.compile(pattern,flags=0)

 

(三)返回match對象 啥是match對象??

match對象的使用方法::

舉例:

import re
m=re.search(r'[1-9]\d{5}','BIT 100081 XYT 100099')
print(m.string)
print(m.re)
print(m.pos)
print(m.endpos)
print(m.group(0))#只返回一次匹配結果,若要屢次匹配結果則 用re.finditer()
print(m.start())
print(m.end())
print(m.span())

結果:

BIT 100081 XYT 100099
re.compile('[1-9]\\d{5}')  #說明了只有通過compile的纔是真正的正則表達式
0
21
100081#返回第一個匹配結果
4 #匹配結果在原字符串中的起始位置
10
(4, 10)

(四)re的貪婪匹配

import re
#re默認採用貪婪匹配,即輸出匹配最長的子串
m=re.search(r'py.*n','pyanbbncccn')
print(m.group())

#如何匹配最短的字符串? 最小匹配,加一個?就能夠了
m1=re.search(r'py.?*n','pyanbbncccn')
print(m1.group())

ans:
pyanbbncccn
pyan

相關文章
相關標籤/搜索