Python 拾起正則表達式,提升對re的認知,爬取某度貼吧篩選所需信息

昨天一起玩遊戲的一位老哥找到我,問我可不可以寫一個爬取百度貼吧中有關回收中石化刮刮卡並且包含手機號碼信息的爬蟲。心想那個時候我第一時間想到了 bs4 的 find_all(),應該這種先入爲主的思想讓我走過了很多彎路。

基本思路

先看一看所需內容的大概結構
大概可以看作網頁以一個列表的形式展現信息即每一篇文章的信息都存放在一個 li節點中
在這裏插入圖片描述
思路:獲取每篇文章的url —> 下載並分析每篇文章的源碼 —> 篩選每位用戶發表信息 —> 匹配手機號碼 —> 保存信息到本地

走過的彎路

過於喜歡遍歷,以至於很浪費時間(此時還沒有考慮內存的思想)

依賴於 for 循環,在匹配手機號碼時,採用了最笨的一種方法

words = '油卡中石化刮刮充值卡,信譽有保障,有興趣的來撩,北京號稱幾十億的大資方迴避,居間人勿擾,誠信做的諮詢!聯繫方式:13703756542'
phone_num = 0
for i in range(len(words)):
	if words[i].isalnum():
		if phone_num == 0:
			if words[i + 1].isalnum()
				phone_num += 1
		if phone_num != 0:
			if words[i - 1].isalnum():
				phone_num += 1
			else:
				phone_num == 1
if phone_num == 10: 
# 手機號碼都是十一位,注意phone_num 從0開始計數,故表示如果文段中包含11位的數字,就保存信息
	with open('./record.txt','a') as record:
		record.write(words + '\n')

保存信息時,忽略編碼格式造成亂碼

可以看到上一小節內容中有這樣的兩行文字

with open('./record.txt','a') as record:
		record.write(words + '\n')

至於編碼格式我沒有進行研究過。大多時候我在保存信息時並沒有加上 encoding = ‘xxx’ 這樣的一句話,也並沒有因此造成存入的信息爲亂碼。只遇到過讀取信息時不加編碼格式會出現亂碼。

with open('./record.txt','a',encoding = 'utf-8') as record:
		record.write(words + '\n')

無論是否研究過編碼格式,養成一個無論讀取都要指定編碼格式的習慣,也會少走一些小彎路。

處理異常能力不強

如果搜一下爬蟲,全稱叫做網絡爬蟲。顧名思義,爬蟲靠得就是網絡。那問題到我這兒就真是個問題了,家裏網絡有時候會有波動,會連不上網,但是對於網絡出現的鏈接不到人家的服務器,我就只會

for page_html in page_htmls:
	try:
		parse_html()
	except:
		time.sleep(3)
		continue

這樣造成的結果就是可能把某個帖子跳過去,然而又恰好這個帖子中有你需要的信息,又恰好這份信息會帶來效益。。。你看,不會處理異常,虧不虧?

正則表達式的優勢

規規矩矩,只找出符合格式的信息

words = '油卡中石化刮刮充值卡,信譽有保障,有興趣的來撩,北京號稱幾十億的大資方迴避,居間人勿擾,誠信做的諮詢!聯繫方式:13703756542'
phone_number = re.findall(r'1\d\d\d\d\d\d\d\d\d\d',words)
# phone_num = re.findall(r'1\d*10')
# 喜歡用第一個方法,因爲我對數字不敏感,第一個雖然麻煩點兒,但是很直觀,但是缺點是糾錯時要一個一個查,很麻煩

與上方笨方法相比,減少了不知多少篇幅,節省了不知多少時間
附加正則匹配規則表一張
在這裏插入圖片描述

正則表達式的劣勢

匹配規則需要十分嚴謹

之前寫過一個爬取小紅書視頻的爬蟲,那時候還沒學xpath、bs4、pyquery 只接觸了正則表達式
先看一個例子吧

def down_video(self,*s1):
        try:
            self.flag += 1
            lis1 = [""]
            for i in s1:
                lis1[0] += i
            response = requests.get(lis1[0],headers=self.headers)
            time.sleep(1)
            html = response.text
            url = re.findall('<video poster=".*?" src="(.*?)" controls=".*?" objectFit=".*?" class=".*?" ', html)
            title = re.findall('<meta property="og:title" content="(.*?)">', html)
            lis1 = []
            start = url[0].find("amp;")
            lis1.append(url[0][:start])
            lis1[0] += url[0][start + 4:]
            url = lis1[0]
            response = requests.get(url, headers=self.headers)
            with open("D:/小紅書視頻/" + title[0] + '.mp4', 'wb') as f:
                f.write(response.content)
        except urllib.error.URLError as e:
            print(e.reason())

這是當時用純正則匹配出來的url,可以看到這樣的兩行內容

url = re.findall('<video poster=".*?" src="(.*?)" controls=".*?" objectFit=".*?" class=".*?" ', html)
title = re.findall('<meta property="og:title" content="(.*?)">', html)

在匹配 url 時,原標籤頁不只是

<video poster=".*?" src="(.*?)" controls=".*?" objectFit=".*?" class=".*?" '

在class後還有很多個屬性,當時也是處於懵懂的狀態,認爲匹配可以將那些相同的屬性刪去,所以嘗試過很多次都失敗告終
失敗時的寫法:

url = re.findall('<video poster=".*?" src="(.*?)" controls=".*?" objectFit=".*?" class=".*?" '>, html)

仔細看就可以看到與正確寫法只相差一個 > ,正因爲這樣的一個 > 符號,讓我對正則表達式有了一份忌憚,以至於在寫過這個小紅書爬蟲後再也沒有用過正則表達式

總結

在篩選信息時,不要太依賴於更高級別,更方便的解析器。就像美某國一樣,科技的確很發達,但是基礎製造業很是平凡,離開中國,還不是算個der

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章