AttributeError: 'tuple' object has no attribute 'timeout' - urllib request in Python3
AttributeError: 'tuple' object has no attribute 'timeout' - urllib request in Python3
我正在使用 urllib 发出请求并返回一些数据:
queryURL = "https://hazards.fema.gov/gis/nfhl/rest/services/CSLF/Prelim_CSLF/MapServer/3/query"
params = urllib.parse.urlencode({'f': 'json', 'geometryType': 'esriGeometryPolygon', 'outFields': 'OBJECTID, SHAPE, CSLF_ID, Area_SF', 'returnGeometry': 'false'})
直到这里我才 运行 遇到任何问题:
req = urllib.request.urlretrieve(queryURL, params)
然后:
urllib.request.urlopen(req)
此时我收到一个错误 - AttributeError: 'tuple' object has no attribute 'timeout'.
我知道它返回一个不可变的元组,因为我格式化 params
变量的方式。我的问题是,如何解决这个问题,以便我可以开始查看我的结果?
jsonResult = json.load(response)
根据要求,这是回溯:
AttributeError Traceback (most recent call last) <ipython-input-68-cb3f46b2da76> in <module>()
----> 1 urllib.request.urlopen(req)
C:\Program Files\ArcGIS\Pro\bin\Python\envs\arcgispro-py3\lib\urllib\request.py in urlopen(url, data, timeout, cafile, capath, cadefault, context)
221 else:
222 opener = _opener
--> 223 return opener.open(url, data, timeout)
224
225 def install_opener(opener):
C:\Program Files\ArcGIS\Pro\bin\Python\envs\arcgispro-py3\lib\urllib\request.py in open(self, fullurl, data, timeout)
515 req.data = data
516
--> 517 req.timeout = timeout
518 protocol = req.type
519
AttributeError: 'tuple' object has no attribute 'timeout'
核心问题是这段代码没有任何意义:
req = urllib.request.urlretrieve(queryURL, params)
urllib.request.urlopen(req)
urlretrieve
为您发起网络请求,将结果保存在本地文件中,然后 returns "a tuple (filename, headers)
".
您正在尝试将 (filename, headers)
对传递给 urlopen
。但是 urlopen
不知道该怎么办;它需要 URL 字符串或 Request
object,而 (filename, headers)
对两者都不是。
此外,您甚至想要它做什么也不清楚。您已经提取请求并将结果保存在文件中。为什么要再次获取相同的请求?
简单的答案是,如果您不需要,就不要使用 urlretrieve
。 (特别是因为它已经被弃用了……)就这样做:
response = urllib.request.urlopen(queryURL, params)
此外,请注意我将 urlopen
的结果保存在一个变量中。如果您不这样做,您只是在发出请求并丢弃响应,这不是很有用。 jsonResult = json.load(response)
会给你一个 NameError
,因为你从未创建任何名为 response
.
的东西
但是,您的代码仍然(至少)存在另外两个问题。
首先,正如 urlencode
的文档所说:
If the resultant string is to be used as a data for POST … then it should be encoded to bytes, otherwise it would result in a TypeError
.
但你没有那样做。
其次,如果你想发送url-encoded数据作为你的POSTbody,你需要手动设置Content-Type
header这样说.
有些服务器即使你弄错了也会猜对,但这真的不是你应该依赖的东西。
最后,如果您按照 urllib.request
文档顶部的建议进行操作,所有这些都会变得容易得多:
See also: The Requests package is recommended for a higher-level HTTP client interface.
有了请求,整个事情就变成了:
queryURL = "https://hazards.fema.gov/gis/nfhl/rest/services/CSLF/Prelim_CSLF/MapServer/3/query"
params = {'f': 'json', 'geometryType': 'esriGeometryPolygon', 'outFields': 'OBJECTID, SHAPE, CSLF_ID, Area_SF', 'returnGeometry': 'false'}
jsonResult = requests.post(queryURL, data=params).json()
我正在使用 urllib 发出请求并返回一些数据:
queryURL = "https://hazards.fema.gov/gis/nfhl/rest/services/CSLF/Prelim_CSLF/MapServer/3/query"
params = urllib.parse.urlencode({'f': 'json', 'geometryType': 'esriGeometryPolygon', 'outFields': 'OBJECTID, SHAPE, CSLF_ID, Area_SF', 'returnGeometry': 'false'})
直到这里我才 运行 遇到任何问题:
req = urllib.request.urlretrieve(queryURL, params)
然后:
urllib.request.urlopen(req)
此时我收到一个错误 - AttributeError: 'tuple' object has no attribute 'timeout'.
我知道它返回一个不可变的元组,因为我格式化 params
变量的方式。我的问题是,如何解决这个问题,以便我可以开始查看我的结果?
jsonResult = json.load(response)
根据要求,这是回溯:
AttributeError Traceback (most recent call last) <ipython-input-68-cb3f46b2da76> in <module>()
----> 1 urllib.request.urlopen(req)
C:\Program Files\ArcGIS\Pro\bin\Python\envs\arcgispro-py3\lib\urllib\request.py in urlopen(url, data, timeout, cafile, capath, cadefault, context)
221 else:
222 opener = _opener
--> 223 return opener.open(url, data, timeout)
224
225 def install_opener(opener):
C:\Program Files\ArcGIS\Pro\bin\Python\envs\arcgispro-py3\lib\urllib\request.py in open(self, fullurl, data, timeout)
515 req.data = data
516
--> 517 req.timeout = timeout
518 protocol = req.type
519
AttributeError: 'tuple' object has no attribute 'timeout'
核心问题是这段代码没有任何意义:
req = urllib.request.urlretrieve(queryURL, params)
urllib.request.urlopen(req)
urlretrieve
为您发起网络请求,将结果保存在本地文件中,然后 returns "a tuple (filename, headers)
".
您正在尝试将 (filename, headers)
对传递给 urlopen
。但是 urlopen
不知道该怎么办;它需要 URL 字符串或 Request
object,而 (filename, headers)
对两者都不是。
此外,您甚至想要它做什么也不清楚。您已经提取请求并将结果保存在文件中。为什么要再次获取相同的请求?
简单的答案是,如果您不需要,就不要使用 urlretrieve
。 (特别是因为它已经被弃用了……)就这样做:
response = urllib.request.urlopen(queryURL, params)
此外,请注意我将 urlopen
的结果保存在一个变量中。如果您不这样做,您只是在发出请求并丢弃响应,这不是很有用。 jsonResult = json.load(response)
会给你一个 NameError
,因为你从未创建任何名为 response
.
但是,您的代码仍然(至少)存在另外两个问题。
首先,正如 urlencode
的文档所说:
If the resultant string is to be used as a data for POST … then it should be encoded to bytes, otherwise it would result in a
TypeError
.
但你没有那样做。
其次,如果你想发送url-encoded数据作为你的POSTbody,你需要手动设置Content-Type
header这样说.
有些服务器即使你弄错了也会猜对,但这真的不是你应该依赖的东西。
最后,如果您按照 urllib.request
文档顶部的建议进行操作,所有这些都会变得容易得多:
See also: The Requests package is recommended for a higher-level HTTP client interface.
有了请求,整个事情就变成了:
queryURL = "https://hazards.fema.gov/gis/nfhl/rest/services/CSLF/Prelim_CSLF/MapServer/3/query"
params = {'f': 'json', 'geometryType': 'esriGeometryPolygon', 'outFields': 'OBJECTID, SHAPE, CSLF_ID, Area_SF', 'returnGeometry': 'false'}
jsonResult = requests.post(queryURL, data=params).json()