python - 非标准图像分析 API 失败,出现 urllib2 错误 : Temporary failure in name resolution

标签 python image api urllib2

这来自face++网站。一个简单的 Python 脚本接受图像 URL 并返回图像中面部的面部分析。

API_KEY = '<your API key here>'
API_SECRET = '<your API secret here>'

# Import system libraries and define helper functions
import time
from pprint import pformat
def print_result(hint, result):
    def encode(obj):
        if type(obj) is unicode:
            return obj.encode('utf-8')
        if type(obj) is dict:
            return {encode(k): encode(v) for (k, v) in obj.iteritems()}
        if type(obj) is list:
            return [encode(i) for i in obj]
        return obj
    print hint
    result = encode(result)
    print '\n'.join(['  ' + i for i in pformat(result, width = 75).split('\n')])

# First import the API class from the SDK
# 首先,导入SDK中的API类
from facepp import API

api = API(API_KEY, API_SECRET)

# Here are the person names and their face images
# 人名及其脸部图片
IMAGE_DIR = 'http://cn.faceplusplus.com/static/resources/python_demo/'
PERSONS = [
    ('Jim Parsons', IMAGE_DIR + '1.jpg'),
    ('Leonardo DiCaprio', IMAGE_DIR + '2.jpg'),
    ('Andy Liu', IMAGE_DIR + '3.jpg')
]
TARGET_IMAGE = IMAGE_DIR + '4.jpg'

# Step 1: Detect faces in the 3 pictures and find out their positions and
# attributes
# 步骤1:检测出三张输入图片中的Face,找出图片中Face的位置及属性

FACES = {name: api.detection.detect(url = url)
        for name, url in PERSONS}

for name, face in FACES.iteritems():
    print_result(name, face)

输出如下:

Jim Parsons

      {'face': [{'attribute': {'age': {'range': 7, 'value': 33},
                               'gender': {'confidence': 99.94,
                                          'value': 'Male'},
                               'race': {'confidence': 99.6939,
                                        'value': 'White'},
                               'smiling': {'value': 2.71368}},
                 'face_id': '830ddcd5b598d5feb545a613e3cb5e59',
                 'position': {'center': {'x': 42.307692, 'y': 23.5},
                              'eye_left': {'x': 37.637557, 'y': 20.637333},
                              'eye_right': {'x': 46.111991, 'y': 19.983833},
                              'height': 14.0,
                              'mouth_left': {'x': 39.380317, 'y': 27.826667},
                              'mouth_right': {'x': 46.24457, 'y': 27.269333},
                              'nose': {'x': 41.688009, 'y': 24.5085},
                              'width': 19.004525},
                 'tag': ''}],
       'img_height': 1220,
       'img_id': '518b8d3aca3a0b4d43183fba4939c9eb',
       'img_width': 900,
       'session_id': '7137fea60f964e8cb10aec9526204185',
       'url': 'http://cn.faceplusplus.com/static/resources/python_demo/1.jpg'}
    Andy Liu
      {'face': [{'attribute': {'age': {'range': 7, 'value': 40},
                               'gender': {'confidence': 99.9976,
                                          'value': 'Male'},
                               'race': {'confidence': 80.2355,
                                        'value': 'Asian'},
                               'smiling': {'value': 21.9477}},
                 'face_id': 'c38a15080defaabebea4efa5e4bd466b',
                 'position': {'center': {'x': 58.363636, 'y': 38.106796},
                              'eye_left': {'x': 50.705455, 'y': 29.711408},
                              'eye_right': {'x': 66.452, 'y': 30.17233},
                              'height': 42.718447,
                              'mouth_left': {'x': 52.394, 'y': 53.006068},
                              'mouth_right': {'x': 65.139091,
                                              'y': 52.509951},
                              'nose': {'x': 56.065636, 'y': 43.470874},
                              'width': 32.0},
                 'tag': ''}],
       'img_height': 412,
       'img_id': 'bf382efa07150a240aaf85e70cba4537',
       'img_width': 550,
       'session_id': '2bcfaa61ffc047ffa493e169a124bc05',
       'url': 'http://cn.faceplusplus.com/static/resources/python_demo/3.jpg'}
    Leonardo DiCaprio
      {'face': [{'attribute': {'age': {'range': 5, 'value': 24},
                               'gender': {'confidence': 99.9998,
                                          'value': 'Male'},
                               'race': {'confidence': 99.5828,
                                        'value': 'White'},
                               'smiling': {'value': 6.56214}},
                 'face_id': '6cc1d6261835ef58a9325de9cc9ca4e8',
                 'position': {'center': {'x': 42.75, 'y': 49.916388},
                              'eye_left': {'x': 32.551, 'y': 44.078428},
                              'eye_right': {'x': 51.022667, 'y': 42.1801},
                              'height': 38.628763,
                              'mouth_left': {'x': 36.497333, 'y': 61.53495},
                              'mouth_right': {'x': 50.798, 'y': 61.055017},
                              'nose': {'x': 42.608167, 'y': 53.22592},
                              'width': 38.5},
                 'tag': ''}],
       'img_height': 598,
       'img_id': '399ed42afa5637b3e28b5ff7bec36787',
       'img_width': 600,
       'session_id': '93c4e7d442e84b1fa2ed42f5767e08fe',
       'url': 'http://cn.faceplusplus.com/static/resources/python_demo/2.jpg'}

如果你仔细看上面的代码,你会发现这些是来自faceplusplus网站的库存图片。我显然想使用其他图像,并且能够使用互联网上的其他图像来这样做。

但是,如果我尝试使用 Instagram 图像的 URL,例如传递以下 URL- https://scontent.cdninstagram.com/t51.2885-15/s640x640/sh0.08/e35/929449_1540098689645789_1761267313_n.jpg?ig_cache_key=MTE1NTQ0Nzc0Mzg5MjIyMzY5OQ%3D%3D.2,我会收到错误消息

错误如下:

Traceback (most recent call last):
  File "hello.py", line 70, in <module>
    for name, url in PERSONS}
  File "hello.py", line 70, in <dictcomp>
    for name, url in PERSONS}
  File "C:\Users\ssh105\facepp-python-sdk-master\facepp.py", line 237, in __call__
    raise APIError(e.code, url, e.read())
facepp.APIError: code=432
url=http://api.faceplusplus.com/detection/detect?url=http%3A%2F%2Forigincache-frc.fbcdn.net%2F12545241_601559039998519_1096073656_n.jpg&api_secret=XXX
XXXXX&api_key=XXXXXXX
{
    "error": "IMAGE_ERROR_FAILED_TO_DOWNLOAD: Temporary failure in name resolution",
    "error_code": 1302
}

因为回溯导致文件facepp.py,所以我也将其粘贴在下面:

# -*- coding: utf-8 -*-
# $File: facepp.py
# $Date: Thu May 16 14:59:36 2013 +0800
# $Author: jiakai@megvii.com
#
# This program is free software. It comes without any warranty, to
# the extent permitted by applicable law. You can redistribute it
# and/or modify it under the terms of the Do What The Fuck You Want
# To Public License, Version 2, as published by Sam Hocevar. See
# http://sam.zoy.org/wtfpl/COPYING (copied as below) for more details.
#
#                DO WHAT THE F*** YOU WANT TO PUBLIC LICENSE 
#                        Version 2, December 2004 
#
#     Copyright (C) 2004 Sam Hocevar <sam@hocevar.net> 
#
#     Everyone is permitted to copy and distribute verbatim or modified 
#     copies of this license document, and changing it is allowed as long 
#     as the name is changed. 
#
#                DO WHAT THE F*** YOU WANT TO PUBLIC LICENSE 
#       TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 
#
#      0. You just DO WHAT THE F*** YOU WANT TO. 

"""a simple facepp sdk
example:
api = API(key, secret)
api.detection.detect(img = File('/tmp/test.jpg'))"""

__all__ = ['File', 'APIError', 'API']


DEBUG_LEVEL = 1


import sys
import socket
import urllib
import urllib2
import json
import os
import os.path
import itertools
import mimetools
import mimetypes
import time
import tempfile
from collections import Iterable
from cStringIO import StringIO

class File(object):
    """an object representing a local file"""
    path = None
    content = None
    def __init__(self, path):
        self.path = path
        self._get_content()

    def _resize_cv2(self, ftmp):
        try:
            import cv2
        except ImportError:
            return False
        img = cv2.imread(self.path)
        assert img is not None and img.size != 0, 'Invalid image'
        bigdim = max(img.shape[0], img.shape[1])
        downscale = max(1., bigdim / 600.)
        img = cv2.resize(img,
                (int(img.shape[1] / downscale),
                    int(img.shape[0] / downscale)))
        cv2.imwrite(ftmp, img)
        return True

    def _resize_PIL(self, ftmp):
        try:
            import PIL.Image
        except ImportError:
            return False

        img = PIL.Image.open(self.path)
        bigdim = max(img.size[0], img.size[1])
        downscale = max(1., bigdim / 600.)
        img = img.resize(
                (int(img.size[0] / downscale), int(img.size[1] / downscale)))
        img.save(ftmp)
        return True

    def _get_content(self):
        """read image content; resize the image if necessary"""

        if os.path.getsize(self.path) > 2 * 1024 * 1024:
            ftmp = tempfile.NamedTemporaryFile(
                    suffix = '.jpg', delete = False).name
            try:
                if not (self._resize_cv2(ftmp) or self._resize_PIL(ftmp)):
                    raise APIError(-1, None, 'image file size too large')
                with open(ftmp, 'rb') as f:
                    self.content = f.read()
            finally:
                os.unlink(ftmp)
        else:
            with open(self.path, 'rb') as f:
                self.content = f.read()

    def get_filename(self):
        return os.path.basename(self.path)


class APIError(Exception):
    code = None
    """HTTP status code"""

    url = None
    """request URL"""

    body = None
    """server response body; or detailed error information"""

    def __init__(self, code, url, body):
        self.code = code
        self.url = url
        self.body = body

    def __str__(self):
        return 'code={s.code}\nurl={s.url}\n{s.body}'.format(s = self)

    __repr__ = __str__


class API(object):
    key = None
    secret = None
    server = 'http://api.faceplusplus.com/'

    decode_result = True
    timeout = None
    max_retries = None
    retry_delay = None

    def __init__(self, key, secret, srv = None,
            decode_result = True, timeout = 30, max_retries = 10,
            retry_delay = 5):
        """:param srv: The API server address
        :param decode_result: whether to json_decode the result
        :param timeout: HTTP request timeout in seconds
        :param max_retries: maximal number of retries after catching URL error
            or socket error
        :param retry_delay: time to sleep before retrying"""
        self.key = key
        self.secret = secret
        if srv:
            self.server = srv
        self.decode_result = decode_result
        assert timeout >= 0 or timeout is None
        assert max_retries >= 0
        self.timeout = timeout
        self.max_retries = max_retries
        self.retry_delay = retry_delay

        _setup_apiobj(self, self, [])

    def wait_async(self, session_id, referesh_interval = 2):
        """wait for asynchronous operations to complete"""
        while True:
            rst = self.info.get_session(session_id = session_id)
            if rst['status'] != u'INQUEUE':
                return rst
            _print_debug(rst)
            time.sleep(referesh_interval)

    def update_request(self, request):
        """overwrite this function to update the request before sending it to
        server"""
        pass


def _setup_apiobj(self, api, path):
    if self is not api:
        self._api = api
        self._urlbase = api.server + '/'.join(path)

    lvl = len(path)
    done = set()
    for i in _APIS:
        if len(i) <= lvl:
            continue
        cur = i[lvl]
        if i[:lvl] == path and cur not in done:
            done.add(cur)
            setattr(self, cur, _APIProxy(api, i[:lvl + 1]))

class _APIProxy(object):
    _api = None
    """underlying :class:`API` object"""

    _urlbase = None

    def __init__(self, api, path):
        _setup_apiobj(self, api, path)

    def __call__(self, post = False, *args, **kargs):
        if len(args):
            raise TypeError('Only keyword arguments are allowed')
        if type(post) is not bool:
            raise TypeError('post argument can only be True or False')
        form = _MultiPartForm()
        add_form = False
        for (k, v) in kargs.iteritems():
            if isinstance(v, File):
                add_form = True
                form.add_file(k, v.get_filename(), v.content)

        if post:
            url = self._urlbase
            for k, v in self._mkarg(kargs).iteritems():
                form.add_field(k, v)
            add_form = True
        else:
            url = self.geturl(**kargs)

        request = urllib2.Request(url)
        if add_form:
            body = str(form)
            request.add_header('Content-type', form.get_content_type())
            request.add_header('Content-length', str(len(body)))
            request.add_data(body)

        self._api.update_request(request)

        retry = self._api.max_retries
        while True:
            retry -= 1
            try:
                ret = urllib2.urlopen(request, timeout = self._api.timeout).read()
                break
            except urllib2.HTTPError as e:
                raise APIError(e.code, url, e.read())
            except (socket.error, urllib2.URLError) as e:
                if retry < 0:
                    raise e
                _print_debug('caught error: {}; retrying'.format(e))
                time.sleep(self._api.retry_delay)

        if self._api.decode_result:
            try:
                ret = json.loads(ret)
            except:
                raise APIError(-1, url, 'json decode error, value={0!r}'.format(ret))
        return ret

    def _mkarg(self, kargs):
        """change the argument list (encode value, add api key/secret)
        :return: the new argument list"""
        def enc(x):
            if isinstance(x, unicode):
                return x.encode('utf-8')
            return str(x)

        kargs = kargs.copy()
        kargs['api_key'] = self._api.key
        kargs['api_secret'] = self._api.secret
        for (k, v) in kargs.items():
            if isinstance(v, Iterable) and not isinstance(v, basestring):
                kargs[k] = ','.join([enc(i) for i in v])
            elif isinstance(v, File) or v is None:
                del kargs[k]
            else:
                kargs[k] = enc(v)

        return kargs

    def geturl(self, **kargs):
        """return the request url"""
        return self._urlbase + '?' + urllib.urlencode(self._mkarg(kargs)) 

    def visit(self, browser = 'chromium', **kargs):
        """visit the url in browser"""
        os.system('{0} "{1}"'.format(browser, self.geturl(**kargs)))



# ref: http://www.doughellmann.com/PyMOTW/urllib2/
class _MultiPartForm(object):
    """Accumulate the data to be used when posting a form."""

    def __init__(self):
        self.form_fields = []
        self.files = []
        self.boundary = mimetools.choose_boundary()
        return

    def get_content_type(self):
        return 'multipart/form-data; boundary=%s' % self.boundary

    def add_field(self, name, value):
        """Add a simple field to the form data."""
        self.form_fields.append((name, value))
        return

    def add_file(self, fieldname, filename, content, mimetype = None):
        """Add a file to be uploaded."""
        if mimetype is None:
            mimetype = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
        self.files.append((fieldname, filename, mimetype, content))
        return

    def __str__(self):
        """Return a string representing the form data, including attached files."""
        # Build a list of lists, each containing "lines" of the
        # request.  Each part is separated by a boundary string.
        # Once the list is built, return a string where each
        # line is separated by '\r\n'.  
        parts = []
        part_boundary = '--' + self.boundary

        # Add the form fields
        parts.extend(
            [ part_boundary,
              'Content-Disposition: form-data; name="%s"' % name,
              '',
              value,
            ]
            for name, value in self.form_fields
            )

        # Add the files to upload
        parts.extend(
            [ part_boundary,
              'Content-Disposition: file; name="%s"; filename="%s"' % \
                 (field_name, filename),
              'Content-Type: %s' % content_type,
              '',
              body,
            ]
            for field_name, filename, content_type, body in self.files
            )

        # Flatten the list and add closing boundary marker,
        # then return CR+LF separated data
        flattened = list(itertools.chain(*parts))
        flattened.append('--' + self.boundary + '--')
        flattened.append('')
        return '\r\n'.join(flattened)


def _print_debug(msg):
    if DEBUG_LEVEL:
        sys.stderr.write(str(msg) + '\n')

_APIS = [
  '/detection/detect',
  '/detection/landmark',
  '/faceset/add_face',
  '/faceset/create',
  '/faceset/delete',
  '/faceset/get_info',
  '/faceset/remove_face',
  '/faceset/set_info',
  '/group/add_person',
  '/group/create',
  '/group/delete',
  '/group/get_info',
  '/group/remove_person',
  '/group/set_info',
  '/grouping/grouping',
  '/info/get_app',
  '/info/get_face',
  '/info/get_faceset_list',
  '/info/get_group_list',
  '/info/get_image',
  '/info/get_person_list',
  '/info/get_quota',
  '/info/get_session',
  '/person/add_face',
  '/person/create',
  '/person/delete',
  '/person/get_info',
  '/person/remove_face',
  '/person/set_info',
  '/recognition/compare',
  '/recognition/group_search',
  '/recognition/identify',
  '/recognition/recognize',
  '/recognition/search',
  '/recognition/test_train',
  '/recognition/train',
  '/recognition/verify',
  '/train/group_search',
  '/train/identify',
  '/train/recognize',
  '/train/search',
  '/train/verify'
]

_APIS = [i.split('/')[1:] for i in _APIS]

我怀疑这是代理、非标准 API 的问题,或者只是处理 Instagram API 的一些问题。

最佳答案

哈哈,像往常一样我找到了答案。我让它工作了,而且我确实有一个关于为什么它不起作用的理论。

如果您注意到,API 的 URL 中有一个“cn”。这意味着它是中国服务器。在中国,Instagram 和其他社交媒体通常被禁止并因此被封锁。这就是问题所在。

有一个美国版本的 API,我没有使用它,因为我找不到 API key 和 API secret ,因此我不断收到授权错误。我在互联网上搜索了不起眼的中文网站,终于找到了一个。因此,如果您需要,请告诉我。

无论如何,谢谢,我想我只有在将问题发布到这里后才能解决问题,无论谁有帮助或没有帮助:P

关于python - 非标准图像分析 API 失败,出现 urllib2 错误 : Temporary failure in name resolution,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35449388/

相关文章:

Python 子进程超时终止

html - <img> 与背景图像 : url ('' ) in fixed header (explanation)

asp.net - Internet Explorer : whitelines around pictures, 缺少图片

python - 为什么 Django 的 related_model 属性返回字符串而不是模型实例?

python - 请澄清以下Python NumPy数组初始化和拼接示例

node.js - 获取 react 照片库中图像的链接?

javascript - 如何在成功和错误这两种情况下有效地调用 setState?

api - 通过 ShipStation API 更新订单重量

ruby-on-rails - Ruby on Rails API 教程

python - 你如何在 Python 中进行二维 (x,y) 索引?