無登錄爬取糗事百科段子
第一步:獲取頁面源碼
(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)根據應用把所需的信息存儲起來。
重點:
①查看源代碼的佈局。
②最常用的正則表達式部分是
③提取了信息後,可以根據應用需要進行字符串上的修改。因爲提取的信息可能還包含諸如
第三步:構建程序邏輯
(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()