实现频繁调用对 Python 脚本征税的最佳方法

Posted

技术标签:

【中文标题】实现频繁调用对 Python 脚本征税的最佳方法【英文标题】:Best way to implement frequent calls to taxing Python scripts 【发布时间】:2012-07-30 12:57:36 【问题描述】:

我正在编写一些使用 mechanize 从另一个网站获取数据的 Python 代码。由于网站的复杂性,代码需要 10-30 秒才能完成。它必须通过几页之类的方式工作。

我计划相当频繁地调用这段代码。我想知道在不造成巨大服务器负载的情况下实现这样的事情的最佳方法。由于我对 python 还很陌生,我不确定该语言是如何工作的。

如果代码正在处理一个请求,而另一个用户调用了该代码,是否可以同时运行该代码的两个实例?有没有更好的方法来实现这样的东西?

我想以一种可以完成繁重任务而又不会对服务器造成太大负担的方式来设计它。

【问题讨论】:

描述脚本必须为每次调用执行的操作。 1.加载站点 2. 从站点抓取框架,自行加载框架 3. 设置表单值,提交(使用新选项更新表单) 4. 再次提交,这是一个奇怪的表单(实际上是搜索结果) 5. 提交再次(我是否要显示超过 250 个结果)第 5 步可能需要的时间最长,因为查询 250 多个结果似乎需要一段时间 过程的哪些部分是不变的? 我不确定你的意思。我总是加载相同的页面,但加载长度不同,搜索值不同。想一想,当我试图找到不同部门的商店的商品成本时。步骤 3 指定哪个部门。第 4 步表示任何超过 20 美元的商品。 【参考方案1】:

我的数据抓取脚本都使用缓存来最小化服务器上​​的负载。请务必使用 HTTP 工具,例如“If-Modified-Since”、“If-None-Match”和“Accept-Encoding: gzip”。

还可以考虑使用 multiprocessing 模块,以便您可以并行运行请求。

这是我的下载脚本的摘录:

def urlretrieve(url, filename, cache, lock=threading.Lock()):
    'Read contents of an open url, use etags and decompress if needed'    

    request = urllib2.Request(url)
    request.add_header('Accept-Encoding', 'gzip')
    with lock:
        if ('etag ' + url) in cache:
            request.add_header('If-None-Match', cache['etag ' + url])
        if ('date ' + url) in cache:
            request.add_header('If-Modified-Since', cache['date ' + url])

    try:
        u = urllib2.urlopen(request)
    except urllib2.HTTPError as e:
        return Response(e.code, e.msg, False, False)
    content = u.read()
    u.close()

    compressed = u.info().getheader('Content-Encoding') == 'gzip'
    if compressed:
        content = gzip.GzipFile(fileobj=StringIO.StringIO(content), mode='rb').read()

    written = writefile(filename, content) 

    with lock:
        etag = u.info().getheader('Etag')
        if etag:
            cache['etag ' + url] = etag
        timestamp = u.info().getheader('Date')
        if timestamp:
            cache['date ' + url] = timestamp

    return Response(u.code, u.msg, compressed, written)

缓存是shelve的一个实例,一个持久化的字典。

对下载器的调用与多处理 Pool 实例上的 imap_unordered() 并行化。

【讨论】:

看到麻烦的问题是页面实际上并没有重新加载(我相信)所以“If-Modified-Since”没有多大帮助。该页面通过 javascript 重新填充。太烦人了。 如果服务器没有利用 HTTP 缓存功能,那么最小化服务器负载是他们的问题,而不是你的问题。也就是说,许多使用 Javascript 来填充数据的网站都有禁止自动屏幕抓取的服务条款。换句话说,如果他们没有让您轻松获取数据,那么他们可能不希望您拥有这些数据。 是的,这是一个设置购买系统的组织,碰巧很困难。我猜这个系统对每个人来说都很容易使用。我亲自与组织中的一位 IT 人员交谈过,他们说如果我制作这个应用程序会很棒,但他们没有任何 API 来支持它。这个组织很大,我认为他们不会花时间为一个人实现 API。哦,我关心的不是最小化他们这边的服务器负载,我不想让我的服务器因为经常运行的长时间运行的代码而超载。【参考方案2】:

基本答案是“您可以运行任意数量的程序实例,只要它们不共享关键资源(如数据库)”。

在现实世界中,您经常需要使用 "multiprocessing module" 并正确设计您的应用程序以处理并发并避免损坏状态或死锁。

顺便说一句,多进程应用程序的设计超出了 *** 上一个简单问题的范围......

【讨论】:

是的,我认为这可能超出了简单答案的范围。我正在寻找一些关于此类事情的良好文档和实践的链接。谢谢。 嗯,这取决于你在编程和算法方面的实际技能。要学习算法,我认为像笔、纸和书这样的旧工具会更好,因为它们自然有助于让你专注于理论。对于编程,文档提供的示例是一个好的开始。【参考方案3】:

您一次可以运行多个 python 进程。至于导致服务器上的过度负载,只能通过确保在任何给定时间只有一个实例运行或其他数量的进程(比如两个)来缓解。为此,您可以查看使用锁定文件或某种系统标志、互斥锁等...

但是,限制过度使用的最好方法是限制并发运行的任务数。

【讨论】:

我想到的一种方法是让用户请求一个 php 文件,该文件将在文本文件中设置一个值(假设 1 表示搜索,0 表示什么都不做)。然后,我将每分钟运行一个 cron 作业,这将触发检查文本文件以查看它是否应该运行的 python 代码。虽然看起来很复杂。我也觉得每分钟运行一段 30 秒的代码会很费力。 类似的东西可以正常工作,但它可能会遇到一个奇怪的情况,即正在写入文件并且进程可能会得到错误的值,这可以解决,但如果你要走这条路,记住它。

以上是关于实现频繁调用对 Python 脚本征税的最佳方法的主要内容,如果未能解决你的问题,请参考以下文章

价格计算(税收和折扣)

脚本实现页面静态化

从另一个脚本调用脚本的最佳方法是啥?

C++调用Python浅析

基于Python的网页文档处理脚本实现

根据支付网关和国家/地区对 WooCommerce 自定义费用征税