Django开发中使用Google custom search API
我们的网站通常都要集成搜索服务。通常情况下,我们都使用自己的搜索后端,例如使用Django,对于Python,我们主要有两种选择,一种是Whoosh,它是纯Python写成的搜索后端;另一种则是著名的Lucene的Python扩展,PyLucene,要提醒使用PyLucene,需要安装JVM。以后的文章我会介绍他们。
不过,今天的主角显然不是它们。因为有时候,我们并不需要这么麻烦,有时我们只需要集成一个Google搜索在其中就可以了。那么,Google custom search就派上了用场。在这里,我们也有三种方案:
- 用iframe版本的cse,使用这种方式,甚至不需要写什么代码。
- 使用Google ajax API,使用ajax方式获取搜索结果,然后用js将结果呈现在页面上。
- 使用Custom search API,在后端使用Python的http编程,远程获取json方式的结果,并把数据渲染到模板中。
在一切开始之前,必须先创建一个新的自定义搜索。在cse页面上,点击“Create a Custom Search Engine”,如果已经新建过了,点击下面的“manage your existing search engines”。
创建或进入管理界面以后,在“Control panel”中可以得到Search engine unique ID,常常用cx标记。在Control panel中有众多设置,比如你的网站不是所有页面都想被索引,你可以在“Sites”设置匹配规则。或者,你可以把网站的sitemap添加到“Indexing”中,更多请参考cse页面中说明。
使用iframe版本的cse是相当简单的,直接拷贝cse提供的html代码拷贝到自己页面即可,这里不多赘述。对于第二种方式,请参考这篇文章,讲的很详细。本文主要讲解第三种方式。
要使用Custom search API获取json方式的结果,首先需在Google APIs console中开启(需翻墙),来获取API的key。要注意的是,使用这种方式,每天只能免费搜索100次。不过对于个人网站,100次基本上够用了。
假设现在我们已经获取了API的key和cx。那我们就正式开始。
由于我们使用json处理数据,我们需要导入json库,Python中有内置的json模块,不过在2.6版本前称为simplejson,为了保证在Python各版本中不会发生导入错误,我们这么写:
def import_simplejson(): try: import simplejson as json except ImportError: try: import json # Python 2.6+ except ImportError: try: from django.utils import simplejson as json # Google App Engine except ImportError: raise ImportError, "Can't load a json library" return json
这样我们在使用json库之前,只需调用import_simplejson函数即可。
考虑我们以后可能考虑换成其他的搜索后端,另一方面,也是保证依赖倒置的设计原则,我们首先定义SearchBase类:
class SearchBase(object): def __init__(self, q): self._q = q def __call__(): raise NotImplementedError # 使用callable的方式。
我们要获取数据,需要提供这几个参数,以GET方式调用:key,cx,q,start。当然参数不止这么多,其他参数。key和cx已经讲过,q是搜索关键字,必须要url encode。start是搜索起始。贴出代码:
import urllib2, urllib class Record(object): '''表示单条搜索结果''' def __init__(self, adict): assert adict, dict setattr(self, 'title', adict['title']) setattr(self, 'htmlSnippet', adict['htmlSnippet']) setattr(self, 'link', adict['link']) class GoogleSearch(SearchBase): key = '' cx = '' url = 'https://www.googleapis.com/customsearch/v1' # 调用api的地址 def __init__(self, q, page=1): # 初始化,q为搜索关键字,默认从第一页开始 SearchModel.__init__(self, q) self._page = page def _get_data(self): start = (self._page - 1) * 10 + 1 # 计算起始位置 data = {'q': self._q.encode("utf-8")} q_str = urllib.urlencode(data) # 使用urllib中的urlencode方法 abs_url = "https://www.googleapis.com/customsearch/v1?key=%s&cx=%s&%s&start=%d" % \ (self.key, self.cx, q_str, start) data = urllib2.urlopen(abs_url) # 使用urllib2的urlopen方法更简单 resultContent = data.read() # 获取结果 return resultContent def _get_json(self): if getattr(self, '_json', None) is None: json = import_simplejson() self._json = json.loads(self._get_data()) # 加载json数据 return self._json def _get_count(self): # 获取搜索结果数量 _json = self._get_json() return int(_json['queries']['request'][0]['totalResults']) def _get_result_list(self): _json = self._get_json() return _json['items'] def __call__(self): records = [] try: results = self._get_result_list() for r in results: record = Record(r) records.append(record) except KeyError: pass # print KeyError.message return self._get_count(), records
代码很简单。这样,我们在搜索相应的view中,只需获取搜索关键字,渲染给模板即可。
search = GoogleSearch(query, page) count, results = search()
你好,我是最近才开始接触google custom search api的,以上的这些配置我都已经完成了,搜索也已经可以搜索到数据了,可是不知道为什么只能搜索前100条以内的数据。明明totalResult显示有548条,可是我把start设置在100以上的时候就无法搜索了,请问前辈你有遇到过这样的情况么。
您可以使用他们的密钥和代码,因为它们允许我们使用它们。您可以轻松制作自己的程序。