最近閑的無(wú)聊,想爬點(diǎn)書(shū)看看。 于是我選擇了這個(gè)網(wǎng)站雨楓軒。
STEP1.分析網(wǎng)站
一開(kāi)始我想通過(guò)一篇文章引用的鏈接,將書(shū)爬完,后來(lái)發(fā)現(xiàn)并不需要這樣做。比如我們可以打開(kāi)人生哲學(xué)這個(gè)欄目。

如圖1所示,會(huì)把頁(yè)面數(shù)全列出來(lái)。
并且這個(gè)url
http://txt.rain8.com/txtzx/list_93_1.html
也非常的有規(guī)律。
可以看出是由
'http://txt.rain8.com/txt'+'欄目名稱(chēng)'+'list_欄目編號(hào)_頁(yè)數(shù).html'
組成的。
知道了這點(diǎn)后,我們就能輕松的把網(wǎng)站爬完了。
STEP2.初始化
首先我們來(lái)理清思路。

這是我們需要的庫(kù)
import requests
import re
import os
其實(shí)這個(gè)項(xiàng)目用urllib2也能完成。
我們首先來(lái)初始化,在self.urls里,我們定義一些需要fetch的欄目。(比如言情,恐怖仙俠之類(lèi)的書(shū)就可以跳過(guò))。然后寫(xiě)一些正則表達(dá)式,供其他的method使用。
class fetchBook:
def __init__(self):
self.header = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0'}
self.urls = [
'http://txt.rain8.com/txtgw/',
'http://txt.rain8.com/txtzj/',
'http://txt.rain8.com/txtzx/',
'http://txt.rain8.com/txtsh/'
]
self.rePageIndex = re.compile('list_\d+_\d+.html')#得到欄目編號(hào)
self.rePageCount = re.compile('<strong>\d+</strong>')#得到頁(yè)面數(shù)目
self.reDownloadGet1 = re.compile('href=.http://txt.rain8.com/plus/xiazai_yfx.php?[^>]+')#得到下載鏈接
self.reGetTitle = re.compile('<title>.+</title>')#得到標(biāo)題
self.reGetAuthor = re.compile("</small><span>[^>]+")#得到作者名稱(chēng)
self.reBookGetNew = re.compile('')#得到書(shū)籍鏈接
self.reBookGetOld = re.compile('')
self.cnt = 0
STEP3.獲取所有的頁(yè)面
我們可以查看人生哲學(xué)源代碼??梢哉业娇偣驳捻?yè)數(shù)。

然后我們就能得到每一頁(yè)的數(shù)據(jù)。
代碼如下
def viewAllPage(self,url):
"""
函數(shù)功能為把該欄目下所有頁(yè)面全過(guò)一遍。
"""
req = requests.get(url,headers = self.header)
pageIndex = self.rePageIndex.findall(req.text)[0][5:7]
pageCount = int(self.rePageCount.findall(req.text)[0][8:-9])
urlToFetch = [url,'list_',pageIndex,'_','1','.html']
foldname = self.reGetTitle.findall(req.text)[0][7:]
foldname = foldname.encode('unicode_escape').decode('string_escape')
foldname = foldname.split('|')[0]
self.createDir(foldname)
for page in range(1,pageCount+1):
urlToFetch[4] = str(page)
url_to_get = ''.join(urlToFetch)#得到所有頁(yè)面的url
STEP4.得到下載鏈接
然后我們用上面寫(xiě)好的正則表達(dá)式,來(lái)匹配她的下載鏈接。
def fetchDownloadUrl(self,bookurl):
req = requests.get(bookurl,headers = self.header)
result = self.reDownloadGet1.findall(req.text)
result = result[0][6:-17]
authorname = self.reGetAuthor.findall(req.text)[0][14:-6].encode('unicode_escape').decode('string_escape')
req = requests.get(result,headers = self.header)
bookname = self.reGetTitle.findall(req.text)[0][7:-24]
downloadurl = self.reDownloadGet1.findall(req.text)[0][6:-17]
return downloadurl,bookname,authorname
STEP5.下載
下載的時(shí)候,由于該網(wǎng)站下載的書(shū)都是rar格式的。所以我們只要用二進(jìn)制的方式寫(xiě)就可以了。
我們調(diào)用
self.req = requests.get(downloadUrl,headers = self.header)
然后
f = open(posi+'/'+bookname+'.rar','wb')
就可以寫(xiě)進(jìn)去了。
STEP6.編碼問(wèn)題
之前一直被python的編碼問(wèn)題搞的頭大,這次又遇見(jiàn)了。于是找了點(diǎn)資料看了看。
因?yàn)閜ython工作使用的編碼是unicode,如果要在編碼間進(jìn)行轉(zhuǎn)化,推薦要先decode成unicode,然后再encode成別的編碼。
然后我在爬內(nèi)容的過(guò)程中碰到了這個(gè)問(wèn)題:
s = u'\xb9\xc5\xca\xab\xb4\xca\xc3\xfb\xd6\xf8'
\xb9這樣的很明顯應(yīng)該是gbk編碼。而python卻在字符串前加了個(gè)u。然后我對(duì)這串字符encode還是decode都會(huì)報(bào)錯(cuò)。或者打印出來(lái)亂碼。
經(jīng)過(guò)查閱資料,我找到了一種解決辦法
s.encode('unicode_escape').decode('string_escape')
經(jīng)過(guò)這樣處理后
>>> print repr(s)
>>> '\xb9\xc5\xca\xab\xb4\xca\xc3\xfb\xd6\xf8'
很明顯就恢復(fù)了正常。這時(shí)我們只要decode('gb2312')就能轉(zhuǎn)換成unicode編碼了。
STEP7.結(jié)果展示


github地址
喜歡的可以點(diǎn)一下喜歡。