【问题标题】:Error H14 heroku with selenium and fastapi using python使用 python 的 selenium 和 fastapi 错误 H14 heroku
【发布时间】:2022-07-14 05:23:41
【问题描述】:

我有一个带有 python 的 Fastapi,它可以进行某种网络抓取。 api 正确地执行了抓取部分,我通过测试确定这一点,但是当我访问 api 页面时它显示此错误:

2022-07-08T09:15:12.564152+00:00 app[worker.1]: INFO: Started server process [4]
2022-07-08T09:15:12.564200+00:00 app[worker.1]: INFO: Waiting for application startup.
2022-07-08T09:15:12.564650+00:00 app[worker.1]: INFO: Application startup complete.
2022-07-08T09:15:12.565232+00:00 app[worker.1]: INFO: Uvicorn running on http://0.0.0.0:47436 (Press CTRL+C to quit)
2022-07-08T09:16:05.643153+00:00 heroku[router]: at=error code=H14 desc="No web processes running" method=GET path="/" host=cryptic-plateau-86689.herokuapp.com request_id=504c098c-a538-418b-898c-70ed38496780 fwd="156.146.59.25" dyno= connect= service= status=503 bytes= protocol=https

这是我的脚本的一个小sn-p

dict = Scraping().get_books() # this is the web scraping part
app = FastAPI()
@ app.get("/")
def home():
      """Gets everything"""
      return dict

这是我的 Procfile:

worker: uvicorn main:app --host=0.0.0.0 --port=${PORT:-5000}

请注意,我尝试使用 web 而不是 worker,但随后又遇到了另一个错误

 Error R10 (Boot timeout) -> Web process failed to bind to $PORT within 60 seconds of launch 

请注意,Scraping().get_books() 需要很长时间(2-5 分钟),这就是为什么我认为在使用 web 时会导致超时。

请记住,我是一个初学者,我的想法是这样的:我认为worker 可以做网络抓取部分,但不能处理 api 部分。另一方面,web 可以处理 api 部分,但不能进行网页抓取。这个理论正确吗?如果是,我怎样才能同时使用 web 和 worker 来完成不同的任务?

【问题讨论】:

  • 这可能不是您的问题的直接原因,但请注意使用 dict 名称作为变量,因为这会用您新分配的值覆盖 python 中的 dict 关键字,这可能会导致不可预见的问题,尝试将其重命名为其他名称并从那里开始

标签: python web-scraping heroku


【解决方案1】:

你自己已经部分回答了这个问题:你得到 heroku 错误的原因是你没有定义一个 web 进程,你 need to use to expose a web API。您还给出了当您确实使用web 进程时出现另一个错误的原因:第一行 (dict = Scraping().get_books()) 需要 2-5 分钟才能运行,这意味着我们正在“卡住”在第一行等待,因此实际的 FastAPI 应用程序在 2-5 分钟之后才会启动,并且 heroku 有 1 分钟的超时时间来启动 API。

另外,旁注:dict 是 Python 中的保留关键字,因此您真的不应该将它用于变量名。尝试找到一个更具描述性的名称,例如book_dict.

那么可以做些什么来解决这个问题?首先,抓取应该多久运行一次?目前,您只运行一次(在启动应用程序时),然后在您重新启动它之前一直修复它。这对我来说似乎有点奇怪(在这种情况下,您可以运行一次抓取部分,将其保存到 json 文件中,然后读取并返回它)。所以,我假设你至少有时想刷新它。您可以在 home 方法中运行 Scraping().get_books(),但通常认为 HTTP 事务超过几秒钟是不好的做法,并且通常会导致超时。

首先,我会考虑为什么抓取工作需要这么长时间。您是否浏览了很多页面,如果是这样,您是否可以将其拆分为一个包含一系列页面的函数?或者,看看您是否可以直接从底层 API 获取数据,而不是使用 selenium(参见例如this video)。

但如果无法加快抓取速度,有几种方法可以处理“长时间运行的事务”。对此没有一刀切的解决方案,但我会提供一些建议:

  1. 最简单的解决方案可能是在同一进程中运行网页抓取,但在后台线程中:

    import asyncio
    
    book_dict = {}
    
    async def refresh_books():
        global book_dict 
        book_dict = await asyncio.to_thread(Scraping().get_books)
    

    然后您可以使用fastapi-utils library's @repeat_every 一天左右运行几次。

  2. 查看任务队列库,例如Celery。这是一种运行后台任务的更健壮的方式(但也更复杂),您将同时拥有webworker 进程,并使用消息队列进行通信(我建议RabbitMQ on heroku)。然后,您将拥有一个 API 方法来启动抓取任务并立即返回任务 ID,然后是另一个使用该 ID 获取任务结果的方法。在这里,您还可以根据需要安排该作业每天运行几次。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-08-18
    • 2020-06-19
    • 2014-08-25
    • 2020-12-27
    • 2012-04-15
    • 2021-04-27
    • 2021-04-16
    相关资源
    最近更新 更多