【问题标题】:Run spider while web application running based on Python asyncio module在基于 Python asyncio 模块的 Web 应用程序运行时运行蜘蛛
【发布时间】:2017-01-05 04:01:57
【问题描述】:

我现在的练习:


每次刷新或加载页面时,我让我的后端捕获前端页面发送的 get 请求 来运行我的 scrapy 蜘蛛。抓取的数据将显示在我的首页。这是代码,我调用了一个子进程来运行蜘蛛:

from subprocess import run

@get('/api/get_presentcode')
def api_get_presentcode():
    if os.path.exists("/static/presentcodes.json"):
        run("rm presentcodes.json", shell=True)

    run("scrapy crawl presentcodespider -o ../static/presentcodes.json", shell=True, cwd="./presentcodeSpider")
    with open("/static/presentcodes.json") as data_file:
        data = json.load(data_file)

    logging.info(data)
    return data

效果很好。

我想要什么:


但是,蜘蛛抓取的网站几乎没有变化,因此不需要经常抓取。

所以我想在后端使用 coroutine 方法每 30 分钟运行一次我的 scrapy spider。

我尝试并成功的方法:


from subprocess import run

# init of my web application
async def init(loop):
....

async def run_spider():
    while True:
        print("Run spider...")
        await asyncio.sleep(10)  #  to check results more obviously 

loop = asyncio.get_event_loop()
tasks = [run_spider(), init(loop)]
loop.run_until_complete(asyncio.wait(tasks))
loop.run_forever()

它也很好用。

但是当我把run_spider()的代码改成这个时(和第一个基本一样):

async def run_spider():
    while True:
        if os.path.exists("/static/presentcodes.json"):
            run("rm presentcodes.json", shell=True)

        run("scrapy crawl presentcodespider -o ../static/presentcodes.json", shell=True, cwd="./presentcodeSpider")
        await asyncio.sleep(20)

蜘蛛只在第一次运行,爬取的数据成功存储到presentcode.json,但20秒后蜘蛛就再也没有调用过。

问题


  1. 我的程序出了什么问题?是不是因为我在协程中调用了子进程而无效?

  2. 在主应用程序运行时运行蜘蛛有什么更好的想法吗?

编辑:


我先把我的网络应用初始化函数的代码放在这里:

async def init(loop):
    logging.info("App started at {0}".format(datetime.now()))
    await orm.create_pool(loop=loop, user='root', password='', db='myBlog')
    app = web.Application(loop=loop, middlewares=[
        logger_factory, auth_factory, response_factory
    ])
    init_jinja2(app, filters=dict(datetime=datetime_filter))
    add_routes(app, 'handlers')
    add_static(app)
    srv = await loop.create_server(app.make_handler(), '127.0.0.1', 9000)  # It seems something happened here.
    logging.info('server started at http://127.0.0.1:9000') # this log didn't show up.
    return srv

我的想法是,主应用程序使协程事件循环“卡住”,因此蜘蛛以后无法回调。

让我看看create_serverrun_until_complete的源码..

【问题讨论】:

  • 这是一个 Python/异步问题。不是一个乱七八糟的 :) 在原则上,不要做 rm 然后 scrapy crawl 因为那样您将有一段时间没有文件并且您的请求将失败。首先将scrapy crawl 写入临时文件,例如/static/presentcodes.json.tmp 然后做一个 mv /static/presentcodes.json.tmp /static/presentcodes.json 这是 atomic-ish
  • @neverlastn 你的意思是哪个 request 会失败? REST 从网页获取请求?实际上,我现在没有使用 request,我只是让 main web applicationspider 同时运行。前端页面的文件读取和数据显示将在稍后考虑,现在它们都被“注释”了。无论如何,我会先尝试您的解决方案,谢谢!
  • 没错,你是对的!现在没有任何问题,但是使用rm+crawl,一旦您尝试对该文件执行任何操作(除非您有相对复杂的同步),您就会有不可用的时刻

标签: python subprocess python-asyncio coroutine


【解决方案1】:

可能不是一个完整的答案,我不会像你那样做。但是从 asyncio 协程中调用 subprocess 绝对是不正确的。协程提供协作式多任务处理,因此当您从协程中调用 subprocess 时,该协程会有效地停止您的整个应用程序,直到调用的进程完成为止。

使用asyncio 时需要了解的一件事是,只有在调用await(或yield from,或async forasync with 等)时,控制流才能从一个协程切换到另一个协程。快捷方式)。如果你做了一些长时间的动作而没有调用其中任何一个,那么你会阻塞任何其他协程,直到这个动作完成。

您需要使用的是asyncio.subprocess,它将在子进程运行时正确地将控制流返回到应用程序的其他部分(即网络服务器)。

这是run_spider() 协程的实际外观:

import asyncio

async def run_spider():
    while True:
        sp = await asyncio.subprocess.create_subprocess_shell(
            "scrapy srawl presentcodespider -o ../static/presentcodes.new.json",
            cwd="./presentcodeSpider")
        code = await sp.wait()
        if code != 0:
            print("Warning: something went wrong, code %d" % code)
            continue  # retry immediately
        if os.path.exists("/static/presentcodes.new.json"):
            # output was created, overwrite older version (if any)
            os.rename("/static/presentcodes.new.json", "/static/presentcodes.json")
        else:
            print("Warning: output file was not found")

        await asyncio.sleep(20)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-02-15
    • 1970-01-01
    • 2021-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多