python写的数据采集,对一般有规律的页面用 urllib2 + BeautifulSoup + 正则就可以搞定。 但是有些页面的内容是通过js生成,或者通过js跳转的,甚至js中还加入几道混淆机制;对这种涉及页面脚本解析的内容,前面的方式便很无力。
这时我们需要能解析、运行js的引擎——浏览器,而python selenium能提供程序与浏览器的交互接口,再加上phantomjs这个可以后台运行的浏览器,即使用 selenium + phantomjs 便可以解决以上的问题。
selenium可以操作页面的元素,并且提供执行js脚本的接口。但其调用js脚本后并不能直接返回执行的结果,这样再采集内容的过程中就会受到一些限制。 比如我们想使用页面中的函数进行数据转换,或者获取iframe里的内容,这些js产生数据要传回比较麻烦。
所以我便写一个简化js数据回传的扩展 exescript.py
#!/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') |