1. 程式人生 > >python爬蟲的最佳實踐(五)--selenium+PhantomJS的簡單使用

python爬蟲的最佳實踐(五)--selenium+PhantomJS的簡單使用

Ps:又到了我們的ps環節,不知道上次大家嘗試的如何,這次我們將簡單介紹如何使用selenium+PhantomJS來抓取非同步載入的網頁資料資訊。當然,selenium是一個非常強大的自動化工具,可以做非常多的事,有興趣的同學可以自行了解一下。

這次我們的順序稍稍變化一下,因為牽扯到配置環境。

環境配置

  • selenium
    pip install -U selenium
    建議採用pycharm安裝,別忘了我們這個強大的IDE
  • PhantomJS  (類似與Chrome、Firefox瀏覽器級別,可以看做是一個沒有介面的輕量瀏覽器)
    這個不同的作業系統有各自對應的版本,這是官網的下載頁面http://phantomjs.org/download.html
    ,去下載你對應作業系統版本的phantomjs.下載完後,解壓縮可以看到在資料夾的bin目錄下有對應的phantomjs的可執行檔案,拷貝一份放入一個環境變數可以搜尋到的地方,或者直接把phantomjs的bin目錄加入環境變數即可~

簡單介紹一下PhantomJS,這是一個基於webkit的沒有介面的瀏覽器,也就是它可以像瀏覽器解析網頁,功能非常強大。但是據我測試。。解析的結果不一定和火狐或者chrome完全一樣,但是完全夠我們用。
簡單介紹一下selenium,這是一個web的自動測試工具,可以模擬人的操作。支援市面上幾乎所有的主流瀏覽器,同時也支援PhantomJS這種無介面瀏覽器。

因為selenium+Firefox或者Chrome太慢了,所以我們選用selenium+PhantomJS。
想試試selenium+Firefox的同學直接下載最新版的Firefox即可,不需要外掛,但是chrome的話需要一個外掛叫chromedriver,我會放到群裡,閒話不多說,gogogo!

程式碼預覽

#coding:utf-8
import unittest
from selenium import webdriver
from bs4 import BeautifulSoup


class seleniumTest(unittest.TestCase):
    def setUp(self):
        self.driver = webdriver.PhantomJS()

    def testEle(self):
        driver = self.driver
        driver.get('http://www.douyu.com/directory/all')
        soup = BeautifulSoup(driver.page_source, 'xml')
        while True:
            titles = soup.find_all('h3', {'class': 'ellipsis'})
            nums = soup.find_all('span', {'class': 'dy-num fr'})
            for title, num in zip(titles, nums):
                print title.get_text(), num.get_text()
            if driver.page_source.find('shark-pager-disable-next') != -1:
                break
            elem = driver.find_element_by_class_name('shark-pager-next')
            elem.click()
            soup = BeautifulSoup(driver.page_source, 'xml')

    def tearDown(self):
        print 'down'

if __name__ == "__main__":
    unittest.main()

小夥伴們是不是驚奇的發現今天的程式碼怎麼略不一樣了~因為今天除了爬蟲相關,順道教大家一些python 的小知識~

程式碼剖析

import unittest
什麼是unittest呢?看字面意思估計大部分人已經懂了,就是單元測試的意思,這個庫是python自帶的給我們提供測試用的庫,很好用,今天我順道介紹一下這個庫的簡單使用。
今天的這段程式碼是一個簡單的測試用例
class seleniumTest(unittest.TestCase):
繼承TestCase類,表明這是一個測試類。setup方法是初始化方法,在unittest的main方法呼叫之初執行,然後tearDown是在測試完成的時候執行,中間的每個方法必須以test開頭。這是一些簡單的規則,大概瞭解之後我們就可以開心的使用單元測試了~

def setUp(self):
      self.dirver = webdriver.PhantomJS()

首先在我們的setup方法中初始化我們的webdriver,如果你用的是pycharm就可以看到webdriver後面會有多種方法,可以建立火狐的,chrome等各種瀏覽器的webdriver。

初始化完成之後開始解析,今天我們抓取鬥魚tv的房間資訊,用瀏覽器開啟http://www.douyu.com/directory/all,然後選擇檢視網頁原始碼,發現竟然可以直接在原始碼中看到房間資訊,心中一喜,難道不是非同步的方式麼?這太好抓了,直接requests請求然後分析就可以了啊。緊接著再點開第二頁,檢視網頁原始碼。發現竟然和第一頁一模一樣,頓時失望,依然是採用的js非同步的方式來載入資料的,只不過這次返回的不是json格式而直接是html。難道我們需要像上一章那樣麼?nono,今天我們直接使用PhantomJS模擬瀏覽器的訪問過程,然後通過dirver.get方法獲取瀏覽器載入完成後的原始碼。這樣子無論是否非同步,我們取到的source都是和我們在瀏覽器中看到的完全一樣。是不是感覺簡便了很多呢?

dirver.get('http://www.douyu.com/directory/all')
soup = BeautifulSoup(dirver.page_source, 'xml')

這兩句想必大家也能理解了,其實就是換了一種方式去獲取到網頁原始碼而已。這次連帶js渲染出來的網頁也都獲取到了。接下來

 titles = soup.find_all('h3', {'class': 'ellipsis'})
 nums = soup.find_all('span', {'class': 'dy-num fr'})
 for title, num in zip(titles, nums):
      print title.get_text(), num.get_text()

這段程式碼是在原始碼中取出我們想要的資訊,可能同學們也發現了,這和我們第三節講的不太一樣,這是因為我們的解析方式換成了xml而不是原本的lxml了,lxml屬於一種更加高效的解析模式,但是我為什麼要更換呢。因為在我寫這段程式碼的時候發生了一個小插曲,原本我也是用lxml的方式去解析的,但是發現每次只能解析出來32條資訊,但是很明顯鬥魚每個小分頁裡最少都有100多個房間,我查看了driver返回的page_source,發現沒有問題,於是我想可能是beautifulsoup的解析出了問題,列印soup,發現只有原始碼的一半,後面一半莫名奇妙丟失了。原本我以為是網頁中有多個</html>標籤導致解析出錯,後來發現也不是這個問題,百度google很久也沒有結果,所以只能換一種解析模式,當我換成xml的時候發現解析無誤。暫時我也不知道原因,有興趣的同學可以嘗試解決一下這個問題。

那麼上面這段程式碼取出了我們需要的資訊,beautifulsoup的find方法要是不瞭解的話可以參看官方文件。接下來:

elem = driver.find_element_by_class_name('shark-pager-next') 
elem.click() 
soup = BeautifulSoup(driver.page_source, 'xml')

第一行程式碼是webdriver裡面帶有的定位標籤的方法,我們通過觀察發現鬥魚頁面中下一頁這個標籤只出現一次,並且是獨立樣式,所以我們直接通過class進行定位,取到這個控制元件,然後執行element的click()方法模擬滑鼠點選,這樣,頁面就自動跳到了下一頁,接著繼續解析網頁原始碼。

if driver.page_source.find('shark-pager-disable-next') != -1: 
      break

這段程式碼是跳出迴圈用的,什麼時候跳出迴圈呢?我們通過觀察發現,當到最後一頁時候鬥魚下一頁的標籤就會變灰,如圖所示:


STU5R92IEHAZ{881KZ(72LD.png

於是,我們發現了有個唯一的shark-pager-disable-next樣式,那麼我們只需要在原始碼中找這個樣式,如果有則說明已經解析到最後一頁,直接跳出迴圈結束程式就好~

至此,今天的程式碼就講解完畢了。有沒有覺得比上次的觀察法方便了很多呢?附帶一提,有興趣的通許可以吧今天程式碼中self.dirver = webdriver.PhantomJS()換成self.dirver = webdriver.Firefox(),看看會發生什麼有趣的事情,我就不劇透了~

寫在最後

慣例了,demo已經給你們了,也講解完畢,現在需要你們自己實踐了,去嘗試抓取一下其他TV吧,推薦抓一下戰旗,因為載入方式又和鬥魚完全不一樣了,有挑戰性點~下一節我們講解如何在爬蟲中使用多程序!

附加部分

一些seleium的小互動操作

  • 填入表單資料
#coding:utf-8
from selenium import webdriver
from selenium.webdriver.common.keys import Keys

driver = webdriver.Firefox()
driver.get('https://www.baidu.com/')
elem = driver.find_element_by_id('kw')
elem.send_keys(u'爬蟲')
elem.send_keys(Keys.RETURN)
print(driver.page_source)
  • 滾動致頁面最下方
#coding:utf-8
from selenium import webdriver
import time

driver = webdriver.Firefox()
driver.get('http://www.jianshu.com/collections')
time.sleep(1)
for i in range(10):
    dirver.execute_script('window.scrollTo(0,document.body.scrollHeight)')
    time.sleep(1)

使用selenium模擬人的操作行為,這次換成了火狐瀏覽器,可以看得更加清楚~