Python【爬蟲實戰】提取資料

Ugyfyv發表於2020-11-17

Python【爬蟲實戰】提取資料

通過爬蟲抓取到的內容,需要提取出有用的東西,這一步就是資料提取或者資料清洗

內容一般分為兩部分,非結構化的資料 和 結構化的資料。

非結構化資料:先有資料,再有結構,比如文字、電話號碼、郵箱地址(利用正規表示式處理)、HTML 檔案(利用正則、XPath、CSS選擇器)

結構化資料:先有結構、再有資料,比如JSON(JSON Path)/XML (Xpath/正則等)

不同型別的資料,我們需要採用不同的方式來處理。

實際上爬蟲一共就四個主要步驟:

明確目標 (要知道你準備在哪個範圍或者網站去搜尋)

爬 (將所有的網站的內容全部爬下來)

取 (去掉對我們沒用處的資料)

處理資料(按照我們想要的方式儲存和使用)

什麼是正規表示式

正規表示式,又稱規則表示式,通常被用來檢索、替換那些符合某個模式(規則)的文字。

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

在任何程式語言中都有正規表示式,JS、JAVA、C#等等多有,Python 自1.5版本起增加了re 模組,re 模組使 Python 語言擁有全部的正規表示式功能。

正則匹配的規則
在這裡插入圖片描述
在這裡插入圖片描述

re模組使用步驟

在 Python 中,我們可以使用內建的 re 模組來使用正規表示式。

有一點需要特別注意的是,正規表示式使用 對特殊字元進行轉義,所以如果我們要使用原始字串,只需加一個 r 字首,示例:r’testt.tpython’

re 模組的一般使用步驟如下:
1.使用 compile() 函式將正規表示式的字串形式編譯為一個 Pattern 物件

2.通過 Pattern 物件提供的一系列方法對文字進行匹配查詢,獲得匹配結果,一個 Match 物件。

3.最後使用 Match 物件提供的屬性和方法獲得資訊,根據需要進行其他的操作

str="abcdefabcdef" #待匹配的字串
m=re.compile("a") #編譯正規表示式,第一個引數是表示式字串,第二個引數是標誌位,比如re.I 匹配不對大小寫敏感,re.S等等
result=m.findall(str) 
print(result) #輸出["a","a"]

具體的正規表示式如何編寫,其實就是根據上圖的元字元進行組合,匹配你要的結果,
小練習1:找出字串中的數字。 d表示 0-9 + 表示匹配前一個字元1次或無限次

str="a11b22c3"
m=re.compile("\d+")
print(m.findall(str)) #輸出['11', '22', '3']

小練習2:找出單詞中包含 oo的單詞


str="1oo1 tina is a good girl ,she is cool"
m=re.compile("[a-z]oo[a-z]")
print(m.findall(str)) #輸出['good', 'cool']

大概知道了正則的書寫方式以後,先來看後續的步驟,不要著急,編寫正則是個積累的過程。

compile() 函式將正規表示式的字串形式編譯為一個 Pattern 物件,Pattern 物件提供的一系列方法對文字進行匹配查詢,來羅列下方法:

m.search函式會在字串內查詢模式匹配,只要找到第一個匹配然後返回,如果字串沒有匹配,則返回None。


str="1oo1 tina is a good girl ,she is cool"
m=re.compile("[a-z]oo[a-z]")
print(m.search(str)) #<_sre.SRE_Match object; span=(15, 19), match='good'>

m.findall遍歷匹配,可以獲取字串中所有匹配的字串,返回一個列表。


str="1oo1 tina is a good girl ,she is cool"
m=re.compile("[a-z]oo[a-z]")
print(m.findall(str)) #輸出['good', 'cool']

m.match()決定RE是否在字串剛開始的位置匹配


str="aooz tina is a good girl ,she is cool"
m=re.compile("[a-z]oo[a-z]")
#str為待匹配的字串,第一個引數是起始位置,第二個是字串長度,從0開始,長度為6
print(m.match(str,0,6)) #<_sre.SRE_Match object; span=(0, 4), match='aooz'>

m.split()按照能夠匹配的子串將string分割後返回列表


str="aa1bb2cc3dd4"
m=re.compile("\d+")
# split(string[, maxsplit]),maxsplit 用於指定最大分割次數,不指定將全部分割
# list=m.split(str) #輸出['aa', 'bb', 'cc', 'dd', '']
list=m.split(str,2) #輸出['aa', 'bb', 'cc3dd4']
print(list)

m.sub()使用re替換string中每一個匹配的子串後返回替換後的字串。


str="aa1bb2cc3dd4"
m=re.compile("\d+")
result=m.sub('*',str) 
print(result) #輸出aa*bb*cc*dd*

正則練習題

1 已知字串:

info = ‘baidu’

用正則模組提取出網址:"http://www.baidu.com"和連結文字:“baidu”

2 字串:“one1two2three3four4” 用正則處理,輸出 “1234”

3 已知字串:text = “JGood is a handsome boy, he is cool, clever, and so on…”

查詢所有包含’oo’的單詞。

正則練習題答案:


# 1 已知字串:
# info = '<a href="http://www.baidu.com">baidu</a>'
# 用正則模組提取出網址:"http://www.baidu.com"和連結文字:"baidu"
info = '<a href="http://www.baidu.com">baidu</a>'
# pattern1=re.compile(r'http:.+.com')#['www.baidu.com', 'baidu']
# pattern1=re.compile(r"[a-z.]*baidu[.a-z]*")#['www.baidu.com', 'baidu']
pattern1=re.compile(r"[w.]*baidu\.*\w*") #['www.baidu.com', 'baidu']
f1=pattern1.findall(info)
print(f1)
# print(f1[0])

#2 字串:"one1two2three3four4" 用正則處理,輸出 "1234"
info1="one1two2three3four4"
pattern2=re.compile(r'\d{1}')
f2=pattern2.findall(info1)
print(f2) #['1', '2', '3', '4']

# 3 已知字串:text = "JGood is a handsome boy, he is cool, clever, and so on..." 查詢所有包含'oo'的單詞。
info3="JGood is a handsome boy, he is cool, clever, and so on..."
pattern3=re.compile(r'\w*oo\w*')
f3=pattern3.findall(info3)
print(f3)

爬蟲內涵段子正則匹配爬取


from urllib import request
import re

#定義一個爬蟲類
class Splider:
    def __init__(self):
        # 初始化起始頁的位置
        self.page = 1
        # 爬取開關,如果為True繼續爬取
        self.switch = True

    def loadPage(self):
        '''
        下載頁面
        '''
        # 拼接完成的url
        url = 'http://www.neihan8.com/article/list_5_'+str(self.page)+'.html'

        headers = {"User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"}

        request1 = request.Request(url,headers=headers)
        response = request.urlopen(request1)

        # 每頁的html原始碼
        html = response.read().decode('gbk')
        print(html)

        # 建立正規表示式規則物件,匹配每頁裡的段子內容,re.S是匹配全部的字串內容
        pattern = re.compile('<div\sclass="f18 mb20">(.*?)</div>',re.S)

         # 將正則匹配物件應用到html原始碼字串裡,返回這個頁面裡的所有段子的列表
        content_list = pattern.findall(html)

        print(content_list)

        # for content in content_list:
        #     print content.decode('gbk')

        self.dealPage(content_list)

    def dealPage(self,content_list):

        '''
        處理每頁的段子
        content_list: 每頁的段子列表集合
        '''

        for item in content_list:
            item = item.replace('<p>',"").replace('</p>','').replace('&rdquo;','').replace('&ldquo;','').replace('<br />','').replace('<br />','').replace('&hellip;','')
            print(item)
        # 處理完成後呼叫writePage()將每個段子寫入檔案內
        self.writePage(item)
    def writePage(self,item):
        '''
            把每條段子逐個寫入檔案裡
            item:處理後的每條段子
        '''
        # 寫入檔案內
        print('正在寫入資料....')
        with open('duanzi.txt','a') as f:
            f.write(item)

    def startWork(self):
        '''
        控制爬蟲的功能
        '''

        while self.switch:
            # 使用者確定爬取的次數
            self.loadPage()
            command = input('如果想繼續爬取,請按回車(退出輸入的quit)')
            if command == 'quit':
                # 如果停止爬取,則輸入quit
                self.switch = False
            # 每次迴圈,page頁碼自增1
            self.page = self.page+1
        print("謝謝使用")

if __name__ == '__main__':
    duanziSpider = Splider()
    duanziSpider.startWork()

相關文章