Python爬蟲實例--爬取百度貼吧小說
寫在前面
本篇文章是我在簡書上寫的第一篇技術文章,作為一個理科生,能把僅剩的一點文筆拿出來獻丑已是不易,希望大家能在指教我的同時給予我一點點鼓勵,謝謝。
一.介紹
小說吧:顧名思義,是一個小說愛好者的一個聚集地。當然這不是重點,重點是,我們要做的事情便是將小說吧中以帖子連載形式的小說用爬蟲給拿下來保存到本地
這個項目是我曾初學python之時做的一個練習項目,現在再重新拿出來作為一篇開篇簡作獻給大家。閱讀本文不需要有很高的python技術或者爬蟲知識,只要略微有些python基礎就可以,在一些地方,我會盡量給大家詳細備注。
二.環境:
Python版本:Python2.7
IDE:Pycharm2017
第三方庫:
urllib2
模塊:urllib2
是python的一個獲取url(Uniform ResourceLocators,統一資源定址器)的模塊。
re
模塊:Python 的re
模塊(Regular Expression 正則表達式)提供各種正則表達式的匹配操作
注:以上兩個第三方庫在Python2.7中自帶,因此不用再安裝。本案例在使用第三方庫函數時會詳細介紹用法與功能。
三.案例
1.導入模塊
首先創建一個python文件,我這里為main.py
(文件名隨意取,本案例只使用一個py文件)。本案例中我們使用兩個模塊urllib2
和re
,因此首先導入模塊.
# -*- coding:utf-8 -*-
import urllib2 , re
當然,python2版本需要在開頭聲明編碼格式。除了上述代碼的寫法以外,也可以這樣聲明
# coding = utf-8
2.理解思路
我個人在做項目前習慣先分析項目,將步驟一步一步的寫出來,然后去慢慢實現。
- 找到目標網頁,獲取源碼
- 匹配標題,獲取標題內容
- 匹配正文,獲取正文內容
- 去除或者替換雜項
OK,這里思路就是這樣的一個四部曲。現在來看一下代碼框架。
# -*- coding:utf-8 -*-
import urllib2 , re
#這是本案例的類
class Novel:
baseUrl = '' #這里是你要爬取的小說的鏈接
#這個方法用來獲取網頁源碼
def getPage(self):
pass
#這個方法用來獲取小說標題并保存
def getTitle(self):
pass
#這個方法用來獲取小說文本并保存
def getText(self):
pass
#這是一個測試模塊,執行本文件時的入口
if __name__ == '__main__':
n = Novel() #實例化一個類
#print n.getPage() #獲取網頁源碼
n.getTitle()#獲取小說題目
n.getText() #獲取小說內容
現在開始一步步實現功能:
1.找到目標網頁,獲取網頁源碼
我在小說吧精品貼里面隨便翻了一個帖子,就以這個帖子為案例。
【原創】《貧僧為什么不可以談戀愛》(古言,長篇)
現在我們需要爬取這個帖子中小說內容,我們需要直接將它的鏈接地址給baseUrl
嗎?當然不是
爬取一個帖子上的小說,實際上是去爬取該小說作者的所發表的內容,所以我們還需要進行一步操作,只看樓主
我們所需要的鏈接地址,就是當前這個了
https://tieba.baidu.com/p/4973334088?see_lz=1
注意一定是要只看樓主后的鏈接,比之前的會多出個?see_lz=1
現在就將你得到的鏈接地址賦值給baseUrl
baseUrl = 'https://tieba.baidu.com/p/4973334088?see_lz=1'
接下來我們來獲取這個網頁的源碼,也就是實現getPage函數:
def getPage(self):
request = urllib2.Request(self.baseUrl)
response = urllib2.urlopen(request).read()
return response
本函數現實通過以基本鏈接baseUrl
為參數實現了一個Request
請求類的對象request。接著通過urlopen去執行request請求對象打開目標網頁。接著通過調用
read`函數獲取目標網頁的源碼,并作為函數返回值返回.
返回的網頁源碼,可在測試代碼塊中通過調用輸出本函數查看。
例:
if __name__ == '__main__':
n = Novel() #實例化一個類
print n.getPage() #獲取網頁源碼
2.匹配標題,獲取標題內容
首先先亮出我的代碼:
def getTitle(self):
html = self.getPage() #調用獲取源碼
#r防止轉義
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('標題===>>>'+item)
f.close()
注意:代碼錯行要在行末加\
號
例如:
print 'hello \
world'
首先我們在網頁源碼中尋找包含小說主題部分的源碼,可以通過Ctrl+F搜索。查找到<div>^=……中間包含小說主題<.div>
這么一長串的包含小說主題的代碼。只要將主題部分全部置換為(.*?)號就可以了。
在正則表達式中的含義:
.:匹配任意字符,除了換行符
:匹配前面的子表達式零次或多次
?:匹配前面的子表達式零次或一次
():標記一個子表達式的開始和結束位置。子表達式可以獲取供以后使用
(.>):匹配所有滿足條件的表達式并作為結果集返回
re.compile
函數是將正則表達式的字符串形式編譯為Pattern
實例,然后使用Pattern實例處理文本并獲得匹配結果,其中字符串前的r是為了防止轉義。
findall(正則表達式,文本) ------將滿足的匹配結果以list列表返回
用迭代拿到items中的主題名后在將之寫入名為novel.txt
的文件中
3.匹配正文,獲取小說正文內容
匹配正文,與匹配標題相差無幾,首先是尋找以樓主發表的第一層為例的代碼<div>
段,從中獲取可以作為正則匹配的語句。并將正文部分改為(.*?)
如下
class="d_post_content j_d_post_content "> (.*?)</div><br>
實現函數如下:
#這個方法用來獲取小說文本并保存
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()
如同匹配主題一樣的步驟匹配正文,但是并沒有結束,因為你會在你的結果中看到這樣
對沒錯。雜亂無章的正文,中間還有HTML
中的<a>
,<img>
,<br>
等標簽
我們接著來處理
4.替換或者去出雜項
re
模塊中有sub
函數
sub(被替換的內容,替換的內容,需要處理的文本) ---- 返回處理后的文本
現在我們將雜項全部給替換成空字符吧""
吧
當然<br>
標簽可以直接調用字符串中的replace
函數替換成換行符\n
修改后的函數模塊如下:
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()
注意:記得在打開文件函數中,對文件的操作方式為a
追加模式
案例結束:
將完整代碼貼給大家:
# -*- coding: utf-8 -*-
import urllib2 , re
#這是本案例的類
class Novel:
baseUrl = 'https://tieba.baidu.com/p/4973334088?see_lz=1' #這里是你要爬取的小說的鏈接
#這個方法用來獲取網頁源碼
def getPage(self):
request = urllib2.Request(self.baseUrl)
response = urllib2.urlopen(request).read()
return response
#這個方法用來獲取小說標題并保存
def getTitle(self):
html = self.getPage() #調用獲取源碼
#r防止轉義
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('標題===>>>'+item)
f.close()
#這個方法用來獲取小說文本并保存
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()
#這是一個測試代碼塊,執行本文件時的入口
if __name__ == '__main__':
n = Novel() #實例化一個類
#print n.getPage() #獲取網頁源碼
n.getTitle()#獲取小說題目
n.getText() #獲取小說內容
以后想要獲取小說吧哪個小說,只要將baseUrl
的地址修改一下就好咯。
撒花撒花撒花,從11點寫到了將近2點,終于搞定了。
因為是第一次寫技術文寫這么長時間,所以,,后面耐心不太好,導致后半篇文章質量太差勁。
不過,終究是先搞完了一篇哪,簡書處女技術作。。
至于文章瑕疵,我在白天會花時間去修改,也希望大家給我多多提意見。我呢~爭取展現給大家的是一篇更加完美的文章。
夜了,晚安。
看在作者君這么辛苦的份上,求您點個喜歡吧!!