《Tango with Django》-第13章 Webhose 搜索

13.1 Webhose API

Webhose 是一项在线服务,其功能是汇集众多在线源,实时整理信息。借助Webhose API,我们能以编程的方式查询Webhose,得到JSON格式的结果。返回的数据经过JSON解析器解析后,在应用的模板上显示出来。

注册 Webhose API 密钥

登录https://www.webhose.io注册一个临时账号,邮件激活账号后,登录如下:
在这里插入图片描述
记下API秘钥后,点击顶部导航栏中的“API Playground”链接。这个页面供您试用Webhose API接口。(1)在“Define the query”下面的方框中输入一个词条。(2)在“Sort By”下拉菜单中选择“Relevancy”。(3)“Crawled Since”用于设定返回什么时候爬取的结果,默认值3天就可以了。(4)点击“Run”按钮。稍等片刻页面就会出现查询结果。
在这里插入图片描述
看一下Webhose API返回的结果,以及原始的JSON响应。向上拉动滚动条,找到“Endpoint”框,就可以找到URL。http://webhose.io/filterWebContent?token=<KEY&format=json&sort=relevancy&q=< QUERY>

13.2 添加搜索功能

  • rango/webhose_search.py
import json
import urllib.parse
import urllib.request

def read_webhose_key():
    webhose_api = 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(serch_terms,size=10):
    webhose_api_key = read_webhose_key()

    if not webhose_api_key:
        raise KeyError('Webhose key not found')

    root_url = 'http://webhose.io/search'

    query_string = urllib.parse.quote(search_terms)

    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:
        response = urllib.request.urlopen(search_url).read().decode('utf-8'
        json_response = json.loads(response)
        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 密钥

read_webhose_key()函数从名为search.py的文件中读取Webhose API密钥。这个文件应该放在Django项目的根目录中(< workspace>/tango_with_django_project/),而不是Rango应用的目录中。

run_query():执行查询

run_query()函数接受两个参数:search_terms,值为字符串,表示用户输入的搜索词条;size,默认值为10,控制Webhose API返回的结果数量。run_query()函数与Webhose API通信,返回一个由Python字典构成的列表,每个字典表示一个结果(有title、link和summary)。
run_query()函数的逻辑大致可以分成7个任务,说明如下:
(1)调用 read_webhose_key() 获取Webhose API。
(2)然后构建要发给 API 的查询字符串。这里要编码URL,把特殊的字符串转化为Web服务器和浏览器能理解的格式。比如,空格会转换成%20
(3)根据 Webhose API 文档,接下来要拼接编码后的 search_terms 字符串和 size 参数,以及Webhose API 密钥,构建请求 Webhose API 的完整 URL。
(4)使用 Python urllib模块连接Webhose API。服务器响应存为response变量。
(5)使用 Python json 库把响应转换成 Python 字典对象。
(6)迭代字典,把Webhose API返回的各个结果(包含title、link和summay键值对)以字典为单位存入results列表
(7)返回 results 列表。

13.3 集成到 Rango 应用中

在 webhose_search.py 模块中实现搜索功能后,接下来分三步将它集成到Rango应用中。
(1)创建 search.html 模板,拓展自base.html 模板。search.html 模板有个HTML表单。
(2)编写一个Django视图,调用前面定义的 run_query() 函数,渲染 search.html 模板。
(3)在 Rango 应用的url.py模块中把新视图映射到一个 URL 上。

创建模板

  • teplates/rango/rango/search.html
{
    
    % extends 'rango/base.html' %}
{
    
    % load static %}

{
    
    % block title_block %}
Search
{
    
    % endblock %}

{
    
    % block body_block %}
<div>
    <h1>Search with Rango</h1>
    <br/>
    <form class="form-inline" id="user_form" 
        method="post" action="{% url 'search' %}">
        {
    
    % csrf_token %}
        <div class="form-group">
            <input class="form-control" type="text" size="50" 
                name="query" value="" id="query" />
            <button class="btn btn-primary" type="submit" name="submit"
                value="Search">Search</button>
        </div>
    </form>


    <div>
        {
    
    % if result_list %}
        <h3>Results</h3>
        <div class="list-group">
        {
    
    % for result in result_list %}
            <div class="list-group-item">
                <h4 class="list-group-item-heading">
                    <a href="{
    
    { result.link }}">{
    
    {
    
     result.title }}</a>
                </h4>
                <p class="list-group-item-text">{
    
    {
    
     result.summary }}</p>
            </div>
        {
    
    % endfor %}
        </div>
        {
    
    % endif %}
    </div>
    
</div>        
{
    
    % endblock %}

上述模板代码主要执行两个任务:
(1) 在HTML表单中显示搜索框和搜索按钮,供用户输入和提交查询词条。
(2) 渲染模板时,如果传给模板上下文的results_list对象有内容,那就迭代results_list对象,渲染里面的结果。上述模板期待每个结果中有title、link和summary,这与前面定义的run_query()函数是一致的。

编写视图

Rango/views.py

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})

添加映射

❏ 把search() 视图映射到 URL /rango/search/ 上,并设定 name=‘search’ 参数。在 Rango应用的 urls.py 模块中添加 url(r’search/$’, views.search, name=‘search’)。

  • Rango/urls.py
urlpatterns = [
    url(r'^$',views.index,name='index'),
    url(r'^add_category/$',views.add_category,name='add_category'),
    url(r'^category/(?P<category_name_slug>[\w\-]+)/$',views.show_category, name='show_category'),
    url(r'about/$', views.about, name='about'),
    url(r'^category/(?P<category_name_slug>[\w\-]+)/add_page/$', views.add_page, name='add_page'),
    url(r'^register/$',views.register,name='register'),
    url(r'^login/$',views.user_login, name='login'),
    url(r'^restricted/',views.restricted,name='restricted'),
    url(r'^logout/$',views.user_logout,name='logout'),
    url(r'search/$', views.search, name='search'),
    ]

❏ 更新 base.html 模板中的导航栏,加入搜索页面的链接。不要在模板中硬编码 URL,应该使用 url 模板标签。

  • base.html
        {
    
    % if user.is_authenticated %}
            <li class="nav-item">
              <a class="nav-link" href="{% url 'add_category' %}">Add a New Category</a>
            </li>
            <li class="nav-item">
            </li>
            <li class="nav-item">
            </li>
            <li class="nav-item">
              <a class="nav-link" href="{% url 'logout' %}?next=/rango/">Logout</a>
            </li>
            <li class="nav-item">
              <a class="nav-link" href="{% url 'search' %}">Search</a>
            </li>

在这里插入图片描述

练习

我的小结

  • NameError at /rango/search/,name ‘run_query’ is not defined
    在这里插入图片描述
    解决措施:from rango.webhose_search import read_webhose_key,run_query

  • OSError at /rango/search/,search.key file not found
    在这里插入图片描述

解决措施:取得Webhose的API接口的密钥

我的尝试:

因为暂时没有Webhose的API接口,改用高德地图API。
rango/webhose_search.py

import json
import urllib.parse
import urllib.request
from bs4 import BeautifulSoup
import requests

def read_webhose_key():
    #webhose_api = None
    #try:
    #    with open('search.key','r') as f:
    #        webhose_api_key = f.readline().strip()
    #except:
    #    raise IOError('search.key file not found')
    webhose_api_key = '8c7d5f869c745fca4ea8da92574a93d1'
    return webhose_api_key


def run_query(serch_terms,size=10):
    webhose_api_key = read_webhose_key()

    if not webhose_api_key:
        raise KeyError('Webhose key not found')

    parameters = {
    
    
                'address': serch_terms, 
                'key': '8c7d5f869c745fca4ea8da92574a93d1'
                }
    base = 'http://restapi.amap.com/v3/geocode/geo'

    results = []

    #try:
    response = requests.get(base, parameters)
    answer = response.json()
    #print(answer)
    try:
        for post in answer['geocodes']:
            results.append({
    
    'title':post['formatted_address'],
                            'link':post['citycode'],
                            'summary':post['location'][:200]})
    except:
        print("Error when querying the webhose API")
    #print(results)
    return results


def main():
    serch_terms = '中山港麦当劳'
    print(run_query(serch_terms,size=10))

if __name__ == '__main__':
    main()

改后的页面如下:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/m0_46629123/article/details/113503678