小喵的嘮叨話:此次的博客,講的是使用python編寫一個爬蟲工具。爲何要寫這個爬蟲呢?緣由是小喵在看完《極黑的布倫希爾特》這個動畫以後,又想看看漫畫,結果發現各大APP都沒有資源,最終好不容易找到一個網站能夠看,可是因爲網速太渣,看起來額外的費勁。這時候若是能提早下載下來就行了。javascript
先上項目地址(github):https://github.com/miaoerduo/cartoon-cat 。歡迎你們隨時fork、star和指教。css
本文系原創,轉載請註明出處~html
小喵的博客:http://www.miaoerduo.com前端
博客原文:http://www.miaoerduo.com/python/爬蟲-漫畫喵的100行逆襲.htmljava
緣由就是這樣,做爲技術喵,任何問題都不能阻礙一顆愛漫畫的心。因此問題就來了,挖掘機技修哪家強?python
在bing上搜索Python、爬蟲框架。找到你們經常使用的框架。git
Scrapy彷佛是個很不錯的選擇。至於相對於其餘框架的優勢,小喵沒有細查,至少這個框架是以前聽過的。可是在實現的時候發現有一些問題,scrapy不能直接抓取動態的頁面。小喵須要抓取的網站的漫畫都是使用Ajax生成的。須要本身分析各類數據,這個有點麻煩。github
那麼有沒有能夠渲染頁面的工具呢?像瀏覽器同樣的?有。web
這裏介紹兩個工具:ajax
PhantomJs,能夠理解是一個瀏覽器。不過它沒有界面,咱們能夠經過js的代碼模擬用戶的行爲。這就要求瞭解它的api並有js基礎了。
Selenium,這是個瀏覽器自動化測試框架。它依賴於瀏覽器(這個瀏覽器也能夠是PhantomJs),經過Selenium能夠模擬用戶的行爲。並且有Python接口,因此相對簡單一些。
咱們這個爬蟲使用selenium + phantomjs來實現。
喲,這個爬蟲軟件應該有個響噹噹的名字。。。就叫 漫畫喵 吧,英文名Cartoon Cat。
下面咱們一點點的介紹這個爬蟲的實現過程吧。
小喵這裏選用Python做爲開發語言,框架是selenium。緣由是python常常用來寫爬蟲,selenium能夠用來模擬用戶行爲,PhantomJs是可選的,不太小喵最終會在一個服務器上運行,因此也是須要的。
爲了避免影響本機上的python,咱們還須要使用virtualenv來建立一個獨立的python環境。具體步驟以下:
virtualenv是一個經常使用的用來建立python環境的工具。小喵用這個有兩個緣由,一是爲了避免污染本機的環境,二是在本機直接安裝庫的時候出了一個權限的問題。
virtualenv的安裝十分簡單,使用pip工具就能夠安裝。
pip install virtualenv
待程序執行結束,你就會開心的發現本身已經有了virtualenv這個工具了。
virtualenv的使用很是的方便。
創建新的運行環境:virtualenv <env-name>
進入相應的獨立環境:source <env-path>/bin/activate
執行完第一個指令後,就會建立成功一個python環境,執行第二個指令後,就會發現命令行的起始位置有變化。這時候python、pip等工具就變成使用這個新環境的了,固然也可使用which python
來查看。
進入新環境後,pip安裝的依賴庫都會在新環境中安裝,不會影響主機自身的python。使用pip 安裝selenium:
pip install selenium
至此,咱們的基本環境就搭建完了。
這個只在從官網上下載就能夠:http://phantomjs.org/download.html
小喵的本地實驗環境是Mac,因此下載了Mac版本。解壓以後就可使用。
小喵想看的這個漫畫貌似各大網站都沒有資源,在費了九牛二虎之力後,終於找到了一個網站!http://www.tazhe.com/mh/9170/。
每一個網站的結構都不相同,所以都須要定製一套爬蟲程序。本文的爬蟲就只能針對這個漫畫網站使用,喵粉們須要爬其餘網站的話,須要本身作相應的修改。
這裏須要解析兩個頁面,一個是漫畫的首頁,好比前面的:http://www.tazhe.com/mh/9170/
另外一個就是具體章節的頁面。
爲了減少圖片的大小,小喵把窗口作了縮放。首頁大體是這個樣子。
圖1 漫畫首頁
各種信息十分的明瞭。咱們關注的就是下面的漫畫列表。經過Chrome強大的審查元素的功能,咱們馬上就能定位到章節的位置。(對着感興趣的位置->右鍵->審查 就能找到)
圖2 章節的節點
能夠看到,章節所在的區域的id
是play_0
,學過前端的童鞋都應該知道,一個頁面中id
一般惟一標示一個節點。所以若是咱們可以獲取這個頁面的話,查找id
爲play_0
的節點就能一會兒縮小搜索範圍。
而每一個章節的信息都是一個a
標籤,標籤的href
是對應章節的具體網址,標籤的文本部分是章節名。這樣相對關係就得出了:div#play_0 > ul > li > a
。
首頁的分析就到此結束。
咱們隨意打開一個具體章節的頁面。好比:http://www.tazhe.com/mh/9170/1187086.html
引入眼簾的是一個很乾淨的頁面(簡直是漫畫界的清流,好多漫畫網站上所有是廣告)。
咱們把鼠標放在圖片這個區域->右鍵->審查。
咦,咱們的右鍵怎麼按不了?
其實呢,這個現象在小說網站上遇到的機會會更多。當咱們看到比較優美的文字或是炫酷的圖片,都會下意識的選中->右鍵->保存。而不少時候,這些資源都是有版權的。並不該該隨意的傳播(狠狠的打了本身的臉/(ㄒoㄒ)/~~)。所以限制鼠標右鍵會是一個很簡單卻有效的辦法。
那麼咱們如何繞過這個陷阱呢?
很簡單,咱們不用右鍵便可。打開瀏覽器的開發者工具選項,找到elements這個選項。能夠看到一個複雜的結構(其實和上面審查元素以後的結果同樣)。以後不斷的選中標籤,當標籤被選中時,左側頁面中對應的位置會有藍色。多試幾回,最終就能找到對應的位置。
圖3 漫畫圖片
這是一個img
標籤,對應的id
是qTcms_pic
。這樣找到這個id
,就能找到這個img
標籤,根據src
就能找到圖片的具體URI地址。
接下來是找到下一張圖片的地址。這時候須要查看下一頁這個按鈕的內容。用相同的方法,很容易定位成功。
圖4 下一頁
小喵原本是用scrapy來作爬蟲的,看到這裏的時候就果斷放棄了。咱們分析一下,選中的a
標籤的代碼以下:
<a class="next" href="javascript:a_f_qTcms_Pic_nextUrl_Href();" title="下一頁"><span>下一頁</span></a>
比較簡單的網站,「下一頁」能夠用真的a
標籤和href
屬性來作。這樣的好處是實現比較簡單,壞處是一旦獲得網頁源碼就能很容易的解析。而像scrapy這樣的爬蟲工具只能抓取靜態的代碼(動態的須要本身分析ajax,有點麻煩)。而顯然這裏的頁面是動態的,使用了ajax來實現。因此光是獲得網頁源碼並不能真的獲得圖片,而是必須讓其中的js代碼運行才能夠。因此咱們才須要使用瀏覽器或者PhantomJs這樣的能夠執行js代碼的工具。
上面的a
標籤的代碼告訴了咱們不少信息。首先是告訴了咱們,這個節點的位置,經過next
這個類名能夠方便的找到該節點(其實有兩個類名爲next
的按鈕,另外一個在下面,可是功能都同樣)。其次,當這個按鈕被點擊時會調用:a_f_qTcms_Pic_nextUrl_Href()
這個js函數。難道咱們須要再研究這個函數?
不用。由於PhantomJs的角色就是一個瀏覽器。咱們只須要向真正的用戶同樣點擊一下這個next
按鈕,就會進入下一個頁面。/* 感覺到這個工具的強大了嗎? */
最後一個問題就是,如何判斷這個章節結束了?
咱們跳到章節的最後一頁,而後再次點擊「下一頁」,這時候會出現一個彈窗。
圖5 最後一頁
屢次試驗以後,咱們會發現,只有在最後一頁的時候纔會彈出這個彈窗,這樣的話,咱們每抓取完一頁,點擊一次「下一頁」,判斷有無彈窗就知道是否是最後一頁了。在右側的開發者工具中咱們可以看到,這個彈窗是一個id
爲msgDiv
的div
(並且它的出現和消失是經過增減節點來實現的,另外一種實現方法是將display
設成none
和block
,這種狀況能夠根據display的屬性來判斷)。因此咱們判斷這個節點存不存在就好了。
至此,兩種頁面的解析都完成了。下一步就開始咱們的代碼實現吧。
from selenium import webdriver browser = webdriver.Firefox() # browser = webdriver.Safari() # browser = webdriver.Chrome() # browser = webdriver.Ie() # browser = webdriver.PhantomJs() browser.get('http://baidu.com') print browser.title # do anything you want
上面是一個簡單的例子,第一步import依賴的庫。
第二步,得到一個瀏覽器實例。selenium支持多種瀏覽器。使用firefox以外的瀏覽器都須要下載驅動(selenium自己自帶了firefox的驅動)。驅動下載地址:https://pypi.python.org/pypi/selenium 。驅動下載完以後將它的路徑加入到PATH裏,確保驅動程序可以被訪問到。或者顯式的把驅動程序的地址當參數傳入。像下面同樣調用:
browser = webdriver.PhantomJs('path/to/phantomjs')
第三步,用get的方式打開網頁。
最後,經過browser對象來解析和處理頁面。
在上面的解析頁面的時候,咱們知道了章節信息的位置:div#play_0 > ul > li > a
。這樣就能夠解析出章節信息。browser支持一大堆的選擇器。大大簡化咱們查找節點的工做。
from selenium import webdriver if __name__ == "__main__": driver = "path/to/driver" # 驅動地址 browser = webdriver.PhantomJS(driver) # 瀏覽器實例 main_page = "http://www.tazhe.com/mh/9170/" browser.get(main_page) # 加載頁面 # 解析出章節的元素節點 chapter_elem_list = browser.find_elements_by_css_selector('#play_0 ul li a') # 經過css選擇器找出章節節點 chapter_elem_list.reverse() # 本來的章節是倒敘的 chapter_list = [] for chapter_elem in chapter_elem_list: # 元素的text和href屬性分別就是章節的名稱和地址 chapter_list.append((chapter_elem.text, chapter_elem.get_attribute('href'))) # chapter_list 就是章節的信息
這一步涉及到節點的獲取、模擬鼠標的點擊以及資源的下載。selenium的點擊實現特別的人性化。只須要獲取節點而後調用click()
方法就搞定。資源的下載網上有許多教程,主要有兩個方法,經過模擬右鍵另存爲,和獲取url用其餘工具下載。考慮到這裏的右鍵不必定可用,並且操做有一點點複雜。小喵選用了第二種方案。
from selenium import webdriver from selenium.common.exceptions import NoSuchElementException import os from os import path as osp import urllib # 一個簡單的下載器 download(url, save_path): try: with open(save_path, 'wb') as fp: fp.write(urllib.urlopen(url).read()) except Exception, et: print(et) if __name__ == "__main__": driver = "path/to/driver" # 驅動地址 browser = webdriver.PhantomJS(driver) # 瀏覽器實例 chapter_url = "http://www.tazhe.com/mh/9170/1187061.html" save_folder = "./download" if not osp.exists(save_folder): os.mkdir(save_folder) image_idx = 1 browser.get(chapter_url) # 加載第一個頁面 while True: # 根據前文的分析,找到圖片的URI地址 image_url = browser.find_element_by_css_selector('#qTcms_pic').get_attribute('src') save_image_name = osp.join(save_folder, ('%05d' % image_idx) + '.' + osp.basename(image_url).split('.')[-1]) download(image_url, save_image_name) # 下載圖片 # 經過模擬點擊加載下一頁,注意若是是最後一頁,會出現彈窗提示 browser.find_element_by_css_selector('a.next').click() try: # 找尋彈窗,若是彈窗存在,說明這個章節下載完畢,這個大循環也就結束了 browser.find_element_by_css_selector('#bgDiv') break except NoSuchElementException: # 沒有結束彈窗,繼續下載 image_idx += 1
至此,漫畫喵的設計思路和主要的代碼實現都介紹完了。上面的代碼只是用來示意,小喵本身下載漫畫用的代碼是另外一套。github的地址是:https://github.com/miaoerduo/cartoon-cat 。項目只有100多行。不過也用了小喵很多的一段時間。
博客寫完了~小喵的漫畫也下完了~
圖6 下載好的漫畫
若是您以爲本文對您有幫助,那請小喵喝杯茶吧~~O(∩_∩)O~~
轉載請註明出處~