Python爬蟲實踐筆記(一)

無登錄爬取糗事百科段子

第一步:獲取頁面源碼

(1)先確定我們要爬取的頁面的url,然後通過頁面的開發者工具查看需要發送的headers信息。這裏,糗事百科需要我們添加User-Agent這個頭文件信息,不然建立連接會失敗的。
(2)通過urllib2的Request(url, data, headers)函數生成一個請求包。data和headers都是可選的。這裏不需要傳遞data但是要傳遞headers,必須在傳遞實參時寫明headers = XXX,不然編譯器不知道你傳的是哪個數據的實參。
(3)通過urllib2的urlopen(req)函數來發送請求包並建立連接,函數返回一個響應。需要注意的是,可能會出現連接失敗的情況,所以可以使用異常處理機制try-except來捕獲異常,輸出異常信息,比在編譯時出現一大串信息要好。
(4)使用返回的響應對象的read()方法讀取頁面信息,通過decode(‘utf-8’)函數使頁面信息解碼成utf-8的數據,方便之後的處理。

重點:
①請求的data和headers
②異常處理
③信息讀取和解碼

第二步:提取所需信息

(1)由於上一步獲取的頁面的源代碼,我們需要通過正則表達式來提取我們需要的信息,如發佈人,被贊數以及段子文本。這裏,我們必須仔細查看頁面的源代碼,看看我們的信息在哪裏,然後使用正則表達式來匹配。使用re模塊的compile函數生產字符模式pattern。這個pattern在所有的re模塊函數中都會用到。
(2)將pattern作爲實參傳遞給findall函數,找到符合要求的字符串。在這裏就是要匹配到所有段子所在的部分,以列表的形式作爲findall的返回值返回,列表的元素爲一個匹配成功的字符串。
(3)使用循環逐個處理每一個成功匹配的字符串。
(4)根據應用把所需的信息存儲起來。

重點:
①查看源代碼的佈局。
②最常用的正則表達式部分是.? ,這是非貪婪模式的最長匹配,也就是說一旦匹配到? 後面的字符就立刻停止匹配。加上括號(.?) 分組後可以讓我們在之後使用分組內的信息,所以對於要提取的信息必須用(.?) 匹配。
③提取了信息後,可以根據應用需要進行字符串上的修改。因爲提取的信息可能還包含諸如<br/> 等html符號,還有空格,空行,所以要獲取乾淨的文本必須進行處理。

第三步:構建程序邏輯

(1)這一步比較工程化,只需要把上述步驟封裝好,確定好程序的邏輯,就可以自頂向下地編寫代碼了。可以用面向對象的方法來構建一個爬蟲類,提高代碼的重用性。

重點:
①要注意python面向對象的特點,例如類方法中的參數第一個都是指向實例的參數,不能漏。
②類的成員,不管是數據成員還是成員函數,都需要通過self.XXX的方式調用,而且不要跟自己聲明的局部變量混淆了。
③如果在輸入input函數中顯示中文要是用一下方式unicode(‘XXX’, ‘utf-8’).encode(‘gbk’)。

程序部分:自己實現的程序

下面是我實現的根據頁數爬取糗事百科中的段子,並顯示出來的程序。

__author__ = 'HJX'
# _*_ coding: utf-8 _*_
import re
import urllib
import urllib2
import thread
import time

class QSBK2:
    '糗事百科爬蟲2'
    def __init__(self):
        self.pageIndex = 1;
        self.url = 'https://www.qiushibaike.com/hot/page/'+str(self.pageIndex);
        self.user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36'
        self.headers = {'User-Agent' : self.user_agent}
        self.stories = []

    def getPageCode(self):
        try:
            req = urllib2.Request(self.url, headers = self.headers)
            res = urllib2.urlopen(req)
            pageCode = res.read().decode('utf-8')
            return pageCode
        except urllib2.URLError, e:
            if hasattr(e, 'reason'):
                print u'獲取源碼失敗,原因是:', e.reason
                return None

    def getStories(self):
        stories = []
        pageCode = self.getPageCode()
        if not pageCode:
            print u'獲取當前頁面段子失敗!'
            return None
        pattern = re.compile('<div.*?author clearfix">.*?<h2>(.*?)</h2>.*?content">.*?span>(.*?)</span>.*?number">(.*?)</i>', re.S)
        items = re.findall(pattern, pageCode)
        for item in items:
            publisher = item[0].strip()
            br = re.compile('<br/>')
            text = re.sub(br, '\n', item[1])
            vote = item[2].strip()
            stories.append([publisher, text, vote])
        return stories

    def showStories(self):
        if len(self.stories) == 0:
            print u'當前頁數沒有段子!'
        else:
            for story in self.stories:
                publisher = story[0]
                text = story[1]
                vote = story[2]
                print u'發佈人:%s\t\t被贊數:%s\n%s\n' % (publisher, vote, text)

    def start(self):
        print u'-----糗事百科爬蟲閱讀器,根據頁數看段子-----'
        while 1:
            self.pageIndex = input(unicode('請輸入您要看的頁數,輸入0退出程序:', 'utf-8').encode('gbk'));
            if self.pageIndex == 0:
                print u'程序已退出!'
                break
            self.stories = self.getStories()
            self.showStories();

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