下載漫畫的腳本
身爲漫畫迷,一直想直接將漫畫下載到電腦上看,於是就有這個python腳本。
系統:Ubuntu 14.04
python版本:2.7.6
用到的python庫有:
- os (操作系統接口的標準庫,用於創建文件)
- sys (標準庫,獲取命令行參數)
- string (字符串操作的標準庫,用於將字符串中的數值轉換爲整型)
- getopt (對命令行參數進行處理)
- lxml (當中的html,相當於Jsoup,這裏用於快速查找網頁的元素)
- requests (通過URL獲取網頁)
- urllib2 (作用和requests差不多)
其中非標準庫getopt、lxml、requests、urlslibs可以通過pip安裝。
思路:
- 選擇漫畫網站進行解析,顯示漫畫章節
- 選擇漫畫章節,找到本章漫畫圖片的路徑
- 按漫畫圖片的路徑下載到本地保存
要求:瞭解Python、XPath、URL、html即可。
步驟
1.解析漫畫章節列表
以納米漫畫網下的盤龍爲例(以前叫國漫吧,很多國漫都能看,我挺喜歡的,不過chromium卻顯示這網站有毒*=*,注意)
爲了方便下載,需要將漫畫的每個章節標題和相應的鏈接記錄下來。
查看章節列表的源碼,發現章節是用無序列表關聯的,查看其中一個章節的XPath,/html/body/div[2]/div[1]/div[2]/div[3]/ul/li[1]/a。但是每個章節的xpath都是不一樣的,我們不可能一個一個地計算,這時就要找到它們的共同點。
很明顯,可以用含class的xpath代替,xpath可以理解爲網頁元素的標識、位置。
這裏用//div[@class=”tab-content tab-content-selected zj_list_con autoHeight”]/ul[@class=”list_con_li autoHeight”]/li代替每個章節,
那麼章節標題就是
**//div[@class="tab-content tab-content-selected zj_list_con autoHeight"]/ul[@class="list_con_li autoHeight"]/li/a/span[@class="list_con_zj"]/text()**
,
章節的鏈接就是**//div[@class="tab-content tab-content-selected zj_list_con autoHeight"]/ul[@class="list_con_li autoHeight"]/li/a[@href]/@href**
代碼如下
#獲取漫畫的目錄
def getIndexLinkFromDirectory(comic_directory_url):
page = requests.get(comic_directory_url)
tree = html.fromstring(page.content)
comic_title = tree.xpath('//div[@class="comic_deCon"]/h3[1]/a/text()')
chapter_link = tree.xpath('//div[@class="tab-content tab-content-selected zj_list_con autoHeight"]/ul[@class="list_con_li autoHeight"]/li/a[@href]/@href')
chapter_title = tree.xpath('//div[@class="tab-content tab-content-selected zj_list_con autoHeight"]/ul[@class="list_con_li autoHeight"]/li/a/span[@class="list_con_zj"]/text()')
#print "Cretae directory"
return comic_title[0],chapter_link,chapter_title
主要就是以漫畫章節目錄網頁的URL作爲參數,並通過requests獲得這一網頁page,然後用html生成tree,在tree中可以通過xpath方便地獲取網頁元素,即章節標題和鏈接,以及漫畫名稱,並返回。
注意,python可以在一個函數中返回多個值,所以這裏依次返回漫畫名稱、章節標題數組和鏈接數組,其中後兩者有對應關係(同一下標的標題和鏈接相關)。
2.解析獲得漫畫圖片
以134話來看源碼
漫畫圖片的地址是http://cartoon.kdm8.com/?u=/manhuatuku/12757/manhua_12_20160225_2016022508144669474.jpg,我們要做的就是獲取這章節所有圖片的地址。爲了流暢快速,一般網站可能會將這些圖片地址保存到客戶端的瀏覽器中,也就是JS裏面。這時再看回網頁源碼,發現在某段的JS代碼裏就有,不過就是有點暈。
本頁的圖片地址和下一頁的圖片地址都在,很明顯這就是我們要的這一章的圖片地址了,這就方便下載。分析這段JS,可以發現在”page_url”的鍵值對裏面,而且以”|”分隔每個圖片地址。
代碼如下
#獲取一章節漫畫的鏈接
def getPictureUrls(data):
page_url = "\"page_url\":\""
if page_url in data:
index = data.find(page_url)
page_url = data[(index+len(page_url)):data.find("\"",index+len(page_url))]
return page_url.split("||")
主要是將requests獲得的網頁內容作爲參數data傳入,然後提取圖片地址,即”page_url”:”…..”這個鍵值對,然後在用”|”劃分爲地址數組並返回。
3.下載漫畫圖片到本地
通過上一步獲取圖片地址後,就可以通過其讀取圖片數據並保存到本地上。爲了方便,依次將圖片下載保存到以章節標題命名的文件夾中。
先嚐試直接下載是否被網站filter,有些網站會過濾掉這種外部請求
明顯能訪問,所以可行。
代碼如下
#下載漫畫到本地目錄中
def downloadPicture(pic_urls,base_directory):
total = len(pic_urls)
print "開始下載..."
for i in xrange(total):
print "Downloading %d in %d" % (i+1, total)
url = pic_urls[i].replace("\\","").replace("|","")
f = urllib2.urlopen(url)
data = f.read()
with open(base_directory+"/%03d.jpg" % i,"wb") as pic:
pic.write(data)
print "下載完成"
以圖片地址數組爲參數pic_urls,本地目錄名(圖片保存)爲參數base_directory,依次通過urllibs下載到base_directory中,並用格式化字符串按順序重命名。
注意,因爲linux系統下文件路徑以”/“爲分隔符,所以如果要在windows下適用,文件名(”/%03d.jpg”)也要相應修改。
4.查找漫畫
一開始總不能直接輸入漫畫的網址,因爲不知道的,所以就需要實現查找功能,即輸入漫畫名後在網站上進行查找。
看回這網站的查找界面,嘗試查找盤龍
可見網址的形式爲http://nmmanhua.com/search/?key=盤龍,那說明只要將搜索的漫畫名組成http://nmmanhua.com/search/?key=漫畫名再處理即可。
而搜索結果列表如圖
同理,漫畫的XPath是//span[@class=”comic_list_det”]/,那麼標題就爲//span[@class=”comic_list_det”]/h3/a/text(),鏈接就是//span[@class=”comic_list_det”]/a/@href。
代碼如下
#根據漫畫名查找,返回漫畫名和相應的鏈接
def searching(content):
print "查找中....."
search_url = "http://nmmanhua.com/search/?key="+content #調用漫畫網站進行搜索
page = requests.get(search_url)
tree = html.fromstring(page.content)
comic_title = tree.xpath('//span[@class="comic_list_det"]/h3/a/text()') #顯示漫畫名
comic_link = tree.xpath('//span[@class="comic_list_det"]/a/@href') #記錄漫畫的鏈接
print "查找完成"
return comic_title,comic_link
和第一步很相似,只是這裏返回漫畫標題數組和鏈接數組。
顯示
主要時通過上述處理後,獲得相應的相關數組,按順序顯示。
輸入相應的下標即爲選擇下載。
顯示搜索結果
搜索盤龍
代碼如下
#顯示漫畫搜索的結果
def showSearchResult(comic_title,comic_link):
for i in xrange(len(comic_title)):
print "%d.%-15s" % (i+1,comic_title[i])
print "共找到 %d" % len(comic_title)
引用searching(content)
後,格式化輸出。
顯示漫畫目錄
代碼如下
#顯示漫畫目錄
def showDirectory(comic_title,chapter_link,chapter_title):
print "Title : ",comic_title
for i in xrange(len(chapter_title)):
print "%3d.%-15s" % (i+1,chapter_title[i])
引用getIndexLinkFromDirectory(comic_directory_url)
後,格式化輸出。
下載第133話
顯示下載結果
下載自動保存到本地
下載後看漫畫
總結
- 只是CUI,沒有GUI。這個腳本爲命令行界面,目前只是對納米漫畫網進行查找、下載,不過道理一樣。
- 用getopt處理參數,可以添加更多如
-d 網址
的options,不過這裏只處理了-h
和-s
。 - 如果想同時用作圖片查看的話,可以使用python出名的PIL實現。
- 要跨平臺的話,就要修改文件名中的路徑分隔符才行。
Future
1. 想嘗試用Java實現,因爲Jsoup和lxml的html是一樣的道理,只是將xpath改用jquery表達式而已。
2. 寫一個Android端的app,也用於下載漫畫。現在困在怎樣異步獲取漫畫章節等信息並更新。