我們想針對(duì)網(wǎng)站的內(nèi)容進(jìn)行篩選,只獲取自己感興趣的部分。比如你想在XX網(wǎng)站把小黃圖篩選出來(lái),打包帶走。這里只做簡(jiǎn)單的實(shí)現(xiàn),以百思不得姐上的段子(純文本)為例。我們想要實(shí)現(xiàn)如下功能:
批量下載若干頁(yè)段子到本地文件中
按下任意一鍵,開(kāi)始閱讀下一條段子
導(dǎo)入urllib
的相關(guān)庫(kù),Python 3中應(yīng)該這樣寫:
import urllib.requestimport urllib.parseimport re
re庫(kù)是正則表達(dá)式(Regular Expression),后面作匹配時(shí)會(huì)用到。
百思不得姐的段子頁(yè)面url ='http://www.budejie.com/text/1'
,這里末尾數(shù)字1代表此為第一頁(yè)。通過(guò)以下代碼就能返回網(wǎng)頁(yè)內(nèi)容。
req = urllib.request.Request(url)# 添加headers 使之看起來(lái)像瀏覽器在訪問(wèn)req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 ' '(KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36') response = urllib.request.urlopen(req)# 得到網(wǎng)頁(yè)內(nèi)容,注意必須使用decode()解碼html = response.read().decode('utf-8')
print(html)
的話,就是如下所示的內(nèi)容:
這能看?段子呢?我們想要的段子呢?!
哦對(duì)了headers這樣查看。
按F12,然后...看圖吧
要想篩選符合普通人閱讀的內(nèi)容(如果還帶著html標(biāo)簽?zāi)沁€咋讀是不),成功提取出段子,為此我們需要一些既定的模式去和網(wǎng)頁(yè)全部?jī)?nèi)容進(jìn)行匹配,將模式下匹配成功的對(duì)象返回。我們使用強(qiáng)大的正則表達(dá)式進(jìn)行匹配(Regular Expression),相關(guān)語(yǔ)法可以看這里。
僅僅針對(duì)本例中的網(wǎng)頁(yè)內(nèi)容,先看看我們需要的段子對(duì)應(yīng)了網(wǎng)頁(yè)中的什么內(nèi)容。
可以看到段子被<div class="j-r-list-c-desc">(我們要的內(nèi)容)</div>
這樣的標(biāo)簽所包圍,只需要指定相應(yīng)規(guī)則提取出來(lái)即可!上圖可以看出段子正文前后是有很多空格的,需要匹配進(jìn)去。
pattern = re.compile(r'<div class="j-r-list-c-desc">s+(.*)s+</div>') result = re.findall(pattern, html)
通過(guò)re
庫(kù)的compile
函數(shù)制定規(guī)則。
s+
可以匹配一個(gè)或更多的空格
.
匹配除開(kāi)換行符
外的所有字符。
現(xiàn)在我們得到了匹配后的結(jié)果,來(lái)看下。
Bingo!提取出來(lái)了不是?!
可是我們發(fā)現(xiàn)里面還有些討厭的<br />
。沒(méi)關(guān)系,寫幾行代碼的事。這里就不再展示去掉后的內(nèi)容,自行腦補(bǔ)哈哈。
for each in content:# 如果某個(gè)段子里有<br />if '<br />' in each:# 替換成換行符并
這里content
是我們通過(guò)re.findall()
返回的列表。
至此,我們成功得到我們想看的段子了!如果想要下載到本地呢?
通過(guò)定義一個(gè)save()
函數(shù)即可,num
參數(shù)用戶自定,想下載最近100頁(yè)的內(nèi)容都沒(méi)問(wèn)題!里面還有些變量沒(méi)有提到,最后會(huì)給出源代碼。
# num是指定網(wǎng)頁(yè)頁(yè)數(shù)def save(num):# 寫方式打開(kāi)一個(gè)文本,把獲取的段子列表存放進(jìn)去with open('a.txt', 'w', encoding='utf-8') as f: text = get_content(num)# 和上面去掉<br />類似for each in text:if '<br />' in each: new_each = re.sub(r'<br />', ' ', each) f.write(new_each)else: f.write(str(each) + ' ')
下載到本地文檔后如下圖所示
段子太多,琳瑯滿目。可我們只希望一條條閱讀。通過(guò)按下鍵盤任意鍵可以切換到下一條,直到讀取到最后一條程序才結(jié)束,或者通過(guò)設(shè)置一個(gè)退出鍵隨時(shí)退出程序,比如設(shè)定q
鍵退出。這里把全部代碼給出。
import urllib.requestimport urllib.parseimport re pattern = re.compile(r'<div class="j-r-list-c-desc">s+(.*)s+</div>')# 返回指定網(wǎng)頁(yè)的內(nèi)容def open_url(url): req = urllib.request.Request(url) req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 ' '(KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36') response = urllib.request.urlopen(req) html = response.read().decode('utf-8')return html# num為用戶自定,返回的是所有頁(yè)的段子列表def get_content(num):# 存放段子的列表text_list = []for page in range(1, int(num)): address = 'http://www.budejie.com/text/' + str(page) html = open_url(address) result = re.findall(pattern, html)# 每一頁(yè)的result都是一個(gè)列表,將里面的內(nèi)容加入到text_listfor each in result: text_list.append(each)return text_list# num是指定網(wǎng)頁(yè)頁(yè)數(shù)def save(num):# 寫方式打開(kāi)一個(gè)文本,把獲取的段子列表存放進(jìn)去with open('a.txt', 'w', encoding='utf-8') as f: text = get_content(num)# 和上面去掉<br />類似for each in text:if '<br />' in each: new_each = re.sub(r'<br />', ' ', each) f.write(new_each)else: f.write(str(each) + ' ') if __name__ == '__main__':print('閱讀過(guò)程中按q隨時(shí)退出') number = int(input('想讀幾頁(yè)的內(nèi)容: ')) content = get_content(number + 1)for each in content:if '<br />' in each: new_each = re.sub(r'<br />', ' ', each)print(new_each)else:print(each)# 用戶輸入user_input = input()# 不區(qū)分大小寫的q,輸入則退出if user_input == 'q' or user_input == 'Q':break
演示一下,效果是這樣的。
雖然功能很雞肋,不過(guò)作為初學(xué)我還是很滿意了,有興趣才能深入下去嘛!爬蟲可不僅僅如此而已,以后會(huì)學(xué)習(xí)更加高級(jí)的功能。
by @sunhaiyu
2016.8.15
聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com