雖然自2018年開始,PhantomJS暫停開發,而且新版本Selenium不再支持PhantomJS,而是推薦使用谷歌或者火狐無界面瀏覽器,但是現在仍然可以使用Selenium+PhantomJS,只是warning而已。
這裏有篇博客以供參考:https://blog.csdn.net/u010358168/article/details/79749149
Selenium模擬瀏覽器
Python網絡爬蟲中最麻煩的就是那些通過JavaScript獲取數據的站點。Python對JS的支持不太好,想用Python獲取網站中JavaScript返回的數據,唯一的方法就是模擬瀏覽器了。
安裝Selenium模塊
Selenium是一套完整的Web應用程序測試系統,其核心Selenium Core基於JsUnit,完全由JavaScript編寫,因此可運行於任何支持JavaScript的瀏覽器上。
Windows下安裝Selenium模塊:
python -m pip install -U selenium
在編寫Python網絡爬蟲的時候,主要用到Selenium的Webdriver。Selenium.Webdriver不可能支持所有瀏覽器,查看Webdriver支持列表,打開cmd執行命令:
python
from selenium import webdriver
help(webdriver)
執行結果:
可以看出所支持的瀏覽器,其中PhantomJS是一個基於WebKit的服務端JavaScript API。它全面支持 Web而不需瀏覽器支持,其快速原生支持各種Web標準:DOM處理、CSS選擇器、JSON、Canvas和SVG。PhantomJS可用於頁面自動化、網絡監測、頁面截屏以及無界面測試等。
無界面意味着開銷小速度快,以前網上有牛人測試過,使用Selenium調用上面的瀏覽器,速度前三分別是PhantomJS、Chrome、IE,現在呢Chrome和Firefox推出了無界面瀏覽器,所以Selenium開始推薦使用Chrome和Firefox的無界面瀏覽器了。(但本文還是使用PhantomJS)
Windows下安裝PhantomJS
進入PhantomJS官網下載頁:https://phantomjs.org/download.html,Download V2.1(這是官方認定的暫停開發前最穩定的版本),下載完成後解壓,將.exe文件複製到Python的目錄中就行了。(需要將.exe文件加入到系統路徑中,由於Python已經加入到系統路徑中且是配合Python使用的,所以乾脆將其放到Python目錄中就可以了。)
Selenium+PhantomJS抓取數據
首先要引入Selenium.Webdriver,連接PhantomJS:
from selenium import webdriver
browser = webdriver.PhantomJS()
然後三步走:
1、獲取頁面響應內容。
browser.get(url) #get方法請求網頁
browser.implicity_wait(10)
# PhantomJS解釋瀏覽器是需要時間的,給implicity_wait()一個時間參數,
# implicity_wait()會智能等待,只要解釋完成了就進行下一步操作。
# 當然可以使用time.sleep()強行休眠一段時間,但是時間不好掌握。
html = browser.page_source #獲取返回的數據可以使用page_source方法
2、定位要爬取的數據。
定位html標籤元素selenium含有以下18個函數:
可以對定位的元素進行操作,即模擬瀏覽器操作:
#定位到百度首頁的輸入框
textElement=browser.find_element_by_id('kw')
#向輸入框裝填數據
textElement.send_keys('Python selenium')
#定位到提交按鈕
submitElement=browser.find_element_by_id('su')
#對該元素執行點擊操作
submitElement.click()
selenium常用函數:https://blog.csdn.net/poppy3163/article/details/78044122
3、獲取要爬取的數據。
element.text #獲取element標籤裏的文字
element.get_attribute(name) #獲取element中某個屬性值
爬取極速漫畫實戰:
極速漫畫網址:http://www.1kkk.com/
隨便找一篇漫畫《我的男友風淨塵》,進入第一章第一頁:http://www.1kkk.com/ch1-866831/#ipg1
想要爬取第一章的漫畫保存在自定義的文件夾裏。
from selenium import webdriver
import logging
import os
import time
import requests
import codecs
class getCartoon(object):
#可以理解爲構造函數
def __init__(self):
self.startUrl='http://www.1kkk.com/ch1-866831/#ipg1'
self.browser=self.getBrowser() #獲取網頁
self.saveCartoon(self.browser) #定位內容,保存漫畫
#獲取網頁
def getBrowser(self):
browser=webdriver.PhantomJS()
try:
browser.get(self.startUrl)
browser.implicitly_wait(10)
except:
logging.error('open the url failed')
return browser
#保存漫畫
def saveCartoon(self, browser):
cartoonTitle=browser.title.split('_')[0] #獲取網頁title以_分割,取出分割後數組第一個賦給cartoonTitle變量
self.createDir(cartoonTitle) #新建文件夾,以cartoonTitle爲名
os.chdir(cartoonTitle) #將輸入流切換到當前路徑
sumPage=int(browser.find_element_by_xpath('//*[@id="chapterpager"]/a[8]').text) #獲取該章節的頁數
i=1
#循環一頁一頁地爬
while i<=sumPage:
imgName=str(i)+'.png'
imgElement=browser.find_element_by_xpath('//*[@id="cp_image"]') #匹配到漫畫圖片的<img>元素
imgUrl=imgElement.get_attribute('src') #獲取<img>標籤裏的src屬性值,即圖片鏈接
print(imgUrl)
#使用requests請求imgUrl
response=requests.get(imgUrl)
with codecs.open(imgName,'ab') as fp:
fp.write(response.content)
logging.info('save img %s' %imgName)
i+=1
#模擬點擊下一頁
nextTag=browser.find_element_by_xpath('/html/body/div[7]/div/a[2]')
nextTag.click() #模擬點擊操作
browser.implicitly_wait(20) #等待加載頁面
time.sleep(5)
logging.info('save img successs')
exit()
#創建新路徑,新建文件夾
def createDir(self, dirName):
if os.path.exists(dirName):
logging.error('create directory %s failed, have a same name file or directory' %dirName)
else:
try:
os.makedirs(dirName)#新建文件夾
except:
logging.error('create directory %s failed' %dirName)
else:
logging.info('create directory %s success' %dirName)
if __name__=='__main__':
getCartoon()
查看爬取結果:
發現,這個網站在防盜鏈上做的很到位,只要在頁面上執行一次刷新操作,網站就判爲盜鏈,顯示出防止盜鏈的圖片,並且得到的圖片鏈接地址也無法下載。
所以乾脆我就截圖保存下來,不下載了:
將下載圖片文件的操作:
imgElement=browser.find_element_by_xpath('//*[@id="cp_image"]') #匹配到漫畫圖片的<img>元素
imgUrl=imgElement.get_attribute('src') #獲取<img>標籤裏的src屬性值,即圖片鏈接
print(imgUrl)
#使用requests請求imgUrl
response=requests.get(imgUrl)
with codecs.open(imgName,'ab') as fp:
fp.write(response.content)
logging.info('save img %s' %imgName)
換成對整個頁面截屏的操作:
browser.get_screenshot_as_file(imgName) #對整個頁面進行截圖存爲圖片
再次運行:
成功。