Chinaunix首页 | 论坛 | 博客
  • 博客访问: 64768
  • 博文数量: 20
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 198
  • 用 户 组: 普通用户
  • 注册时间: 2013-03-31 17:15
文章分类

全部博文(20)

文章存档

2014年(1)

2013年(19)

我的朋友

分类: Python/Ruby

2013-05-25 15:08:02

在使用python抓取网页的过程中,有的时候需要执行某些简单的javascript,以获得自己需要的内容,例如执行js里面的document.write或者document.getElementById等。自己解析js代码显然有点吃力不讨好,因此最好能找到一些可以解析执行js的python库。

google之可以找到三个候选者,分别是微软的ScriptControl,v8的python移植,还有SpiderMonkey的Python移植。其中ScriptControl只能在windows上运行,需要win32com库;PyV8能在windows和*nix上运行,但是需要装PyV8库;而SpiderMonkey是mozilla的js引擎在python上的移植,感觉已经不太活跃,因此没用。

微软的ScriptControl中对执行js最重要的方法就是addObject与eval,通过addObject,我们可以向js执行环境注入一个我们自定义的document对象,通过eval方法,我们可以执行一段js代码。注入自定义对象需要使用win32com.server.util.wrap方法,将一个python对象包装为COM对象,例如假设我们想注入一个只实现了write方法的document对象,代码是这样的:

点击(此处)折叠或打开

  1. import win32com.server.util, win32com.client

  2. class win32Doc:
  3.      _public_methods_ = ['write']
  4.      def write(self, s):
  5.              print s

  6. doc = win32Doc()
  7. jsengine = win32com.client.Dispatch('MSScriptControl.ScriptControl')
  8. jsengine.language = 'JavaScript'
  9. jsengine.allowUI = False
  10. jsengine.addObject('document', win32com.server.util.wrap(doc))
  11. jsengine.eval('document.write("hello, world")')


在windows里运行这段python代码,最终就会打印出hello, world来。如果我们希望从python里读取js通过document.write写入的字符串并进行解析,只要给上面的win32Doc类添加对应的方法(例如read),就可以读取并解析HTML代码,并进行进一步处理了。

对PyV8来说,原理也是类似的,不过在具体机制上有所不同而已。在PyV8中需要在初始化的时候加入一个全局对象,其他的对象都是挂在全局对象之下的,例如document只是全局对象的一个属性而已(实际上,document对象就是window对象的一个属性么),当然,这个属性对应的实际上是一个对象。需要注意的是,PyV8在处理字符串编码的时候让人很迷惑,在windows下它需要js的编码为UTF8,而在Linux下只要求宽字符串,即python里的unicode,而在内部的字符串都是UTF8编码的。至于为何如此,熊猫也骚扰过开发PyV8的flier,貌似是V8自己的feature。示例代码是这样的:

点击(此处)折叠或打开

  1. import PyV8

  2. class v8Doc(PyV8.JSClass):
  3.      def write(self, s):
  4.              print s.decode('utf-8')

  5. class Global(PyV8.JSClass):
  6.      def __init__(self):
  7.              self.document = v8Doc()

  8. glob = Global()
  9. ctxt = PyV8.JSContext(glob)
  10. ctxt.enter()
  11. #or ctxt.eval(u'document.write("你好,中国")') for Linux
  12. ctxt.eval(u'document.write("你好,中国")'.encode('utf-8'))
上面只是在python里模拟执行js的document.write的大体思路,如果还需要执行其他的js代码对DOM树进行操纵,那就一个个添加对应的方法好了。当然,这个添加也要保持一个限度,不然添加的方法太多,代码会非常复杂,相当于自己已经开始实现一个DOM树处理和解析的完全封装了,如果是这样,还不如使用自动化接口操纵浏览器,例如通过js/vbs操纵IE,或者在后台进行自动化批处理的话,使用一些headless browser软件,例如,这就留待以后再说了。



阅读(1223) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~