繁体   English   中英

为什么request.get()在循环中不起作用,而在循环之外起作用?

[英]Why a requests.get() does not work within a loop, but works outside?

我获得了从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 + '&param2=' + param2 + '&param3=' + param3

    res = requests.get(xml_url, auth = HTTPDigestAuth(keys[0], keys[1]))
    xml = res.text

    return xml

我希望此函数在采用param1param2param3的循环内工作。

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块之外)–结果”部分仅是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在外部(调用)循环中恒定,则您可能希望查看请求会话 ,这可能会使查询数量减少一半。 否则,这对您和目标服务器来说都是浪费时间,带宽和CPU周期。 请对服务器的所有者好一些。

    xml_url = 'http://www.sitetogetdata.com/xml/?param1=' + param1 + '&param2=' + param2 + '&param3=' + param3    
    res = requests.get(xml_url, auth = HTTPDigestAuth(keys[0], keys[1]))

现在这是TypeError的来源(假设您发布的是您的真实代码或足够类似的代码):您将调用程序代码中的params值显式转换为int ,现在尝试将这些int与字符串连接起来。 这是行不通的,确实会引发TypeError (由于很好的原因-默默地转换不兼容类型的语言被设计破坏了)。

通常,对于此类操作,您最好使用字符串格式而不是字符串连接,即:

xml_url = '...?param1={}&param2={}&param3={}'.format(param1, param2, param3)

这不仅更具可读性,而且会调用str() (或取决于格式说明符的适当格式函数),从而避免TypeError

但是HTTP查询字符串还有其他陷阱,并且python-requests已经知道如何从dict正确创建有效的查询字符串 ,因此您实际上应该使用:

   res = requests.get(url, params={"param1": param1, "param2": param2, "param3": param3}, ....)

错误不是来自爬网。它在以下几行中:

param1 = int(table_with_params.loc[i, 'param1']) param2 = int(table_with_params.loc[i, 'param2']) param3 = int(table_with_params.loc[i, 'param3'])

这些行之一是返回一个不能转换为int的pandas Series对象。 请原谅我的格式化,因为我是Stackoverflow的新手,也不知道如何正确格式化代码。

谢谢

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM