python - 为什么 requests.get() 在循环中不起作用,但在外部起作用?
问题描述
我得到了这个函数来从 XML 中提取数据(内部网络,出于安全原因,我无法提供 URL):
def crawl_and_get_data(url, keys, param1, param2, param3):
r = requests.get(url, auth = HTTPDigestAuth(keys[0], keys[1]))
xml_url = 'http://www.sitetogetdata.com/xml/?param1=' + param1 + '¶m2=' + param2 + '¶m3=' + param3
res = requests.get(xml_url, auth = HTTPDigestAuth(keys[0], keys[1]))
xml = res.text
return xml
我希望这个函数在一个循环中工作,该循环需要param1
,param2
和param3
.
frames = []
for i in range(len(table_with_params)):
try:
param1 = int(table_with_params.loc[i, 'param1'])
param2 = int(table_with_params.loc[i, 'param2'])
param3 = int(table_with_params.loc[i, 'param3'])
data = crawl_and_get_data(url, keys, param1, param2, param3)
frames.append(data)
except TypeError:
print('Whoops, something is wrong with this request.')
continue
对于大多数情况,它有效,但对于某些特定情况,它不起作用。执行后,我尝试再次获取数据,但在循环之外,它可以工作。
data = crawl_and_get_data(url, keys, problematic_param1, problematic_param2, problematic_param3)
# it works!
有什么提示吗?提前致谢。
编辑:跳过异常处理,返回的错误是:
TypeError: cannot convert the series to <class 'int'>
当函数退出循环时不会抛出此错误。
解决方案
HTTP 请求失败的原因有很多,它们有时会成功是一个奇迹,所以你最好为失败的请求做好准备。话虽这么说,您的问题实际上可能完全出在其他地方,并且您的(相当糟糕的)异常处理使您无法获得任何提示。
您的第一个问题是您的 try 块太大,您想将 try 块限制为严格的必要条件。第二个问题是您完全忽略了实际的异常,只是打印了一条完全无用的消息。
目前,您的 try 块中主要包含三个不同的部分:准备请求的参数、执行请求本身(实际上是 2 个请求)以及对结果执行某些操作。这些部分中的每一个都可以引发它自己的特定异常,因此一个适当的异常处理方案是将每个部分放在一个不同的 try 块中(或者如果你不期望有什么特别的,至少在其他 try 块之外 - “做某事结果“部分是 just frames.append(data)
,它并不真正保证 try/except 块)。IOW,你想要这样的东西:
try:
param1 = int(table_with_params.loc[i, 'param1'])
param2 = int(table_with_params.loc[i, 'param2'])
param3 = int(table_with_params.loc[i, 'param3'])
except TypeError as e:
print("invalid source value at row {} : {}".format(i, e))
continue
try:
data = crawl_and_get_data(url, keys, param1, param2, param3)
你不应该在这里得到任何 TypeError - 理论上,也就是说,看看下面可能是你真正的问题
except RequestError as e:
print("Failed request for row {} : {}".format(i, e))
continue
frames.append(data)
请注意,使用该logging
模块会更好,特别是因为它知道如何正确记录完整的错误回溯(通常包含非常有价值的调试信息)。
另请注意:
def crawl_and_get_data(url, keys, param1, param2, param3):
r = requests.get(url, auth = HTTPDigestAuth(keys[0], keys[1]))
如果目标是登录并且 url 在外部(调用)循环中保持不变,您可能希望查看 requests 会话,这可能会使查询数量减半。否则,这对您和目标服务器来说有点浪费时间、带宽和 CPU 周期。请善待服务器的主人。
xml_url = 'http://www.sitetogetdata.com/xml/?param1=' + param1 + '¶m2=' + param2 + '¶m3=' + param3
res = requests.get(xml_url, auth = HTTPDigestAuth(keys[0], keys[1]))
现在这里是 a 的来源TypeError
(假设您发布的是您的真实代码或足够类似的代码):您明确地将参数值转换int
为调用者代码中的值,现在尝试将这些整数与字符串连接起来。这不起作用并且TypeError
确实引发了(出于很好的原因 - 默默地强制转换不兼容类型的语言被设计破坏)。
作为一般规则,对于此类操作,您应该更好地使用字符串格式而不是字符串连接,即:
xml_url = '...?param1={}¶m2={}¶m3={}'.format(param1, param2, param3)
这不仅更具可读性,而且会调用str()
(或取决于格式说明符的适当格式函数),避免使用TypeError
.
但是 HTTP 查询字符串还有其他陷阱,并且python-requests
已经知道如何从 dict 正确创建有效的查询字符串,因此您应该实际使用:
res = requests.get(url, params={"param1": param1, "param2": param2, "param3": param3}, ....)
推荐阅读
- python - 过滤具有多个未知列和条件的数据框
- javascript - Richtextbox (RTE) link.aspx 自定义链接不可点击
- c# - C# Teigha(Auto Cad),如何设置 mline 元素计数?
- java - 缺少权限的正确 SQLException / spring 数据异常是什么
- swift - 快速退出协调器模式中的协调器
- reactjs - 使用 React.clone 元素与不使用它来应用道具
- asp.net-core - Blazor - 应用程序洞察遥测中缺少用户
- web-services - Webservice SOAP XML 请求在 Axis2 Webservice 中不起作用
- flutter - 在颤振中从父小部件调用 setState 不会更新状态
- rest - 克隆现有的 Web 服务