python寫的數據採集,對通常有規律的頁面用 urllib2 + BeautifulSoup + 正則就能夠搞定。 可是有些頁面的內容是經過js生成,或者經過js跳轉的,甚至js中還加入幾道混淆機制;對這種涉及頁面腳本解析的內容,前面的方式便很無力。前端
這時咱們須要能解析、運行js的引擎——瀏覽器,而python selenium能提供程序與瀏覽器的交互接口,再加上phantomjs這個能夠後臺運行的瀏覽器,即便用 selenium + phantomjs 即可以解決以上的問題。python
selenium能夠操做頁面的元素,而且提供執行js腳本的接口。但其調用js腳本後並不能直接返回執行的結果,這樣再採集內容的過程當中就會受到一些限制。 好比咱們想使用頁面中的函數進行數據轉換,或者獲取iframe裏的內容,這些js產生數據要傳回比較麻煩。jquery
因此我便寫一個簡化js數據回傳的擴展 exescript.pylinux
#!/usr/bin/env python # -*- coding:utf-8 -*- # # created by heqingpan _init_js=""" (function (){ if (window.__e) { return; } var e=document.createElement('div'); e.setAttribute("id","__s_msg"); e.style.display="none"; document.body.appendChild(e); window.__e=e; })(); window.__s_set_msg=function(a){ window.__e.setAttribute("msg",a.toString()||""); } """ _loadJsFmt=""" var script = document.createElement('script'); script.src = "{0}"; document.body.appendChild(script); """ _jquery_cdn="http://lib.sinaapp.com/js/jquery/1.7.2/jquery.min.js" _warpjsfmt="__s_set_msg({0})" class ExeJs(object): def __init__(self,driver,trytimes=10): from time import sleep self.driver=driver driver.execute_script(_init_js) while trytimes >0: try: self.msgNode=driver.find_element_by_id('__s_msg') break except Exception: sleep(1) trytimes -= 1 if self.msgNode is None: raise Exception() def exeWrap(self,jsstr): """ jsstr 執行後有返回值,返回值經過self.getMsg()獲取 """ self.driver.execute_script(_warpjsfmt.format(jsstr)) def loadJs(self,path): self.execute(_loadJsFmt.format(path)) def loadJquery(self,path=_jquery_cdn): self.loadJs(path) def execute(self,jsstr): self.driver.execute_script(jsstr) def getMsg(self): return self.msgNode.get_attribute('msg')
打開ipython上一個例子,獲取博客園首頁文章title列表web
from selenium import webdriver import exescript d=webdriver.PhantomJS("phantomjs") d.get("http://www.cnblogs.com/") exejs=exescript.ExeJs(d) exejs.exeWrap('$(".post_item").length') print exejs.getMsg() #out: """ 20 """ jsstr="""(function(){ var r=[]; $(".post_item").each(function(){ var $this=$(this); var $h3=$this.find("h3"); r.push($h3.text()); }); return r.join(',');})()""" exejs.exeWrap(jsstr) l=exejs.getMsg() for title in l.split(','): print title #out: """ mac TeamTalk開發點點滴滴之一——DDLogic框架分解上 The directfb backend was supported together with linux-fb backend in GTK+2.10 Science上發表的超讚聚類算法 功能齊全、效率一流的免費開源數據庫導入導出工具(c#開發,支持SQL server、SQLite、ACCESS三種數據 庫),每個月藉此處理數據5G以上 企業級應用框架(三)三層架構之數據訪問層的改進以及測試DOM的發佈 Unity3D 第一季 00 深刻理解U3D開發平臺 Welcome to Swift (蘋果官方Swift文檔初譯與註解二十一)---140~147頁(第三章--集合類型) appium簡明教程(11)——使用resource id定位 SQL語句彙總(終篇)—— 表聯接與聯接查詢 fopen警告處理方式 AndroidWear開發之HelloWorld篇 AMD and CMD are dead之KMD.js版本0.0.2發佈 SQL語句彙總(三)——聚合函數、分組、子查詢及組合查詢 DevExpress GridControl功能總結 ASP.NET之Jquery入門級別 2014年前端面試經歷 grunt源碼解析:總體運行機制&grunt-cli源碼解析 跟用戶溝通,問題儘可能分析清楚,以及解決問題 ASP.NET之Ajax系列(一) 算法複雜度分析 """