【问题标题】:How to store an object between script runs?如何在脚本运行之间存储对象?
【发布时间】:2018-01-29 12:27:32
【问题描述】:

我正在使用基于 Mint API 的 Python 脚本每小时提取个人财务信息。

要连接到 Mint,我执行 mint = mintapi.Mint(email, password),它通过 selenium 打开一个 Chrom 实例并登录到 Mint,并创建一个 <class 'mintapi.api.Mint'> 的对象

要刷新信息,我只需要mint.initiate_account_refresh()

但每次我运行脚本时,它都会再次执行整个登录操作。

我能否以某种方式将mint 对象存储在磁盘上,这样我就可以跳过该步骤而只刷新帐户?

【问题讨论】:

  • 您是否可以将 chrome 窗口最小化并让脚本每小时循环一次 mint.initiate_account_refresh() 而不是每小时再次调用脚本?
  • 我不熟悉 Mint API,但使用 python 中的 pickle 模块可以轻松存储对象。阅读它的文档here。当心pickle 模块有一个众所周知的安全漏洞!
  • 我将它与 bitbar (getbitbar.com) 一起使用,它将结果放在我的菜单栏中……据我所知,它必须每 x 分钟从头开始实际运行一次脚本。 pickle 似乎可以存储对象,但后来我不断收到Session has expired ...我猜这是 Mint API 的问题。 [叹气]
  • 但是每次我运行脚本时,它都会再次执行整个登录操作。,您是运行mint.initiate_account_refresh() 还是同时运行整个程序来刷新?

标签: python


【解决方案1】:

啊开源的奇迹。

很好奇,我去查看了您链接的mintapi,看看是否有什么明显和简单的方法可以在不进行繁琐设置的情况下重新创建对象实例。

事实证明,真的没有。 :(

这是实例化Mint 对象时调用的内容:

def __init__(self, email=None, password=None):
    if email and password:
        self.login_and_get_token(email, password)

如你所见,如果你不给它一个真实的emailpassword,它什么也做不了。 (作为旁注,它应该真的检查is None,但无论如何)。

因此,我们可以避免轻松轻松地完成设置过程,但现在我们需要找出如何根据以前的数据伪造设置过程。

查看.login_and_get_token(),我们看到以下内容:

def login_and_get_token(self, email, password):
    if self.token and self.driver:
        return

    self.driver = get_web_driver(email, password)
    self.token = self.get_token()

又好又简单。如果它已经有一个令牌,它就完成了,所以它消失了。如果没有,它会设置一个驱动程序,并通过调用.get_token() 来设置.token

这使得整个过程非常容易被覆盖。只需实例化一个不带参数的 Mint 对象,如下所示:

mint = mintapi.Mint()

然后设置.token就可以了:

mint.token = 'something magical'

现在您有一个处于几乎就绪状态的对象。问题是它基本上每个方法调用都依赖self.driver,包括你的.initiate_account_refresh()

def initiate_account_refresh(self):
    self.post(
        '{}/refreshFILogins.xevent'.format(MINT_ROOT_URL),
        data={'token': self.token},
        headers=JSON_HEADER)

...

def post(self, url, **kwargs):
    return self.driver.request('POST', url, **kwargs)

这看起来像是一个简单的POST,我们可以用requests.post() 调用来替换它,但我怀疑它是通过网络浏览器执行的,它依赖于某种方式的cookie 或会话存储。

如果你想进行实验,你可以像这样子类化Mint

class HeadlessMint(Mint):

    def post(self, url, **kwargs):
        return requests.post(url, **kwargs)

但我的猜测是,随着时间的推移,会有更多的问题浮出水面。

好消息是这个mintapi 项目看起来相当简单,并且重写它以不依赖网络浏览器对于有一点经验的人来说看起来不是一个不合理的项目,所以把它放在你的口袋里。


至于酸洗,我不相信它会起作用,因为我不相信子类化会起作用 - 我认为浏览器的存在很重要。即使您腌制您的mint 实例,当您尝试加载它时它也会丢失它的浏览器。

最简单的解决方案很可能是让脚本长时间运行,而不是每小时运行一次,而是运行一次,它会做它需要做的事情,然后休眠一个小时,然后再做一次。这样一来,您只需在开始时登录一次,然后它就可以在会话运行期间保持该会话。

【讨论】:

  • 人们可以使用time.sleep(3600) 来实现您的建议,因为它不是CPU intensive.
  • 是的,这就是我的建议。您认为我应该在答案中明确包含 sn-p 吗?
  • 实际上,这与 sn-p 无关,但当我阅读您的回答时,我想到了 CPU 使用率,但由于它不密集,我想我最好提一下这个事实!
【解决方案2】:

要在 Python 中存储对象,您可以使用 pickle 模块。

假设你有一个对象mint

import pickle
mint = Something.Somefunc()

with open('data.pickle','wb') as storage:
    pickle.dump(mint,storage)

对象将作为二进制字节序列保存在名为data.pickle的文件中。

要访问它,只需使用pickle.load() 函数。

import pickle

with open('data.pickle','rb') as storage:
    mint = pickle.load(storage)

>>>mint
>>><class 'something' object>

注意:

虽然这里没关系,但是pickle模块有一个缺陷,它可以在从文件加载它们的同时执行一些函数对象,所以从第三方源读取pickle存储对象时不要使用它。

【讨论】:

    【解决方案3】:

    使用库pickle 保存和加载对象

    保存

    import pickle
    
    mint = mintapi.Mint(email, password)
    with open('mint .pkl', 'wb') as output:
        pickle.dump(mint , output, pickle.HIGHEST_PROTOCOL)
    

    加载

    import pickle
    
    with open('mint.pkl', 'rb') as input:
        mint= pickle.load(input)
    
    mint.initiate_account_refresh()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-18
      • 1970-01-01
      • 2012-06-07
      • 1970-01-01
      • 1970-01-01
      • 2018-09-13
      相关资源
      最近更新 更多