1. 程式人生 > >Python抓取網頁動態資料——selenium webdriver的使用

Python抓取網頁動態資料——selenium webdriver的使用

文章目的

當我們使用Python爬取網頁資料時,往往用的是urllib模組,通過呼叫urllib模組的urlopen(url)方法返回網頁物件,並使用read()方法獲得url的html內容,然後使用BeautifulSoup抓取某個標籤內容,結合正則表示式過濾。但是,用urllib.urlopen(url).read()獲取的只是網頁的靜態html內容,很多動態資料(比如網站訪問人數、當前線上人數、微博的點贊數等等)是不包含在靜態html裡面的,例如我要抓取這個bbs網站中點選開啟連結 各個板塊的當前線上人數,靜態html網頁是不包含的(不信你檢視頁面原始碼試試,只有簡單的一行)。像這些動態資料更多的是由JavaScript、JQuery、PHP等語言動態生成的,因此再用抓取靜態html內容的方式就不合適了。

解決思路

我嘗試過網上所說的用瀏覽器自帶的開發者工具(一般是F12彈出相應網頁的開發者工具),檢視網路可以獲得動態資料的走向,但這需要從眾多的url中找出蛛絲馬跡,個人覺得太麻煩了。另外,用檢視器檢視的html內容也是包含動態資料的,但這有幾個問題:怎麼實時獲取檢視器的html內容?怎麼將檢視器的html匯入python程式?因此利用檢視器的html內容的方法也是不符合抓取程式要求的。

而偶然間發現了selenium模組,發現這個模組可以很方便地根據url載入頁面獲得session,並找到當前session的相應標籤。本文將通過selenium webdriver模組的使用,以獲取這些動態生成的內容,尤其是一些重要的動態資料。其實selenium模組的功能不是僅僅限於抓取網頁,它是網路自動化測試的常用模組,在Ruby、Java裡面都有廣泛使用,Python裡面雖然使用相對較少,但也是一個非常簡潔高效容易上手的自動化測試模組。通過利用selenium的子模組webdriver的使用,解決抓取動態資料的問題,還可以可以對selenium有基本認識,為進一步學習自動化測試打下基礎。

實現過程

執行環境

我是在windows 7系統上安裝了Python 2.7版本,使用Python(X,Y)這個IDE,安裝好的Python庫沒有自帶selenium,在Python程式中直接import selenium會提示沒有這個模組,聯網狀態下cmd直接輸入pip install selenium,系統會找到Python的安裝目錄直接下載解壓並安裝這個模組。等到終端提示完成後可以看看,在C:\Python27\Lib\site-packages目錄下有沒有selenium模組,這個目錄取決於你安裝Python的路徑。如果有selenium和selenium-2.47.3.dist-info這兩個資料夾,代表模組可以在Python程式中被載入了。

使用webdriver抓取動態資料

1.先匯入webdriver子模組

from selenium import webdriver

2.獲得瀏覽器的session,瀏覽器用Firefox、Chrome、IE等都可以,這裡以Firefox為例

browser = webdriver.Firefox()

3.載入頁面,url自己指定一個合法的字串即可

browser.get(url)

4.獲得了session物件後,要定位元素,webdriver提供了一系列的元素定位方法,常用的有以下幾種方式:

id

name

class-name

link

text

partial

link

text

tag

name

xpath

cssselector

比如通過id定位,返回所有元素組成的list,lis=borwser.find_elements_by_id_name('kw'')

通過class-name定位,lis=find_elements_by_class_name('title_1')

更詳細的定位方式可以參考‘部落格園-蟲師’這個大神的selenium webdriver(python)教程的第三章-定位方式部分(第一版可在百度文庫閱覽,第二版開始就收費了>-<)

5.結合正則表示式過濾相關資訊

定位後的元素有些是不想要的,用正則過濾掉即可,比如我想只提取英文字元(包括0-9),建立下面的正則

pa=re.compile(r'\w+')

for u in lis:

    en=pa.findall(u.lis)

    print en

6.關閉會話

當執行完抓取操作後,必須關閉session,不然讓它一直佔記憶體會影響機器其他程序的執行

browser.close()或者browser.quit()都可以關閉session,前者只是關閉當前的session,瀏覽器的webdriver不關閉,後者則是包括webdriver這些東西全部shut down

7.加入異常處理

這是有必要的,因為有時會獲得session失敗,因此要把上述語句塊放入try裡面,然後exception處理異常

except NoSuchElementException:

     assert 0, "can't find element"

程式碼實現

我抓取了點選開啟連結 指定分割槽中各個板塊的線上人數,指定分割槽id號(0-9),可以獲得板塊名稱和對應的線上人數,形成列表打印出來,程式碼如下

# -*- coding: utf-8 -*-

from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException
import time
import re

def find_sec(secid):
    pa=re.compile(r'\w+')
    browser = webdriver.Firefox() # Get local session of firefox
    browser.get("http://bbs.byr.cn/#!section/%s "%secid) # Load page
    time.sleep(1) # Let the page load
    result=[]
    try:
        #獲得版面名稱和線上人數,形成列表
        board=browser.find_elements_by_class_name('title_1')
        ol_num=browser.find_elements_by_class_name('title_4')
        max_bindex=len(board)
        max_oindex=len(ol_num)
        assert max_bindex==max_oindex,'index not equivalent!'
        
        #版面名稱有中英文,因此用正則過濾只剩英文的
        for i in range(1,max_oindex):
            board_en=pa.findall(board[i].text)
            result.append([str(board_en[-1]),int(ol_num[i].text)])
            
        browser.close()
        return result
    except NoSuchElementException:
        assert 0, "can't find element"

#列印分割槽5下面的所有板塊的當前線上人數列表        
print find_sec('5')

執行結果如下:


總結

無論是從程式碼行數還是執行效率上看,selenium都非常優秀,用selenium webdriver抓取動態資料非常簡潔高效,進一步地利用這個實現資料探勘、機器學習等深層研究也是可以的,因此selenium+python是很值得深入學習的!