【问题标题】:Optimizing speed of python code that tests results of an API优化测试 API 结果的 python 代码的速度
【发布时间】:2018-09-18 23:53:27
【问题描述】:

我正在尝试测试一个公开可用的网页,该网页接受 GET 请求并根据 GET 参数返回不同的 JSON 文件。

API 看起来像

https://www.example.com/api/page?type=check&code=[Insert string here]

我编写了一个程序来检查此 API 上所有可能的 4 字母字符串的结果。我的代码看起来像这样(替换了实际的 URL):

import time, urllib.request

for a in "ABCDEFGHIJKLMNOPQRSTUVWXYZ":
    for b in "ABCDEFGHIJKLMNOPQRSTUVWXYZ":
        for c in "ABCDEFGHIJKLMNOPQRSTUVWXYZ":
            for d in "ABCDEFGHIJKLMNOPQRSTUVWXYZ":
                a,b,c,d = "J","A","K","E"
                test = urllib.request.urlopen("https://www.example.com/api/page?type=check&code=" + a + b + c + d).read()
                if test != b'{"result":null}':
                    print(a + b + c + d)
                    f = open("codes", "a")
                    f.write(a + b + c + d + ",")
                    f.close()

此代码功能齐全,可以按预期工作。但是,有一个问题。因为程序在收到响应之前无法继续,所以这种方法非常慢。如果这个 API 的 ping 时间是 100 毫秒,那么每次检查需要 100 毫秒。当我修改这段代码以便它可以在一个实例中测试一半的结果,在另一个实例中测试一半时,我注意到速度翻了一番。

因此,我相信网站的 ping 时间是此脚本的限制因素。我想要做的是能够基本上检查每个代码,然后立即检查下一个而不等待响应。

这相当于在我的浏览器中打开页面几千次。它可以同时加载许多选项卡,因为每个页面都小于一千字节。

我研究过使用线程来执行此操作,但我不确定它是否相关或有用。

【问题讨论】:

    标签: python python-3.x multithreading urllib python-3.7


    【解决方案1】:

    使用工作池,如下所述:https://docs.python.org/3.7/library/multiprocessing.html

    from multiprocessing import Pool
    
    def test_url(code):
        ''' insert code to test URL '''
        pass
    
    if __name__ == '__main__':
        with Pool(5) as p:
            print(p.map(test_url, [code1,code2,code3]))
    

    请注意,网站可能会限制您发出的请求数量。

    为了更具体地说明您的示例,我将其分为两个阶段:(1) 生成测试代码 (2) 测试网址,给定一个测试代码 .生成生成的代码列表后,您可以将上述策略应用到每个生成的代码中,使用工作池。

    要生成测试代码,可以使用itertools:

    codes_to_test = [''.join(i) for i in itertools.product(string.ascii_lowercase, repeat = 5)]
    

    您对如何在给定一个测试代码的情况下测试 URL 有了更好的理解,因此我假设您可以编写一个函数 test_url(test_code) 来发出适当的 URL 请求并根据需要验证结果。然后你可以调用:

    with Pool(5) as p:
        print(p.map(test_url, test_codes))
    

    除此之外,我建议做两件事:首先确保 test_codes 不是很大(例如,通过获取这些生成代码的子列表)以确保您的代码正常工作,以及 (2)可以使用 Worker 池的大小,以免让您的机器或 API 不堪重负。

    或者,您可以使用 asyncio (https://docs.python.org/3/library/asyncio.html) 将所有内容保存在一个进程中。

    【讨论】:

    • 感谢您指出速率限制。手动查阅网站 /robots.txt 文件以检查那里的明确速率限制。如果没有,您可以使用网站的响应时间来插入每个请求的等待时间。
    • 你能告诉我这在我的代码上下文中是如何工作的吗?比如我将如何在其中实现我的 for 循环?
    • 我用更多的细节和建议扩展了我的答案:)
    • 如果您不介意,您可以将其添加到我的问题中的代码中吗?我试过这样做pastebin.com/raw/etWiw87L,但没有成功
    • test_url 将采用一个参数,该参数已经是由 5 个字母组成的代码。因此,将参数名称更改为code,并将构建 url 的方式更改为'...code='+ code。最后你不需要pass(在我的例子中它只是表明函数是空的)
    猜你喜欢
    • 2012-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多