2017年2月5日16:36:10
开始使用API,首先要决定使用哪一款天气服务API,在浏览了长三角大区 ch3 任务提交处各位同学的经验之后选择使用心知天气。
在心知天气上注册账户之后会生成对应的“API密钥”和“用户ID”(d8u4dbx8dg5bhz5q/U76114E1B5),不过不知道怎么使用它们。看到有同学提到过心知天气上有Python的示例代码,在页面上找到了它们。
调试API示例
对于API示例中的这段request相关的示例代码我有个疑问:为什么它们没有使用到“API密钥”和“用户ID”呢?
import json
import sys
import requests
from utils.const_value import API, KEY, UNIT, LANGUAGE
from utils.helper import getLocation
def fetchWeather(location):
result = requests.get(API, params={
'key': KEY,
'location': location,
'language': LANGUAGE,
'unit': UNIT
}, timeout=1)
return result.text
if __name__ == '__main__':
location = getLocation()
result = fetchWeather(location)
print(result)
为了更具体的认识这个问题,我将这些代码拷贝到自己的Python源文件中,执行时出现如下错误:
> python Code3_1_WeatherQuery_CLI.py
Traceback (most recent call last):
File "Code3_1_WeatherQuery_CLI.py", line 5, in <module>
import requests
ImportError: No module named requests
错误提示找不到“requests”,想起卡包里面提到的requests模块是需要单独安装的,根据requests官方文档使用pip安装了requests之后,再次运行,有新的错误出现:
> python Code3_1_WeatherQuery_CLI.py
Traceback (most recent call last):
File "Code3_1_WeatherQuery_CLI.py", line 6, in <module>
from utils.const_value import API, KEY, UNIT, LANGUAGE
ImportError: No module named utils.const_value
查找Python官方文档之后没有发现“utils.const_value”与“utils.helper”的内容,再对比参照 @shippomiru 的代码,推断该utils模块是本地的应用模块,跑到心知天气的github上一看,果然如此。

于是接下来继续修改代码,要将其中utils里的一些变量替换掉,而在这个过程中也将自己上面提出的疑问解决了:示例代码当中的KEY就是注册账户时候获取到的“API密钥”。
ConnectTimeoutError 问题
修改完代码之后再次运行,发现有新的错误:
> python Code3_1_WeatherQuery_CLI.py
Traceback (most recent call last):
File "Code3_1_WeatherQuery_CLI.py", line 51, in <module>
result = fetchWeather(location)
File "Code3_1_WeatherQuery_CLI.py", line 46, in fetchWeather
}, timeout=1)
File "C:\Python27\lib\site-packages\requests\api.py", line 70, in get
return request('get', url, params=params, **kwargs)
File "C:\Python27\lib\site-packages\requests\api.py", line 56, in request
return session.request(method=method, url=url, **kwargs)
File "C:\Python27\lib\site-packages\requests\sessions.py", line 488, in request
resp = self.send(prep, **send_kwargs)
File "C:\Python27\lib\site-packages\requests\sessions.py", line 609, in send
r = adapter.send(request, **kwargs)
File "C:\Python27\lib\site-packages\requests\adapters.py", line 479, in send
raise ConnectTimeout(e, request=request)
requests.exceptions.ConnectTimeout: HTTPSConnectionPool(host='api.thinkpage.cn', port=443): Max retries exceeded with url: /v3/weather/now.json?language=zh-Hans&unit=c&location=beijing&key=d8u4dbx8dg5bhz5q (Caused by ConnectTimeoutError(<requests.packages.urllib3.connection.VerifiedHTTPSConnection object at 0x02B35950>, 'Connection to 10.144.1.10 timed out. (connect timeout=1)'))
因为在安装requests的时候曾经看到过You can upgrade to a newer version of Python to solve this.之类的提示,完整的如下。
c:\python27\lib\site-packages\pip\_vendor\requests\packages\urllib3\util\ssl_.py:318: SNIMissingWarning: An HTTPS request has been made, but the SNI (Subject Name Indication) extension to TLS is not available on this platform. This may cause the server to present an incorrect TLS certificate, which can cause validation failures. You can upgrade to a newer version of Python to solve this. For more information, see https://urllib3.readthedocs.org/en/latest/security.html#snimissingwarning.
SNIMissingWarning
c:\python27\lib\site-packages\pip\_vendor\requests\packages\urllib3\util\ssl_.py:122: InsecurePlatformWarning: A true SSLContext object is not available. This prevents urllib3 from configuring SSL appropriately and may cause certain SSL connections to fail. You can upgrade to a newer version of Python to solve this. For more information, see https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning.
InsecurePlatformWarning
Downloading requests-2.13.0-py2.py3-none-any.whl (584kB)
100% |████████████████████████████████| 593kB 6.0kB/s
Installing collected packages: requests
Successfully installed requests-2.13.0
c:\python27\lib\site-packages\pip\_vendor\requests\packages\urllib3\util\ssl_.py:122: InsecurePlatformWarning: A true SSLContext object is not available. This prevents urllib3 from configuring SSL appropriately and may cause certain SSL connections to fail. You can upgrade to a newer version of Python to solve this. For more information, see https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning.
InsecurePlatformWarning
以为我使用的Python2.7版本太老了,所以修改代码并使用Python3来执行,但问题依旧存在,提示信息类似:
> "D:\Program Files\Python3\python" Code3_1_WeatherQuery_CLI_Py3.py
Traceback (most recent call last):
File "D:\Program Files\Python3\lib\site-packages\requests\packages\urllib3\connectionpool.py", line 594, in urlopen
self._prepare_proxy(conn)
File "D:\Program Files\Python3\lib\site-packages\requests\packages\urllib3\connectionpool.py", line 810, in _prepare_proxy
conn.connect()
File "D:\Program Files\Python3\lib\site-packages\requests\packages\urllib3\connection.py", line 294, in connect
self._tunnel()
File "D:\Program Files\Python3\lib\http\client.py", line 914, in _tunnel
(version, code, message) = response._read_status()
File "D:\Program Files\Python3\lib\http\client.py", line 258, in _read_status
line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")
File "D:\Program Files\Python3\lib\socket.py", line 586, in readinto
return self._sock.recv_into(b)
socket.timeout: timed out
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "D:\Program Files\Python3\lib\site-packages\requests\adapters.py", line 423, in send
timeout=timeout
File "D:\Program Files\Python3\lib\site-packages\requests\packages\urllib3\connectionpool.py", line 649, in urlopen
_stacktrace=sys.exc_info()[2])
File "D:\Program Files\Python3\lib\site-packages\requests\packages\urllib3\util\retry.py", line 376, in increment
raise MaxRetryError(_pool, url, error or ResponseError(cause))
requests.packages.urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='api.thinkpage.cn', port=443): Max retries exceeded with url: /v3/weather/now.json?key=d8u4dbx8dg5bhz5q&location=beijing&language=zh-Hans&unit=c (Caused by ProxyError('Cannot connect to proxy.', timeout('timed out',)))
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "Code3_1_WeatherQuery_CLI_Py3.py", line 51, in <module>
result = fetchWeather(location)
File "Code3_1_WeatherQuery_CLI_Py3.py", line 46, in fetchWeather
}, timeout=1)
File "D:\Program Files\Python3\lib\site-packages\requests\api.py", line 70, in get
return request('get', url, params=params, **kwargs)
File "D:\Program Files\Python3\lib\site-packages\requests\api.py", line 56, in request
return session.request(method=method, url=url, **kwargs)
File "D:\Program Files\Python3\lib\site-packages\requests\sessions.py", line 488, in request
resp = self.send(prep, **send_kwargs)
File "D:\Program Files\Python3\lib\site-packages\requests\sessions.py", line 609, in send
r = adapter.send(request, **kwargs)
File "D:\Program Files\Python3\lib\site-packages\requests\adapters.py", line 485, in send
raise ProxyError(e, request=request)
requests.exceptions.ProxyError: HTTPSConnectionPool(host='api.thinkpage.cn', port=443): Max retries exceeded with url: /v3/weather/now.json?key=d8u4dbx8dg5bhz5q&location=beijing&language=zh-Hans&unit=c (Caused by ProxyError('Cannot connect to proxy.', timeout('timed out',)))
这样看来看与版本关系似乎不大,但为了确认问题,我将 @shippomiru 的代码拿到本地使用Python3进行调试,发现依然有问题。这样就可以知道问题肯定在我这里,出现在request安装过程当中可能性最大。
心理过程
反复尝试,但依旧没有解决问题,这个过程有点痛苦。痛苦一阵之后,反倒可以安静下来了一些,去想这种感受的原因:
- 痛苦的直接根源来自于多次受挫。
- 每次受挫之后,挫折本身带来的失望以及明天上交作业的压力叠加在一起,让感受愈发深刻。
为什么会多次受挫?思考之下与自己的准备工作有关:每一项任务其实需要一定的基础知识,对于基础知识缺乏理解的情况下仿照示例进行编码一旦碰到问题也就没有逻辑推演的基础。如此这样的准备不足,从另一个侧面来说是在基础之上花的有效时间不够。
为了逃离这个心理困境,我给自己做了如下计划:
- 承认当前风险(主要是时间)。首先在心理上减压,将“明天一定要上交作业”的心理修正为“在实践过程中尽心尽力锻炼心智”。
- 从当前错误出发,一个问题一个问题的去解决,放慢节奏,从“精确化搜索问题答案”到“模糊搜索并阅读相关内容”。
如上,问题的出现与解决计划均是围绕着“时间”。切记之后任务一定要尽早做,不到万不得已不要推迟。
继续尝试
今天继续检查这个问题,有意想不到的转机。
在昨天将问题定位到request并且决定一步一步去解决它,于是在google里面搜索SNIMissingWarning: An HTTPS request has been made, but the SNI (Subject Name Indication)并打开多个页面预备逐个阅读过去,在阅读到Having trouble using requests for urls时里面的代码示例提醒了自己:既然怀疑request问题,那为什么不先进行简单的测试呢?于是拷贝如下的代码片段进行测试:
import requests
r = requests.get('https://api.github.com/events')
使用Python2与Python3执行分别有如下执行结果,很明显打印“SNIMissingWarning”问题的确与Python的版本有关系。
lianbche@5CG44636XG D:\Learning\git\Py103\Chap3\project
> python TestRequest.py
C:\Python27\lib\site-packages\requests\packages\urllib3\util\ssl_.py:334: SNIMissingWarning: An HTTPS request has been made, but the SNI (Subject Name Indication) extension to TLS is not available on this platform. This may cause the server to present an incorrect TLS certificate, which can cause validation failures. You can upgrade to a newer version of Python to solve this. For more information, see https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
SNIMissingWarning
C:\Python27\lib\site-packages\requests\packages\urllib3\util\ssl_.py:132: InsecurePlatformWarning: A true SSLContext object is not available. This prevents urllib3 from configuring SSL appropriately and may cause certain SSL connections to fail. You can upgrade to a newer version of Python to solve this. For more information, see https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
InsecurePlatformWarning
lianbche@5CG44636XG D:\Learning\git\Py103\Chap3\project
> "D:\Program Files\Python3\python" TestRequest.py
lianbche@5CG44636XG D:\Learning\git\Py103\Chap3\project
不过留意到错误不一样,我再将自己的代码Code3_1_WeatherQuery_CLI.py运行了一遍,发现竟然可以有输出,尽管每次都会跟上“SNIMissingWarning”:
lianbche@5CG44636XG D:\Learning\git\Py103\Chap3\project
> python Code3_1_WeatherQuery_CLI.py
C:\Python27\lib\site-packages\requests\packages\urllib3\util\ssl_.py:334: SNIMissingWarning: An HTTPS request has been made, but the SNI (Subject Name Indication) extension to TLS is not available on this platform. This may cause the server to present an incorrect TLS certificate, which can cause validation failures. You can upgrade to a newer version of Python to solve this. For more information, see https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
SNIMissingWarning
C:\Python27\lib\site-packages\requests\packages\urllib3\util\ssl_.py:132: InsecurePlatformWarning: A true SSLContext object is not available. This prevents urllib3 from configuring SSL appropriately and may cause certain SSL connections to fail. You can upgrade to a newer version of Python to solve this. For more information, see https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
InsecurePlatformWarning
{"results":[{"location":{"id":"WX4FBXXFKE4F","name":"北京","country":"CN","path":"北京,北京,中国","timezone":"Asia/Shanghai",
"timezone_offset":"+08:00"},"now":{"text":"多云","code":"4","temperature":"6"},"last_update":"2017-02-06T14:52:09+08:00"}]}
hihere
- 欢迎使用简易天气查询软件 -
WQuery 2.0
[email protected]
输入<城市名称> 查询城市天气
点击< help > 查看帮助信息
点击<history> 打印历史记录
点击< quit > 退出查询软件
请输入要查询天气的城市名称:
>
也就是可以正常的获取到“天气数据”,为什么昨天在家里无法工作,今天在公司里面相同的代码却可以获取到数据呢?这不得不将其归结到网络问题了。可以正常的获取数据,但每次获取数据时候的“SNIMissingWarning”打印该怎么办?
阅读打开的第二个页面urllib3\util\ssl_.py: SNIMissingWarning, InsecurePlatformWarning,并阅读其中引用的两篇stackoverflow问答(1,2),通过执行pip install requests[security]命令来安装requests的security特性解决了它。非常棒!