1. 程式人生 > >Python爬蟲例項--爬取百度貼吧小說

Python爬蟲例項--爬取百度貼吧小說

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檔案)。本案例中我們使用兩個模組urllib2re,因此首先匯入模組.

# -*- coding:utf-8 -*-
import urllib2 , re

當然,python2版本需要在開頭宣告編碼格式。除了上述程式碼的寫法以外,也可以這樣宣告

# coding = utf-8

2.理解思路

我個人在做專案前習慣先分析專案,將步驟一步一步的寫出來,然後去慢慢實現。

  1. 找到目標網頁,獲取原始碼
  2. 匹配標題,獲取標題內容
  3. 匹配正文,獲取正文內容
  4. 去除或者替換雜項

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嗎?當然不是
爬取一個帖子上的小說,實際上是去爬取該小說作者的所發表的內容,所以我們還需要進行一步操作,只看樓主
這裡寫圖片描述

我們所需要的連結地址,就是當前這個了

現在就將你得到的連結地址賦值給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的地址修改一下就好咯。