drupal搭建网站很方便灵活,但是在搭建好网站之后需要做的就时填充内容了。
填充内容有人工和自动两种方式,blog、sns等应用靠网站主和网站用户自行添加内容,丰富网站,但其他一些应用靠人工就不太可能实现了,例如信息采集、数据同步,人工耗时耗力。
解决这个问题的思路有三种,其一,直接写入到drupal的数据库里,但是drupal的数据库设计挺复杂的,特别是一些字段的处理上,稍有疏忽会导致各种报错。
其二,http post方式,通过post方式去请求,但是问题是如果数据同步行为比较复杂,提交数据时还需要判断和已连串的操作的话,靠post后响应的html解析判断就很复杂了,甚至有的内容类型并没有提供写入的页面路径,这个方式就不是那么通用。
其三,使用RESTful,这是我现在使用的方法,需要安装额外的模块 Services3。
Services提供了标准的REST请求方式,响应数据有多种格式选择,其中最常用的就是json和xml。
安装好Services后,通过几步简单的设置就可以使用了。推荐再安装一个 Services Views 模块,这个模块可以通过view添加自定义的REST,其中可以通过设置view的字段、过滤条件、关联等实现很多高级的REST资源。
准备好Services后,接下来就是调用他并写入数据了。
各种语言中我选择了python,语法简单,效率也不错,而且我的需求是从另一个接口自动提取并写入drupal,所以不需要界面,也不需要用户触发,只需要在服务器上定时运行即可,因此只需要用python创建已个shell。
在python中http请求需要用到urllib2模块,传递参数时需要urlencode,因此还需要urllib模块,保持会话状态需要cookies,因此需要cookielib,解析响应的json需要用到json模块,因此在python脚本第一行导入这4个模块
import cookielib, urllib, urllib2,json
通过REST向drupal写入数据是需要登陆的,所以需要用到cookiejar,并且使用这个对象创建一个opener
#创建一个cookie处理对象 cookiejar = cookielib.CookieJar() #使用build_opener创建urlOpener,使用刚才创建的cookie处理对象作为cookies处理对象 urlOpener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookiejar))
接下来就时执行请求了,因为从登陆到查询到写入需要请求多次,我将没一次请求都需要写的代码封装成一个函数。
def goRequest(url='',values={},method='GET'): data = urllib.urlencode(values) request = urllib2.Request(baseURL%(url),data) #获取csrf,services3模块在写入和更新时需要验证 if CSRF!=None:request.add_header("X-CSRF-Token", CSRF) request.get_method = lambda:method url=urlOpener.open(request) result = url.read() return result.decode('gbk').encode('utf-8')
封装了这个函数,身下的事情就很好办了
1.登陆
print goRequest(loginURL,{'username':'登陆名','password':'密码'},'POST')
(每一句执行我都使用print打印,为了调试方便,实际执行不需要print,直接调用就行了)
2.获取CSRF验证信息,之前的services模块不需要,但是目前的版本需要,验证方法就是在header里加入X-CSRF-Token描述,在封装的goRequest里有具体写法,在这里我只需要创建一个CSRF全局变量,然后获取CSRF的值,然后每次调用goRequest的时候CSRF就自动设置到header里了。
CSRF=goRequest(sessionTokenURL)
print CSRF #打印出来看看确保获取到数据
3.登陆完成,CSRF验证完成 ,接下来想做什么就做什么了。我在这里是请求写入content。
print 'nodeInfo',nodeInfo try: #add new node goRequest('syn_res/node/‘ ,{"field_title":nodeInfo['title'] ,"field_name[und][0][value]":nodeInfo['name']} ,'POST') except Exception,e: print e
这里用的是POST,services REST数据时可以使用GET、POST、PUT、DELETE,可以分别理解为查、增、改、删。对应操作选择不同的Method方式。
在以上代码中,nodeInfo是我从另一个位置查询并传递过来的json对象,测试时,可以先手工创建这个nodeInfo的json对象。
全部代码是这样的
#encoding:UTF-8 ''' Created on 2013-7-18 @author: ZetaChoww ''' import cookielib, urllib, urllib2,json #配置区域################################################################# baseURL="http://localhost/drupal/?q=%s" ######################################################################### loginURL ='res/user/login' sessionTokenURL ='services/session/token' CSRF=None ########################################################################## #创建一个cookie处理对象 cookiejar = cookielib.CookieJar() #使用build_opener创建urlOpener,使用刚才创建的cookie处理对象作为cookies处理对象 urlOpener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookiejar)) ########################################################################## def goRequest(url='',values={},method='GET'): data = urllib.urlencode(values) request = urllib2.Request(baseURL%(url),data) #获取csrf,services3模块在写入和更新时需要验证 if CSRF!=None:request.add_header("X-CSRF-Token", CSRF) request.get_method = lambda:method url=urlOpener.open(request) result = url.read() return result.decode('gbk').encode('utf-8') def sync_node(nodeinfo=None): #获取 print 'nodeinfo',nodeinfo try: #modify some field from license info on Gzjjzd database goRequest('syn_res/node/" ,{"title":nodeinfo[title] ,"field_name[und][0][value]":nodeinfo['name']} ,'POST') except Exception,e: print e if __name__=='__main__': print '#Start login..' print goRequest(loginURL,{'username':'zz','password':'zzzzzz'},'POST') print '#Login OK!' CSRF=goRequest(sessionTokenURL) print '#CSRF:',CSRF print '#Start run' node={'title':'Hello!','name':'ZetaChow'} sync_node(node) #close the request opener urlOpener.close()
代码中删减了一些实际项目中的代码,所以可能有错漏,分享一下方法,代码不重要,用任何语言都可以实现类似功能,通过services模块,将内外数据整合在一起使得drupal可以用于更广阔的范围,drupal的entity的设计完全就时数据模型,services提供了一个途径在外部操作drupal的数据模型,这个方式也让团队其他成员能够加入到drupal项目的开发。