目前只實現(xiàn)了下載文本內(nèi)容,,其中少數(shù)的幾張插圖被過濾掉了,,爭取本周內(nèi)優(yōu)化一個版本把插圖也補上
在「百度閱讀」上購買了一本《創(chuàng)新公司:皮克斯的啟示》電子書,但坑爹的發(fā)現(xiàn)百度閱讀 APP 的體驗實在渣,。于是就想看看是不是可以把電子書爬下來,,放到 kindle 里面讀。
一開始以為這本書就是睡前讀物
沒讀一會就發(fā)現(xiàn)這貨絕對是管理方法干貨
尤其是對需要創(chuàng)造性的團(tuán)隊管理
創(chuàng)新公司:皮克斯的啟示
[美] 艾德·卡特姆 / 埃米·華萊士 著
靳婷婷 譯
中信出版社
2015 年 2 月
接下來進(jìn)入正題,,如何使用 Python 爬取「百度閱讀」中的內(nèi)容,。
環(huán)境準(zhǔn)備
- Python 2.7.6:我偷懶用的是 MacBook Pro 系統(tǒng)自帶的版本
- requests 庫: 用于獲取「百度閱讀」返回的數(shù)據(jù)。安裝傳送門
抓取過程
整個過程大概分三個部分:
- 抓取數(shù)據(jù)
- 解析數(shù)據(jù)
- 組裝存儲數(shù)據(jù)
1 抓取數(shù)據(jù)
一開始我想簡單了,,以為「百度閱讀」的數(shù)據(jù)都是寫在靜態(tài)頁面里的(如果不是低估這個事情的復(fù)雜度,,我應(yīng)該就不會做這個事情了)。然后__查看源碼__一看傻眼了,,電子書的數(shù)據(jù)是異步加載過來的,。
我 Google 了好一陣技能:
在 Chrome 中用 contrl + command + i 打開「開發(fā)者工具」,切換到 network 下刷新「百度閱讀」,,逐一查看 XHR 和 script 兩個類,。
在 script 分類下有個 jsonp 請求是電子書內(nèi)容,請求的地址是:
http://wenku.baidu.com/content/49422a3769eae009581becba?m=8ed1dedb240b11bf0731336eff95093f&type=json&cn=1&_=1&t=1423309200&callback=wenku7
如果把地址里面的 callback=wenku7 去掉,,返回的就是一個 json 字符串,,這樣解析起來就簡單多了。
2 解析數(shù)據(jù)
get 到這些信息后,,就可以利用 requests 獲取 json 數(shù)據(jù),,把數(shù)據(jù)打印處理研究后發(fā)現(xiàn),json 的節(jié)點主要是 t 屬性 和 c 屬性,,t 屬性是用來定義 html 標(biāo)簽的,,例如 div 、 p,、 h 等等,。而電子書的內(nèi)容都在 c 屬性內(nèi)。
但 C 屬性的值有兩種類型,,一種就是電子書內(nèi)容,,另一種則是另一個列表,,里面又包含了 t 屬性和 c 屬性(嵌套關(guān)系)。
對于這種簡單的嵌套關(guān)系關(guān)系使用遞歸函數(shù)基本就解決了,。
3 組裝存儲數(shù)據(jù)
解析完 json 的結(jié)構(gòu),,直接用 file.write() 講電子書的內(nèi)容保存為本地的 .txt 文件。然后再用一個比較好用的電子書轉(zhuǎn)換工具:「calibre」,,將.txt 文件轉(zhuǎn)成 .mobi 和 .epub 格式,。
至此整個過程就結(jié)束了,完整的代碼如下(因為隱私原因隱藏了 cookie 信息),。
#coding: utf8
import requests
import json
def getConnected(page): #連接百度閱讀,,獲取 json 數(shù)據(jù)
url ='https://wenku.baidu.com/content/ebookID'
header = {
'User-Agent' : 'Mozilla/5.0 ……',
'Cookie' : baiduID
}
data = {
'm': ebookToken,
'type': 'json',
'cn': page, #一共17頁
}
r = requests.get(url, headers = header, params = data)
parseDom(r.json())
def parseDom(json_dict): #解析 json 樹,獲取電子書內(nèi)容
ebook = open('~/chuangxingongsi.txt', 'a')
if isinstance(json_dict, dict):
for item in json_dict:
if item == 't':
print 'tag is : %s' % json_dict[item]
elif item == 'style':
print 'style is : %s' % json_dict[item]
elif item == 'blockNum':
print 'blockNum is : %s' % json_dict[item]
…… #為了減少篇幅,,刪除了部分標(biāo)簽,,完全不影響文本內(nèi)容的抓取
elif item == 'c':
if isinstance(json_dict[item], list):
for sub_item in json_dict[item]:
parseDom(sub_item)
else:
print 'content is : '
print json_dict[item].encode('utf8')
ebook.write(json_dict[item].encode('utf8'))
else:
print json_dict.keys()
else:
print 'something is wrong!'
ebook.close()
def crawlContent():
for page in xrange(1,18):
getConnected(page)
if __name__ == '__main__':
crawlContent()
|