Python爬蟲(chóng)實(shí)例--爬取百度貼吧小說(shuō)
寫在前面
本篇文章是我在簡(jiǎn)書上寫的第一篇技術(shù)文章,作為一個(gè)理科生琐驴,能把僅剩的一點(diǎn)文筆拿出來(lái)獻(xiàn)丑已是不易凿渊,希望大家能在指教我的同時(shí)給予我一點(diǎn)點(diǎn)鼓勵(lì),謝謝熊响。
一.介紹
小說(shuō)吧:顧名思義,是一個(gè)小說(shuō)愛(ài)好者的一個(gè)聚集地诗赌。當(dāng)然這不是重點(diǎn)汗茄,重點(diǎn)是,我們要做的事情便是將小說(shuō)吧中以帖子連載形式的小說(shuō)用爬蟲(chóng)給拿下來(lái)保存到本地
這個(gè)項(xiàng)目是我曾初學(xué)python之時(shí)做的一個(gè)練習(xí)項(xiàng)目铭若,現(xiàn)在再重新拿出來(lái)作為一篇開(kāi)篇簡(jiǎn)作獻(xiàn)給大家洪碳。閱讀本文不需要有很高的python技術(shù)或者爬蟲(chóng)知識(shí),只要略微有些python基礎(chǔ)就可以叼屠,在一些地方瞳腌,我會(huì)盡量給大家詳細(xì)備注。
二.環(huán)境:
Python版本:Python2.7
IDE:Pycharm2017
第三方庫(kù):
urllib2
模塊:urllib2
是python的一個(gè)獲取url(Uniform ResourceLocators镜雨,統(tǒng)一資源定址器)的模塊嫂侍。
re
模塊:Python 的re
模塊(Regular Expression 正則表達(dá)式)提供各種正則表達(dá)式的匹配操作
注:以上兩個(gè)第三方庫(kù)在Python2.7中自帶,因此不用再安裝荚坞。本案例在使用第三方庫(kù)函數(shù)時(shí)會(huì)詳細(xì)介紹用法與功能吵冒。
三.案例
1.導(dǎo)入模塊
首先創(chuàng)建一個(gè)python文件,我這里為main.py
(文件名隨意取西剥,本案例只使用一個(gè)py文件)痹栖。本案例中我們使用兩個(gè)模塊urllib2
和re
,因此首先導(dǎo)入模塊.
# -*- coding:utf-8 -*-
import urllib2 , re
當(dāng)然瞭空,python2版本需要在開(kāi)頭聲明編碼格式揪阿。除了上述代碼的寫法以外,也可以這樣聲明
# coding = utf-8
2.理解思路
我個(gè)人在做項(xiàng)目前習(xí)慣先分析項(xiàng)目咆畏,將步驟一步一步的寫出來(lái)南捂,然后去慢慢實(shí)現(xiàn)。
- 找到目標(biāo)網(wǎng)頁(yè)旧找,獲取源碼
- 匹配標(biāo)題溺健,獲取標(biāo)題內(nèi)容
- 匹配正文,獲取正文內(nèi)容
- 去除或者替換雜項(xiàng)
OK钮蛛,這里思路就是這樣的一個(gè)四部曲”掮裕現(xiàn)在來(lái)看一下代碼框架剖膳。
# -*- coding:utf-8 -*-
import urllib2 , re
#這是本案例的類
class Novel:
baseUrl = '' #這里是你要爬取的小說(shuō)的鏈接
#這個(gè)方法用來(lái)獲取網(wǎng)頁(yè)源碼
def getPage(self):
pass
#這個(gè)方法用來(lái)獲取小說(shuō)標(biāo)題并保存
def getTitle(self):
pass
#這個(gè)方法用來(lái)獲取小說(shuō)文本并保存
def getText(self):
pass
#這是一個(gè)測(cè)試模塊,執(zhí)行本文件時(shí)的入口
if __name__ == '__main__':
n = Novel() #實(shí)例化一個(gè)類
#print n.getPage() #獲取網(wǎng)頁(yè)源碼
n.getTitle()#獲取小說(shuō)題目
n.getText() #獲取小說(shuō)內(nèi)容
現(xiàn)在開(kāi)始一步步實(shí)現(xiàn)功能:
1.找到目標(biāo)網(wǎng)頁(yè)岭辣,獲取網(wǎng)頁(yè)源碼
我在小說(shuō)吧精品貼里面隨便翻了一個(gè)帖子吱晒,就以這個(gè)帖子為案例。
【原創(chuàng)】《貧僧為什么不可以談戀愛(ài)》(古言沦童,長(zhǎng)篇)
現(xiàn)在我們需要爬取這個(gè)帖子中小說(shuō)內(nèi)容仑濒,我們需要直接將它的鏈接地址給baseUrl
嗎?當(dāng)然不是
爬取一個(gè)帖子上的小說(shuō)偷遗,實(shí)際上是去爬取該小說(shuō)作者的所發(fā)表的內(nèi)容墩瞳,所以我們還需要進(jìn)行一步操作,只看樓主
我們所需要的鏈接地址氏豌,就是當(dāng)前這個(gè)了
https://tieba.baidu.com/p/4973334088?see_lz=1
注意一定是要只看樓主后的鏈接喉酌,比之前的會(huì)多出個(gè)?see_lz=1
現(xiàn)在就將你得到的鏈接地址賦值給baseUrl
baseUrl = 'https://tieba.baidu.com/p/4973334088?see_lz=1'
接下來(lái)我們來(lái)獲取這個(gè)網(wǎng)頁(yè)的源碼,也就是實(shí)現(xiàn)getPage函數(shù):
def getPage(self):
request = urllib2.Request(self.baseUrl)
response = urllib2.urlopen(request).read()
return response
本函數(shù)現(xiàn)實(shí)通過(guò)以基本鏈接baseUrl
為參數(shù)實(shí)現(xiàn)了一個(gè)Request
請(qǐng)求類的對(duì)象request箩溃。接著通過(guò)urlopen去執(zhí)行request請(qǐng)求對(duì)象打開(kāi)目標(biāo)網(wǎng)頁(yè)。接著通過(guò)調(diào)用
read`函數(shù)獲取目標(biāo)網(wǎng)頁(yè)的源碼碌嘀,并作為函數(shù)返回值返回.
返回的網(wǎng)頁(yè)源碼涣旨,可在測(cè)試代碼塊中通過(guò)調(diào)用輸出本函數(shù)查看。
例:
if __name__ == '__main__':
n = Novel() #實(shí)例化一個(gè)類
print n.getPage() #獲取網(wǎng)頁(yè)源碼
2.匹配標(biāo)題股冗,獲取標(biāo)題內(nèi)容
首先先亮出我的代碼:
def getTitle(self):
html = self.getPage() #調(diào)用獲取源碼
#r防止轉(zhuǎn)義
reg = re.compile(r'<h3 class="core_title_txt pull-left text-overflow " title="(.*?)" style=')
items = re.findall(reg,html)
for item in items:
print item
f = open('novel.txt','w')
f.write('標(biāo)題===>>>'+item)
f.close()
注意:代碼錯(cuò)行要在行末加\
號(hào)
例如:
print 'hello \
world'
首先我們?cè)诰W(wǎng)頁(yè)源碼中尋找包含小說(shuō)主題部分的源碼霹陡,可以通過(guò)Ctrl+F搜索。查找到<div>^=……中間包含小說(shuō)主題<.div>
這么一長(zhǎng)串的包含小說(shuō)主題的代碼止状。只要將主題部分全部置換為(.*?)號(hào)就可以了烹棉。
在正則表達(dá)式中的含義:
.:匹配任意字符,除了換行符
:匹配前面的子表達(dá)式零次或多次
?:匹配前面的子表達(dá)式零次或一次
():標(biāo)記一個(gè)子表達(dá)式的開(kāi)始和結(jié)束位置怯疤。子表達(dá)式可以獲取供以后使用
(.>):匹配所有滿足條件的表達(dá)式并作為結(jié)果集返回
re.compile
函數(shù)是將正則表達(dá)式的字符串形式編譯為Pattern
實(shí)例浆洗,然后使用Pattern實(shí)例處理文本并獲得匹配結(jié)果,其中字符串前的r是為了防止轉(zhuǎn)義集峦。
findall(正則表達(dá)式伏社,文本) ------將滿足的匹配結(jié)果以list列表返回
用迭代拿到items中的主題名后在將之寫入名為novel.txt
的文件中
3.匹配正文,獲取小說(shuō)正文內(nèi)容
匹配正文塔淤,與匹配標(biāo)題相差無(wú)幾摘昌,首先是尋找以樓主發(fā)表的第一層為例的代碼<div>
段,從中獲取可以作為正則匹配的語(yǔ)句。并將正文部分改為(.*?)
如下
class="d_post_content j_d_post_content "> (.*?)</div><br>
實(shí)現(xiàn)函數(shù)如下:
#這個(gè)方法用來(lái)獲取小說(shuō)文本并保存
def getText(self):
html = self.getPage()
reg = re.compile(r'class="d_post_content j_d_post_content "> (.*?)</div><br>',re.S)#匹配換行符
req = re.findall(reg,html)
for i in req:
print i
f = open('novel.txt','a') #a 追加模式
f.write('\n'+i)
f.close()
如同匹配主題一樣的步驟匹配正文高蜂,但是并沒(méi)有結(jié)束聪黎,因?yàn)槟銜?huì)在你的結(jié)果中看到這樣
對(duì)沒(méi)錯(cuò)。雜亂無(wú)章的正文备恤,中間還有HTML
中的<a>
,<img>
,<br>
等標(biāo)簽
我們接著來(lái)處理
4.替換或者去出雜項(xiàng)
re
模塊中有sub
函數(shù)
sub(被替換的內(nèi)容,替換的內(nèi)容,需要處理的文本) ---- 返回處理后的文本
現(xiàn)在我們將雜項(xiàng)全部給替換成空字符吧""
吧
當(dāng)然<br>
標(biāo)簽可以直接調(diào)用字符串中的replace
函數(shù)替換成換行符\n
修改后的函數(shù)模塊如下:
def getText(self):
html = self.getPage()
reg = re.compile(r'class="d_post_content j_d_post_content "> (.*?)</div><br>',re.S)#匹配換行符
req = re.findall(reg,html)
for i in req:
removeA = re.compile('<a.*?>|</a>')
removeIMG = re.compile('<img.*?>')
removeHTTP = re.compile('<http.*?.html>')
i = re.sub(removeA,"",i)
i = re.sub(removeIMG,"",i)
i = re.sub(removeHTTP,"",i)
i = i.replace('<br>','\n')
print i
f = open('novel.txt','a') #a 追加模式
f.write('\n'+i)
f.close()
注意:記得在打開(kāi)文件函數(shù)中稿饰,對(duì)文件的操作方式為a
追加模式
案例結(jié)束:
將完整代碼貼給大家:
# -*- coding: utf-8 -*-
import urllib2 , re
#這是本案例的類
class Novel:
baseUrl = 'https://tieba.baidu.com/p/4973334088?see_lz=1' #這里是你要爬取的小說(shuō)的鏈接
#這個(gè)方法用來(lái)獲取網(wǎng)頁(yè)源碼
def getPage(self):
request = urllib2.Request(self.baseUrl)
response = urllib2.urlopen(request).read()
return response
#這個(gè)方法用來(lái)獲取小說(shuō)標(biāo)題并保存
def getTitle(self):
html = self.getPage() #調(diào)用獲取源碼
#r防止轉(zhuǎn)義
reg = re.compile(r'<h3 class="core_title_txt pull-left text-overflow " title="(.*?)" style=')
items = re.findall(reg,html)
for item in items:
print item
f = open('novel.txt','w')
f.write('標(biāo)題===>>>'+item)
f.close()
#這個(gè)方法用來(lái)獲取小說(shuō)文本并保存
def getText(self):
html = self.getPage()
reg = re.compile(r'class="d_post_content j_d_post_content "> (.*?)</div><br>',re.S)#匹配換行符
req = re.findall(reg,html)
for i in req:
removeA = re.compile('<a.*?>|</a>')
removeIMG = re.compile('<img.*?>')
removeHTTP = re.compile('<http.*?.html>')
i = re.sub(removeA,"",i)
i = re.sub(removeIMG,"",i)
i = re.sub(removeHTTP,"",i)
i = i.replace('<br>','\n')
print i
f = open('novel.txt','a') #a 追加模式
f.write('\n'+i)
f.close()
#這是一個(gè)測(cè)試代碼塊锦秒,執(zhí)行本文件時(shí)的入口
if __name__ == '__main__':
n = Novel() #實(shí)例化一個(gè)類
#print n.getPage() #獲取網(wǎng)頁(yè)源碼
n.getTitle()#獲取小說(shuō)題目
n.getText() #獲取小說(shuō)內(nèi)容
以后想要獲取小說(shuō)吧哪個(gè)小說(shuō),只要將baseUrl
的地址修改一下就好咯湘纵。
撒花撒花撒花脂崔,從11點(diǎn)寫到了將近2點(diǎn),終于搞定了梧喷。
因?yàn)槭堑谝淮螌懠夹g(shù)文寫這么長(zhǎng)時(shí)間砌左,所以,铺敌,后面耐心不太好汇歹,導(dǎo)致后半篇文章質(zhì)量太差勁。
不過(guò)偿凭,終究是先搞完了一篇哪产弹,簡(jiǎn)書處女技術(shù)作。弯囊。
至于文章瑕疵痰哨,我在白天會(huì)花時(shí)間去修改,也希望大家給我多多提意見(jiàn)匾嘱。我呢~爭(zhēng)取展現(xiàn)給大家的是一篇更加完美的文章斤斧。
夜了,晚安霎烙。
看在作者君這么辛苦的份上撬讽,求您點(diǎn)個(gè)喜歡吧!悬垃!