selenium 是一個web的自動化測試工具,支持多平臺:windows、linux、MAC ,支持多瀏覽器:ie、ff、safari、opera、chrome,支持多語言:例如C、JAVA、Python等,支持分佈式測試用例的執行,可以把測試用例分佈到不同的測試機器的執行,相當於分發機的功能。
雖然Selenium本來是應用於自動化測試領域,但是因爲Selenium可以實現Web交互操作,所以可以利用Selenium模擬Web抓取一些常規方式不能抓取的數據,例如一些頁面生成後纔會動態加載的數據,或者需要登錄後才能訪問的數據。
下面以獲取某股票網站的板塊行情數據爲例子,介紹Python結合Selenium模擬網頁抓取數據的方法:
1、首先配置Python + Selenium環境
(1)訪問http://www.python.org/download/去下載合適的python版本,推薦3.4或2.7版本。
(2)安裝下載包,一路next。
(3)把python的安裝目錄添加到path系統變量中即可。
(4)測試python安裝是否成功,cmd打開命令行輸入 python命令,如下圖即成功了
(5)安裝PIP、SetupTools
安裝地址: http://pypi.python.org/pypi/setuptools、https://pypi.python.org/pypi/pip
(6)安裝Selenium
執行命令 pip install -U selenium
2、分析其頁面結構
頁面包括了股票列表和頁面列表
股票列表通過id爲list-body的ul展示:
頁面列表是一個id爲page-navi的div,但是這個div是根據股票數據動態生成的。
3、程序邏輯
通過頁面分析,初步的程序邏輯:
a. 首先通過Selenium的chrome或者firefox驅動加載頁面
b. 通過頁面元素抓取數據
c. 通過Click()方法實現頁面跳轉
d. 重複a-c直到頁面全部跳轉完成
4、代碼實現:
(1)獲取板塊數據
'''獲取行業板塊數據''' def getIndustrySection(): __logger.debug("開始:收集行業板塊數據") try: dbOperator = DBOperator() dbOperator.connDB() table = __stockTables['section'] date = getNowdate() for code in range(1, 100): code = '012%03d' % code if isStockSectionExitsInDate(table,code, date, dbOperator): dataUrl = "http://…………fi_quote_navi_bar&id=bd_ind#mod=list&id=bd%s"% code getStockSectionDetail(code,dataUrl,dbOperator) except Exception as err: __logger.error(">>>>>> Exception: "+str(code) + " " + str(err)) finally: dbOperator.closeDB() __logger.debug("結束:收集行業板塊數據")
(2)抓取代碼
'''讀取信息''' def getDataFromUrl(dataUrl): try: browser = webdriver.Firefox() browser.get(dataUrl) time.sleep(2) codes = [] pages = [1,] pageTotalNum = 1 listFoot =browser.find_element_by_class_name("list-foot") pageTags =listFoot.find_elements_by_tag_name("a") pageTotalNum = len(pageTags) - 2 for i in range(1, pageTotalNum ): element =browser.find_element_by_xpath("//ul[contains(@id,'list-body')]") codeElements =element.find_elements_by_tag_name("li") for codeElement in codeElements: codes.append(codeElement.get_attribute("id")[-6:]) listFoot =browser.find_element_by_class_name("list-foot") pageTags =listFoot.find_elements_by_tag_name("a") nextPage = i + 1 if i < pageTotalNum and not nextPage in pages: pageTags[nextPage].click() pages.append(nextPage) time.sleep(2) print codes except NoSuchElementException as err: __logger.error(">>>>>> Exception: " + str(err)) return None except TimeoutException as err: __logger.error(">>>>>> Exception: " + str(err)) return None except Exception as err: __logger.error(">>>>>> Exception: " + str(err)) return None finally: browser.close() return codes
(3)調用抓取數據並存儲數據庫
'''獲取板塊交易信息明細''' def getStockSectionDetail(sectionCode, dataUrl, dbOperator): stockCodes = getDataFromUrl(dataUrl) if stockCodes == None and len(stockCodes)== 0: return False stockQuotation = {} date = getNowDate() for stockCode in stockCodes: #存儲到數據庫 ……
(4)多線程實現
爲提高運行效率,採用多線程方式同時採集不同板塊數據:
threads = [] t1 =threading.Thread(target = getIndustrySection) #行業板塊 t2 =threading.Thread(target = getConceptSection) #概念板塊 t3 =threading.Thread(target = getAreaSection) #地域板塊 threads.append(t1) threads.append(t2) threads.append(t3) if __name__ =='__main__': time1= time.time() try: for t in threads: t.setDaemon(True) t.start() while len(threads) > 0 : t = threads[0] t.join() del threads[0] except Exception as err: __logger.error(">>>>>> Exception: " +str(err)) time2= time.time() print "總用時:%d" % (time2-time1) __logger.info("總用時:%d" % (time2-time1))
5、數據分析
抓到的數據就可以用作分析了,例如1月7日板塊現金流的情況(當然還要結合其他數據):main爲主力流入數據,private爲主力流出數據,1月7日當天只開盤半個小時即熔斷,只有煤化工領域錄得小幅資金流入:
6、優點和缺點
(1)優點:大多數Web數據都可以採用這種方式獲得;
(2)缺點:運行效率較低,加載頁面速度慢,如果數據量較大,需要長時間運行,如果是服務端linux,因爲沒有顯示桌面,無法加載firefox或chrome驅動。