赵走x博客
网站访问量:151491
首页
书籍
软件
工具
古诗词
搜索
登录
17、部署 Django 项目
16、自动化测试
14、jQuery 和 Django
13、Webhose 搜索
12、集成 Bootstrap
11、使用 Django-Registration-Redux
10、cookie 和会话
9、用户身份验证
8、模板进阶
7、表单
6、模型、模板和视图
5、模型与数据库
4、模板和媒体文件
3、Django 基础
2、前期准备工作
1、导言
13、Webhose 搜索
资源编号:76320
Tango with Django
Python Web
热度:99
至此,Rango 应用的核心功能已经实现,接下来该考虑一些高级功能了。本章将使用 Webhose API 实现搜索网页的功能,毕竟只能按分类浏览不是很方便。为此,我们需要注册 Webhose 账 户,再编写一个包装脚本(wrapper),通过 API 获取查询结果。
至此,Rango 应用的核心功能已经实现,接下来该考虑一些高级功能了。本章将使用 Webhose API 实现搜索网页的功能,毕竟只能按分类浏览不是很方便。为此,我们需要注册 Webhose 账 户,再编写一个包装脚本(wrapper),通过 API 获取查询结果。 # 13.1 Webhose API Webhose 是一项在线服务,其功能是汇集众多在线源,实时整理信息。借助 Webhose API,我们 能以编程的方式查询 Webhose,得到 JSON 格式的结果。返回的数据经过 JSON 解析器解释后, 在应用的模板中显示出来。 Webhose 已经爬取了大量数据,但那不是我们所关注的。我们的目的是获取 Rango 应用的用户输 入的词条搜索到的网页。使用 Webhose API 之前,要有 API 密钥。有了密钥,我们每个月可以免 费查询一千次——这对我们的演示应用而言足够了。 >★ 应用程序编程接口是什么? ★ 应用程序编程接口(Application Programming Interface,API)定义软件组件之间的交互方 式。对 Web 应用来说,API 可以理解为一系列 HTTP 请求及其响应消息的结构。任何能通过 互联网访问的服务都可以有 API,本章涉及的是搜索 API。如果想进一步了解 Web API,可 以阅读 Luis Rei 写的[这篇优秀教程](http://blog.luisrei.com/articles/rest.html "这篇优秀教程")。 注册 Webhose API 密钥 为了获得 Webhose API 密钥,首先要注册一个免费的 Webhose 账户。在 Web 浏览器中访问 https://www.webhose.io ,点击页面右上角的“Use it for free”按钮注册。公司名称无需填写,工作邮箱填一个有效的电子邮件地址即可。 注册好账户后,打开 Webhose 的控制面板,如图 13-1 所示。在这个页面可以看到当月已经使用 的查询次数,以及还剩多少免费额度。此外,页面中还有一个图表,展示了一段时间内你查询 Webhose 的次数。向下拉滚动条,找到“Active API Key”部分。把这里显示的密钥复制到一个空文 本文件中,以备后用。这是你专用的密钥,通过它对 Webhose API 的请求都算在你名下。  图 13-1:Webhose 的控制面板,显示 API 密钥的位置。你可能要向下拉动滚动条才能看到。上图 中的 API 密钥被遮盖住了。一定要保护好自己的密钥! 记下 API 密钥后,点击顶部导航栏中的“API Playground”链接。这个页面供你试用 Webhose API 接口,你可以自己尝试一下。 ➊ 在“Define the query”下面的方框中输入一个词条。 ➋ 在“Sort By”下拉菜单中选择“Relevancy”。 ➌ “Crawled Since”用于设定返回什么时候爬取的结果,默认值 3 天就可以。 ➍ 点击“Run”按钮。稍等片刻页面中便会出现查询结果。图 13-2 是搜索“Glasgow”得到的结 果。  图 13-2:通过 Webhose API 查询“Glasgow”得到的响应。除了原始的 JSON 响应之外,还有预览。 看一下 Webhose API 返回的结果,以及原始的 JSON 响应。 向上拉动滚动条,找到“Endpoint”框。这里显示的 URL 就是我们的应用将要使用的查询端点。下 面是一个端点 URL 示例: ``` http://webhose.io/filterWebContent?token=
``` 这个 URL 可以分为两部分,问号左边是基 URL,右边是查询字符串。基 URL 相当于 API 的路 径,而查询字符串是一系列键值对(例如 format 是键,json 是值),用于告诉 API 你想做什 么。在后面的示例代码中你会看到,我们将以这种方式分拆 URL,构建好查询字符串之后再合在 一起,构成完整的请求 URL。 # 13.2 添加搜索功能 得到 Webhose API 密钥后,可以开始编写 Python 代码,向 Webhose API 发起查询请求了。在 rango 目录中新建一个模块(文件),命名为 webhose_search.py,写入下述代码。注意选择正确的 Python 版本。正如前文所说,不要盲目复制粘贴,最好自己动手输入,这样在输入的过程中你才 会思考代码的作用。 ``` import json import urllib.parse import urllib.request def read_webhose_key(): """ 从 search.key 文件中读取 Webhose API 密钥 返回 None(未找到密钥),或者密钥的字符串形式 注意:把 search.key 写入 .gitignore 文件,禁止提交 """ # 参见 Python Anti-Patterns 小书,这是一份十分优秀的资料 # 使用 with 打开文件 # http://docs.quantifiedcode.com/python-anti-patterns/maintainability/ webhose_api_key = None try: with open('search.key', 'r') as f: webhose_api_key = f.readline().strip() except: raise IOError('search.key file not found') return webhose_api_key def run_query(search_terms, size=10): """ 指定搜索词条和结果数量(默认为 10), 把 Webhose API 返回的结果存入列表 每个结果都有标题、链接地址和摘要 """ webhose_api_key = read_webhose_key() if not webhose_api_key: raise KeyError('Webhose key not found') # Webhose API 的基 URL root_url = 'http://webhose.io/search' # 处理查询字符串,转义特殊字符 query_string = urllib.parse.quote(search_terms) # 使用字符串格式化句法构建完整的 API URL # search_url 是一个多行字符串 search_url = ('{root_url}?token={key}&format=json&q={query}' '&sort=relevancy&size={size}').format( root_url=root_url, key=webhose_api_key, query=query_string, size=size) results = [] try: # 连接 Webhose API,把响应转换为 Python 字典 response = urllib.request.urlopen(search_url).read().decode('utf-8') json_response = json.loads(response) # 迭代文章,把一篇文章作为一个字典追加到结果列表中 # 限制摘要的长度为 200 个字符,因为 Webhose 返回的摘要可能很长 for post in json_response['posts']: results.append({'title': post['title'], 'link': post['url'], 'summary': post['text'][:200]}) except: print("Error when querying the Webhose API") # 把结果列表返回给调用方 return results ``` 上述代码清单实现了两个函数:read_webhose_key() 函数从本地文件中读取 Webhose API 密钥, run_query() 函数向 Webhose API 发送请求,返回得到的结果。下面分析一下这两个函数。 # read_webhose_key():读取 Webhose API 密钥 read_webhose_key() 函数从名为 search.key 的文件中读取 Webhose API 密钥。这个文件应该放在 Django 项目的根目录中(即 `
/tango_with_django_project/`),而不是 Rango 应用的目录中。单独定义这样一个函数,是为了把读取和使用 API 密钥的代码分开。如果代码是公开共享 的,这么做的好处就凸显出来了,毕竟我们不想让别人使用自己的 API 密钥。 现在请创建 search.key 文件。把之前复制的 API 密钥保存到这个文件中。这个文件只用于存储密 钥,不能有任何其他内容。为了防止把这个文件提交到 GitHub 仓库,更新 .gitignore 文件,添加 *.key,排除所有扩展名为 .key 的文件。这样密钥就只存在于本地,不会意外提交到远程 Git 仓库 中。 # run_query():执行查询 run_query() 函数接受两个参数:search_terms,值为字符串,表示用户输入的搜索词条;size, 可选,默认为 10,控制 Webhose API 返回的结果数量。run_query() 函数与 Webhose API 通信, 返回一个由 Python 字典构成的列表,每个字典表示一个结果(有 title、link 和 summary)。上 述代码清单中的注释解释了每一步操作,如果想进一步理解代码,请阅读注释。 run_query() 函数的逻辑大致可以分成 7 个任务,说明如下。 ➊ 首先,调用 read_webhose_key() 函数,获取 Webhose API。 ➋ 然后构建要发给 API 的查询字符串。这里要编码 URL,把特殊的字符(例如空格)转换成 Web 服务器和浏览器能理解的格式。比如,空格会转换成 %20。 ➌ 根据 Webhose API 文档,接下来拼接编码后的 search_terms 字符串和 size 参数,以及 Webhose API 密钥,构建请求 Webhose API 的完整 URL。 ➍ 然后使用 Pythonurllib 模块连接 Webhose API。服务器的响应 存为 response 变量。 ➎ 使用 Python json 库把响应转换成 Python 字典对象。 ➏ 迭代字典,把 Webhose API 返回的各个结果以字典(包含 title、link 和 summary 键值 对)为单位存入 results 列表。 ➐ 返回 results 列表。 >★ 研究 API 选项 ★ 使用新 API 时最好研究一下文档,看有哪些选项可用。建议你研究一下 [Webhose API 文档](https://docs.webhose.io/ "Webhose API 文档")。 # 13.3 集成到 Rango 应用中 在 webhose_search.py 模块中实现搜索功能后,接下来要把它集成到 Rango 应用中。这个过程主要 分三步: ➊ 创建 search.html 模板,扩展自 base.html 模板。search.html 模板中有个 HTML 表单,收集 用户输入的查询词条,以及用于呈现结果的模板代码。 ➋ 编写一个 Django 视图,调用前面定义的 run_query() 函数,渲染 search.html 模板。 ➌ 在 Rango 应用的 urls.py 模块中把新视图映射到一个 URL 上。 ### 创建模板 首先创建 search.html 模板。把这个模板放在项目 templates 目录中的 rango 目录里。在文件中写入 下述 HTML 标记和 Django 模板代码。 ``` {% extends 'rango/base.html' %} {% load staticfiles %} {% block title %} Search {% endblock %} {% block body_block %}
Search with Rango
{% csrf_token %}
Search
{% if result_list %}
Results
{% for result in result_list %}
{{ result.title }}
{{ result.summary }}
{% endfor %}
{% endif %}
{% endblock %} ``` 上述模板代码主要执行两个任务: ❏ 在 HTML 表单中显示搜索框和搜索按钮,供用户输入和提交查询词条。 ❏ 渲染模板时,如果传给模板上下文的 results_list 对象有内容,那就迭代 results_list 对象,渲染里面的结果。上述模板期望每个结果中有 title、link 和 summary,这与前面定义的 run_query() 函数是一致的。 在样式方面,我们使用了 Bootstrap 的列表组和行内表单。 下一小结定义的 Django 视图将通过 results_list 上下文变量把搜索结果传给模板。results_list 一开始为空,因此未搜索到结果时模板不会渲染后半部分。 ### 编写视图 创建好模板后,接下来要添加视图,渲染模板。在 Rango 应用的 views.py 模块中添加下述 search() 视图。 ``` def search(request): result_list = [] if request.method == 'POST': query = request.POST['query'].strip() if query: # 调用前面定义的函数向 Webhose 发起查询,获得结果列表 result_list = run_query(query) return render(request, 'rango/search.html', {'result_list': result_list}) ``` 学到现在,你应该能理解上述代码了。这里唯一需要注意的地方是对 run_query() 函数的调用。 为此,我们要导入 webhose_search.py 模块。在运行 Django 开发服务之前,请把下述 import 语句 添加到 Rango 应用的 views.py 模块顶部。 ``` from rango.webhose_search import run_query ``` ### 添加映射 接下来要把 search() 视图映射到一个 URL 上,还要在导航栏中添加一个链接,让用户能找到搜 索页面。 ❏ 把 search() 视图映射到 URL /rango/search/ 上,并设定 name='search' 参数。即,在 Rango 应用的 urls.py 模块中添加 url(r'search/$', views.search, name='search')。 ❏ 更新 base.html 模板中的导航栏,加入搜索页面的链接。不要在模板中硬编码 URL,应该 使用 url 模板标签。 最后提醒一下,不要忘了在 Django 项目的根目录中创建 search.key 文件,写入你的 Webhose API 密钥。 现在可以向 Webhose API 发起查询了,如图 13-3 所示。  图 13-3:搜索“Python for Noobs”得到的结果