【问题标题】:AttributeError: 'tuple' object has no attribute 'timeout' - urllib request in Python3AttributeError:“元组”对象没有属性“超时”-Python3 中的 urllib 请求
【发布时间】:2018-08-17 17:02:08
【问题描述】:

我正在使用 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)

根据要求,这里是 Traceback:

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'

【问题讨论】:

  • 你能告诉我们回溯,而不仅仅是错误的描述吗?
  • 好的,添加了回溯。

标签: python python-requests tuples urllib attributeerror


【解决方案1】:

核心问题是这段代码没有任何意义:

req = urllib.request.urlretrieve(queryURL, params)
urllib.request.urlopen(req)

urlretrieve 为您发出网络请求,将结果保存在本地文件中,然后返回“a tuple (filename, headers)”。

您正在尝试将 (filename, headers) 对传递给 urlopen。但是urlopen 不知道该怎么办;它需要一个 URL 字符串或一个 Request 对象,而 (filename, headers) 对都不是。

此外,您甚至想要它做什么都不清楚。您已经获取了请求并将结果保存在文件中。为什么要再次获取相同的请求?

简单的答案是,如果您不想使用urlretrieve,就不要使用它。 (特别是因为它已被弃用......)只需这样做:

response = urllib.request.urlopen(queryURL, params)

另外,请注意我将urlopen 的结果保存在一个变量中。如果你不这样做,你只是在发出请求并丢弃响应,这不是很有用。而jsonResult = json.load(response) 会给你一个NameError,因为你从未创建过任何名为response 的东西。


但是,您的代码仍然存在(至少)另外两个问题。

首先,正如urlencode 的文档所说:

如果将生成的字符串用作 POST 的数据……那么它应该被编码为字节,否则会导致 TypeError

但你没有这样做。

其次,如果你想发送 url 编码的数据作为你的 POST 正文,你需要手动设置 Content-Type 标头这样说。

即使你弄错了,有些服务器也会猜对,但这真的不是你应该依赖的。


最后,如果您按照urllib.request 文档顶部的建议进行操作,所有这一切都会变得容易得多:

另请参阅:建议将 Requests package 用于更高级别的 HTTP 客户端接口。

有了 Requests,整个事情就变成了:

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

【讨论】:

  • 这完全有效!我在查看一个与我的数据太不相似的示例时遇到了这个问题。最后一个问题:如果我想查看这些数据,查看它的最佳方式是什么?由于可能有 1000 行(不能只是 print(jsonResults)),我打算写入一个文件并执行以下操作:file = open(path, 'w') for item in jsonResult: file.write(item + "\r\n") file.close。有没有更好的办法?
  • @gwydion93 我不确定数据是什么样的,或者你想要什么格式。它只是一个字符串数组(其中没有任何换行符)并且您想要这些字符串的文件,每行一个吗?如果是这样,那么您所写的内容将会做到这一点——但如果您拥有或想要不同的东西,它就不会做不同的事情。
猜你喜欢
  • 1970-01-01
  • 2022-01-03
  • 2013-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-26
  • 2021-07-30
相关资源
最近更新 更多