python 開放搜索opensearch示例

這代碼是自己根據官網的demo結合業務需求修改之後的版本

具體api請參考官方文檔實現,只需要根據api設置參數即可

# -- coding: utf-8 --
import time
import random
import hmac
import base64
import copy
import urllib.parse
import requests
import logging

# 應用id
accesskey_id = '**********'
# 應用key
accesskey_secret = '**********'
# 域名
internet_host = 'opensearch-cn-shanghai.aliyuncs.com'
# 應用名
land_name = 'lansi_system_land'
buildings_name = 'lansi_system_build'

logger = logging.getLogger('open_search')


class V3Api:
    # 定義變量
    URI_PREFIX = '/v3/openapi/apps/'
    OS_PREFIX = 'OPENSEARCH'
    VERB = 'GET'

    def __init__(self, address='', port=''):
        self.address = address
        self.port = port

    def runQuery(self,
                 app_name=None,
                 access_key=None,
                 secret=None,
                 http_header={},
                 http_params={}):
        query, header = self.buildQuery(app_name=app_name,
                                        access_key=access_key,
                                        secret=secret,
                                        http_header=http_header,
                                        http_params=http_params)
        url = f'http://{self.address}{query}'
        response = requests.request(self.VERB, url=url, headers=header)
        return response.status_code, response.headers, response.json()

    def buildQuery(self,
                   app_name=None,
                   access_key=None,
                   secret=None,
                   http_header={},
                   http_params={}):
        uri = self.URI_PREFIX
        if app_name is not None:
            uri += app_name
        uri += '/search'

        param = []
        for key, value in http_params.items():
            param.append(urllib.parse.quote(key) + '=' + urllib.parse.quote(value))

        query = ('&'.join(param))

        request_header = self.buildRequestHeader(uri=uri,
                                                 access_key=access_key,
                                                 secret=secret,
                                                 http_params=http_params,
                                                 http_header=http_header)
        return uri + '?' + query, request_header

    # 此處爲簽名代碼實現
    def buildAuthorization(self, uri, access_key, secret, http_params, request_header):
        canonicalized = self.VERB + '\n' \
                        + self.__getHeader(request_header, 'Content-MD5', '') + '\n' \
                        + self.__getHeader(request_header, 'Content-Type', '') + '\n' \
                        + self.__getHeader(request_header, 'Date', '') + '\n' \
                        + self.__canonicalizedHeaders(request_header) \
                        + self.__canonicalizedResource(uri, http_params)
        signature_hmac = hmac.new(secret.encode('utf-8'), canonicalized.encode('utf-8'), 'sha1')
        signature = base64.b64encode(signature_hmac.digest())
        return '%s %s%s%s' % (self.OS_PREFIX, access_key, ':', signature.decode('utf-8'))

    def __getHeader(self, header, key, default_value=None):
        if key in header and header[key] is not None:
            return header[key]
        return default_value

    def __canonicalizedResource(self, uri, http_params):
        canonicalized = urllib.parse.quote(uri).replace('%2F', '/')

        sorted_params = sorted(list(http_params.items()), key=lambda http_params: http_params[0])
        params = []
        for (key, value) in sorted_params:
            if value is None or len(value) == 0:
                continue

            params.append(urllib.parse.quote(key) + '=' + urllib.parse.quote(value))

        return canonicalized + '?' + '&'.join(params)

    def generateDate(self, format="%Y-%m-%dT%H:%M:%SZ", timestamp=None):
        if timestamp is None:
            return time.strftime(format, time.gmtime())
        else:
            return time.strftime(format, timestamp)

    def generateNonce(self):
        return str(int(time.time() * 100)) + str(random.randint(1000, 9999))

    def __canonicalizedHeaders(self, request_header):
        header = {}
        for key, value in request_header.items():
            if key is None or value is None:
                continue
            k = key.strip(' \t')
            v = value.strip(' \t')
            if k.startswith('X-Opensearch-') and len(v) > 0:
                header[k] = v

        if len(header) == 0:
            return ''

        sorted_header = sorted(list(header.items()), key=lambda header: header[0])
        canonicalized = ''
        for (key, value) in sorted_header:
            canonicalized += (key.lower() + ':' + value + '\n')

        return canonicalized

    # 構建Request Header
    def buildRequestHeader(self, uri, access_key, secret, http_params, http_header):
        request_header = copy.deepcopy(http_header)
        if 'Content-MD5' not in request_header:
            request_header['Content-MD5'] = ''
        if 'Content-Type' not in request_header:
            request_header['Content-Type'] = 'application/json'
        if 'Date' not in request_header:
            request_header['Date'] = self.generateDate()
        if 'X-Opensearch-Nonce' not in request_header:
            request_header['X-Opensearch-Nonce'] = self.generateNonce()
        if 'Authorization' not in request_header:
            request_header['Authorization'] = self.buildAuthorization(uri,
                                                                      access_key,
                                                                      secret,
                                                                      http_params,
                                                                      request_header)
        key_del = []
        for key, value in request_header.items():
            if value is None:
                key_del.append(key)

        for key in key_del:
            del request_header[key]

        return request_header


api = V3Api(address=internet_host, port='80')


def search(params, appname, fetch_fields):
    '''
    開放搜索查詢
    :param params: 查詢條件
    :param appname: app名稱
    :param fetch_fields: 返回字段
    :return:
    '''
    query_params = {'query': '&&'.join(params.values()), 'fetch_fields': fetch_fields}
    results = api.runQuery(app_name=appname,
                           access_key=accesskey_id,
                           secret=accesskey_secret,
                           http_params=query_params,
                           http_header={})
    if results[0] == 200 and results[2]['status'] != 'FAIL':
        return results[2]['result']
    elif results[0] == 200:
        logger.error(results[2]['errors'])
        logger.error(query_params)
    return '查詢失敗'


def land_search_of_area(areas, coordinates, limit=1):
    '''
    查詢指定區域內多邊形內的土地
    :param coordinates: 類似'121.415652\,31.299175\,121.44771\,31.307169\,121.451723\,31.297287\,121.449727\,31.289164\,121.442088\,31.28513\,121.434364\,31.287165'
    :return:
    '''
    query = ' OR '.join('area:"{}"'.format(area) for area in areas.strip(' ,').split(','))
    fetch_fields = 'landid;area;plate;landname;electronicmap;location'
    limit_str = 'start:0,hit:{},'.format(limit)
    params = {
        'query': 'query={}'.format(query),
        'config': 'config={}format:json'.format(limit_str),
        'filter': 'filter=in_query_polygon("polygons",location)>0',
        'kvpairs': 'kvpairs=polygons:{}'.format(coordinates),
    }
    app_name = land_name
    return search(params, app_name, fetch_fields)


def land_search(coordinates, limit=1):
    '''
    查詢多邊形內的土地
    :param coordinates: 類似'121.415652\,31.299175\,121.44771\,31.307169\,121.451723\,31.297287\,121.449727\,31.289164\,121.442088\,31.28513\,121.434364\,31.287165'
    :return:
    '''
    fetch_fields = 'landid;color;landname;electronicmap;location'
    limit_str = 'start:0,hit:{},'.format(limit)
    params = {
        'query': 'query=area:"嘉定" OR area:"奉賢" OR area:"寶山" OR area:"崇明" OR area:"徐匯" OR area:"普陀" OR area:"楊浦" OR area:"松江" OR area:"浦東" OR area:"虹口" OR area:"金山" OR area:"長寧" OR area:"閔行" OR area:"青浦" OR area:"靜安" OR area:"黃浦"',
        'config': 'config={}format:json'.format(limit_str),
        'filter': 'filter=in_query_polygon("polygons",location)>0',
        'kvpairs': 'kvpairs=polygons:{}'.format(coordinates),
    }
    app_name = land_name
    return search(params, app_name, fetch_fields)


def build_search(coordinates, limit=1):
    '''
    查詢多邊形內的幢號
    :param coordinates: 類似'121.415652\,31.299175\,121.44771\,31.307169\,121.451723\,31.297287\,121.449727\,31.289164\,121.442088\,31.28513\,121.434364\,31.287165'
    :return:
    '''
    fetch_fields = 'id;floorno;buildingsid_c;coordinate'
    limit_str = 'start:0,hit:{},'.format(limit)
    params = {
        'query': 'query=area:"嘉定" OR area:"奉賢" OR area:"寶山" OR area:"崇明" OR area:"徐匯" OR area:"普陀" OR area:"楊浦" OR area:"松江" OR area:"浦東" OR area:"虹口" OR area:"金山" OR area:"長寧" OR area:"閔行" OR area:"青浦" OR area:"靜安" OR area:"黃浦"',
        'config': 'config={}format:json'.format(limit_str),
        'filter': 'filter=in_query_polygon("polygons",location)>0',
        'kvpairs': 'kvpairs=polygons:{}'.format(coordinates),
    }
    app_name = buildings_name
    return search(params, app_name, fetch_fields)


if __name__ == '__main__':
    # land_res = land_search(
    #     '121.415652\,31.299175\,121.44771\,31.307169\,121.451723\,31.297287\,121.449727\,31.289164\,121.442088\,31.28513\,121.434364\,31.287165')
    land_res = build_search(
        '121.415652\,31.299175\,121.44771\,31.307169\,121.451723\,31.297287\,121.449727\,31.289164\,121.442088\,31.28513\,121.434364\,31.287165')
    # land_res = land_search_of_area("靜安,閔行",
    #                                '121.415652\,31.299175\,121.44771\,31.307169\,121.451723\,31.297287\,121.449727\,31.289164\,121.442088\,31.28513\,121.434364\,31.287165')
    print(land_res)

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章