1. 程式人生 > >正則與爬蟲(1)

正則與爬蟲(1)

正則是什麼

正則是一門小型的程式語言,在python中正則被封裝成re模組。自己對正則的理解就是用來匹配字串中一些字元,正則使得匹配字串的匹配更加多樣。

三種匹配方法

re模組中匹配了三種方法(findall,match,search)

s = "/home/kioskday25/PycharmProjects/python_stack/day25/正則表示式的正常使用符那方法.py"
pattern = r'day'
pattern1 = r'/home'

print(re.findall(pattern,s))
#注意:findall會匹配子符串中所有的字元,並以列表的形式把他們列出來
print(re.match(pattern1,s).group())
#注意:match方法只匹配字串的開頭:
#當在開頭匹配到字串時,返回一個物件,如果要檢視匹配的結果,需要借用group方法,gruop方法返回的是一個字串
#當沒有匹配到結果時返回一個空
print(re.search(pattern,s).group())
#注意:search方法匹配的是整個字串,當字串中有多個滿足匹配結果時,只匹配第一個,並通過gruop方法獲取到匹配的結果。

結果如下:
在這裡插入圖片描述

正則特殊字元類


#.:匹配除\n之外的任意字元,並將每個匹配到的字元通過列表儲存
print(re.findall(r'.','westos\n'))


#\d:匹配一個數字,等加於[0-9]
#\D:匹配除數字外的任意一個字元
print(re.findall('\d','python12345linux'))
print(re.findall('\D','python12345linux'))


#\s:匹配單個任何空白的字元
#\S:匹配除單個任何空白字元的任何字元
print(re.findall('\s',"python\r123\tlinux"))
print(re.findall('\S',"python\r123\tlinux"))


#\w:匹配字母數字或下劃線
#\W:匹配除字母數字下劃線的字元
print(re.findall('\w',"python_123_linxu%%%%@@@"))
print(re.findall('\W',"python_123_linxu%%%%@@@"))

print(re.findall('[1-5][0-9]','123456'))
pattern = r'[ABC][]'

注意:在findall方法中,匹配返回的結果是一個列表。
結果:
在這裡插入圖片描述

在上面的匹配中,如果我們要匹配一個數字,那我們就必須寫多次\d,顯得非常麻煩。在正則中,我們可以利用一個語法實現實現\d多次,免去多次書寫的麻煩。


#*代表前面的字元出現0次或者無限多次
print(re.findall("\d*",'132233'))

#+代表前面的字元出現一次或者無限次
print(re.findall("\d+",'122245'))

#?代表一個字元出現1次或者0次
print(re.findall("\d?","123455"))

#{m}:前一個字元出現m次
#{m,}:前一個字元至少出現m次
#{m,n}:前一個字元出現m次到n次

pattern = r"[a-zA-z][\w]{5,11}@qq\.com"
print(re.findall(pattern,'
[email protected]
'))

結果:
在這裡插入圖片描述

轉義字元

|:匹配左右任意一個表示式即可
print(re.findall(r"(westos|hello)\d+",'westoshello446'))
在這裡插入圖片描述
(mn):將括號裡面的內容作為一個分組

s = '<span class="red">31</span>'
print(re.findall(pattern,s))


pattern1 = r'(<span class="red">(\d+)</span>)'
s = '<span class="red">31</span>'
print(re.findall(pattern1,s))


print(re.findall(r'((westos|hello)\d+)',"westos1hello2"))
#把匹配到的內容分成組,每組以元組的形式儲存

\num:引用分組第num個字串
(?P):分組起別名

爬去貼吧中的qq郵箱

分析:實現這個效果要利用正則表示式,對得到的網頁原始碼進行匹配操作。
程式碼可分為以下幾個模組:

  • 獲取原始碼:對網頁的內容進行爬取,並進行解碼
  • 獲取網頁的頁數:寫一個正則表示式,從獲取到的原始碼中獲取到貼吧的總頁數。
  • 獲取郵箱:寫一個郵箱的正則表示式,從獲取到的的原始碼中獲取到郵箱,具體為先獲取到頁數,然後利用迴圈對每一頁的原始碼進行獲取,然後對原始碼進行一個郵箱的提取操作,。
  • 主函式:呼叫上面幾個函式,然後把函式返回的郵箱地址,寫入檔案中。
from itertools import chain
from urllib.request import urlopen

def getPageHtml(url):
   #獲取網頁的原始碼檔案
   obj = urlopen(url)
   return obj.read().decode('utf-8')

#print(getPageHtml("http://tieba.baidu.com/p/3600458679"))

'''<li class="l_reply_num" style="margin-left:8px" ><span class="red" style="margin-right:3px">1193</span>回覆貼,共<span class="red">26</span>頁</li>'''
def getPagenum(text):
   #從原始碼檔案中獲取,總頁數
   pattern = r'<span class="red">(\d{0,3})</span>'
   return re.findall(pattern,text)[0]

#text = getPageHtml("http://tieba.baidu.com/p/3600458679")
#print(getPagenum(text))

'''http://tieba.baidu.com/p/3600458679?pn=2'''
def getPageEMail(count):
   #對所有頁數的檔案挨個進行爬取,並利用正則表示式從原始碼中,匹配到資訊
   mails = []
   for i in range(int(count)):
       url = "http://tieba.baidu.com/p/2314539885?pn=%d" %(i+1)
       text = getPageHtml(url)
       #<li class="d_name" data-field='{&quot;user_id&quot;:1159023837}'>
       #[email protected]
       pattern1 = r'\d{5,12}@qq\.com'
       print("正在爬取http://tieba.baidu.com/p/3600458679?pn=%d的內容" %(i+1))
       print(re.findall(pattern1,text))
       mails.append(re.findall(pattern1,text))
   return mails


def main():
   text = getPageHtml("http://tieba.baidu.com/p/2314539885")
   count = getPagenum(text)
   email = getPageEMail(count)
   #chain 方法是對不同集合中的元素進行操作時,將不同的列表連線起來
   with open("mails.txt",'w') as f:
       for i in chain(*email):
           f.write(i+"\n")
main()

結果:
在這裡插入圖片描述

爬取圖片

from urllib.request import urlopen


def getPageHtml(url):  #獲取網頁的原始碼
    obj = urlopen(url)  
    return obj.read()

def getPagepic(text):  
#從網頁的原始碼中獲取到圖片的網址,返回的是一個列表,列表裡面儲存的是當前網頁的所有圖片的地址
    pattern ='<img class="BDE_Image" .*?src="(http://.*?\.jpg)".*?>'
    return re.findall(pattern,text.decode('utf-8'))


url = "http://tieba.baidu.com/p/5904388543"
text = getPageHtml(url)  
picurl = getPagepic(text)  
#對存有圖片地址的列表進行一個遍歷,依次對圖片的網址開啟進行一個獲取圖片。
for i,v in enumerate(picurl):
    with open("img/img%d.jpg" %(i+1),"wb") as f:
        content = getPageHtml(v)
        print("正在爬取第%d張圖片" %(i+1))
        f.write(content)

結果:
在這裡插入圖片描述