【问题标题】:How to provide a twisted reactor which is currently running?如何提供当前正在运行的双绞反应器?
【发布时间】:2017-05-16 08:53:47
【问题描述】:

我们正在尝试编写一个机器人,该机器人声称可以从报纸上抓取文章,这要归功于它的 rss 提要。 所以我们希望我们的脚本可以每天多次重复这个步骤:

1) 查看我们列出的 RSS 源

2) 识别我们尚未抓取的文章

3) 将链接添加到要抓取的 url 列表中

4) 抓取列出的网址

我们用这段代码实现了一次执行这些步骤:

rss_feeds_lemonde = [
'http://www.lemonde.fr/rss/une.xml',
'http://www.lemonde.fr/international/rss_full.xml',
'http://www.lemonde.fr/politique/rss_full.xml',
]

db = sqlite3.connect('newspaper_db')
cursor = db.cursor()
urls = []
already_met = False
site = 'lemonde'

for rss_feed in rss_feeds_lemonde:
    parsed_rss_feed = feedparser.parse(rss_feed)
    for post in parsed_rss_feed.entries:
        url = post.link
        if url.split('.')[1] == site:
            cursor.execute('''SELECT url FROM articles WHERE newspaper = site''')
            rows = cursor.fetchall()
            for row in rows:
                if row[0] == url:
                    already_met = True
            if already_met == False:
                cursor.execute('''INSERT INTO articles(url, newspaper) VALUES(?,?)''', (url, site))
                urls.append(url)
            else:
                already_met = False

cursor.close()
db.commit()
db.close()
if urls != []:
    process = CrawlerProcess()
    process.crawl(LeMondeSpider, start_urls = urls)
    process.start()

问题是扭曲反应器不可重新启动,因此它允许我们执行我们的步骤一次。在我们提供新的要抓取的 url 列表后,是否可以暂停反应器并取消暂停? 我们还有其他解决方案吗?

[edit] for notorious.no,多亏了你,这个例子现在可以正常工作了!

def run_when_crawl_done(null):
    time.sleep(10)
    urls = [
    'http://www.lefigaro.fr/elections/presidentielles/2017/05/05/35003-20170505ARTFIG00129-comment-ils-veulent-bloquer-le-pen-sans-soutenir-macron-ce-dimanche.php',
    'http://www.lefigaro.fr/elections/presidentielles/2017/05/04/35003-20170504ARTFIG00259-si-marine-le-pen-atteint-40-ca-serait-deja-une-enorme-victoire-dit-sa-niece.php',
    'http://www.lefigaro.fr/elections/presidentielles/2017/05/04/35003-20170504ARTFIG00126-emmanuel-macron-non-je-n-ai-pas-de-compte-aux-bahamas.php',
    ]
    deffered = runner.crawl(LeFigaroSpider, start_urls = urls)
    deffered.addCallback(lambda _: reactor.stop())

urls = [
'http://www.lemonde.fr/les-decodeurs/article/2017/04/26/europe-macron-emploi-la-trumpisation-de-marine-le-pen-sur-tf1_5117479_4355770.html',
'http://www.lemonde.fr/syrie/article/2017/04/26/attaque-chimique-la-france-avance-ses-preuves-contre-damas_5117652_1618247.html',
]

if urls != []:
    configure_logging()
    runner = CrawlerRunner()
    deferred = runner.crawl(LeMondeSpider, start_urls = urls)
    deferred.addCallback(run_when_crawl_done)
    reactor.run()

【问题讨论】:

  • AFAIK twister reactor 是全球性的,因此您可以将其导入并使用它做任何您想做的事情。但是查看您的代码,我认为这不是您想要做的。通常人们用好的 ol' crontabs 来解决这个问题。安排cd project && scrapy crawl spider 每 8 小时运行一次,一切顺利!如果您想要更多的原子 url 分发,我建议您查看 redis 或更具体地说是 scrapy-redis
  • 感谢您的回答。事实上,我们想做一个脚本,我们执行一次并重复我们的循环(例如每两个小时),直到我们手动停止脚本运行。我们的循环包括执行我们上面解释的步骤 1 到 4。但是是否有可能为已经打开的扭曲反应堆提供爬行?
  • 为什么?长时间运行循环几乎总是一个坏主意,只是一个 cron 或 systemd 作业。
  • 我是一个编程菜鸟,所以我不是很了解所有内容。请你能解释一下什么时候这可能是个坏主意吗?您对 cron 是正确的,但理想情况下,如果有另一个不太复杂的解决方案会更好,因为我们希望稍后再使用该程序并在其他计算机上升级它。感谢您抽出宝贵时间回答我们的问题。
  • 不要使用time.sleep这是一个阻塞调用,会阻塞reactor直到睡眠结束

标签: python scrapy twisted


【解决方案1】:

Twisted 的反应堆确实无法重启。如果你想一想,你会意识到停止一个事件循环,只是让另一个事件启动它,这是违反直觉的。大多数事件驱动的应用程序都是“长时间运行”的,除非出现严重错误,否则不应停止。

不要启动-停止-重启事件循环。启动应用程序,然后永远不要重新启动它(您正在制作一个机器人,所以我假设该机器人从不睡觉)。使用CrawlerRunner 而不是CrawlerProcess 然后执行reactor.run()。这提供了更多的灵活性,并允许您同时运行更多任务。

def run_when_crawl_done(null):
    """
    logic that will be executed after the crawl is done
    """

if urls:
    runner = CrawlerRunner()
    deferred = runner.crawl(LeMondeSpider, start_urls=urls)
    deferred.addCallback(run_when_crawl_done)
    reactor.run()

【讨论】:

  • 确实机器人从不睡觉,所以如果我理解得很好:我们可以通过将 run_when_crawl_down 定义为我们的循环来重复我们的循环,谢谢 runner.addCallback(run_when_crawl_done)?
  • 对不起,这是我的错误。 runner.crawl() 返回一个 Deferred,然后您可以将回调函数链接到它。 run_when_crawl_done 是一个在爬网完成后运行的回调函数示例。我已经更新了答案中的代码示例。至于 reactor,只有 1 个,因此您可以简单地执行 from twisted.internet import reactor 并根据需要简单地调用反应器函数。
  • 我已经用你的方法做了一个测试,但问题是它打开了我的第一个蜘蛛,而不是抓取它的一组 url,它打开了我放在回调函数中的第二个蜘蛛,然后同时抓取两组url。那是我们不想要的。我们希望第一组 url 被抓取,然后寻找另一组 url 并抓取它。感谢您的帮助。
  • 发生这种情况的原因有几个。您需要提供您的新代码,以便我有效地帮助您。只需更新您的问题并附加新代码,而无需删除原始问题。
  • 这是合乎逻辑的,因为回调函数是在deferred之后执行的,问题是defered是在reactor.run()之前执行的。那么有没有办法在 reactor.run() 停止之前执行我们的循环?
【解决方案2】:

如果你真的想让一个 python 循环运行并充当一个爬取调度程序(这通常不是一个好主意),你应该使用subprocess 模块来生成一些爬取进程:

import subprocess
import time

while True:
    subprocess.open('cd project && scrapy crawl spider') 
    time.sleep(60 * 30)

你们所有的 sql 逻辑都应该放在蜘蛛本身而不是执行脚本中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多