0

有一些 URL (domain.com/list) 列出了我需要定期抓取的 10 个链接。这些链接大约每 30 秒更改一次,因此我需要不断地重新抓取 domain.com/list 以检查新链接。由于大小的原因,爬取所有这些链接有时需要超过 30 秒,所以我不能每 30 秒执行一次脚本,因为我最终可能会遇到多个并发蜘蛛。但是,由于蜘蛛在第一次运行期间花费的时间太长而丢失一些链接是可以接受的情况。

我编写了一些蜘蛛中间件来删除已经访问过的链接(对于链接仅部分更改的情况)。我试图在该 process_spider_output 中包含一个新的对 domain.com/list 的请求,其中 dont_filter=True 以便将列表再次提供给调度程序,但我最终得到了大量这些请求。我的代码是:

def process_spider_output(self, response, result, spider):

    for i in result:
        if isinstance(i, Request):
            state = spider.state.get('crawled_links', deque([]))
            if unquote(i.url) in state or i.url in state:
                print "removed %s" % i
                continue
        yield i

    yield spider.make_requests_from_url('http://domain.com/list')

这看起来很丑陋,我不确定它是否按预期工作。我还尝试挂钩蜘蛛空闲和关闭信号以尝试重新抓取该站点但没有成功。

重新抓取特定网址以监视经常发生的更改并且不关闭正在使用的蜘蛛的最佳方法是什么?

提前致谢

4

1 回答 1

1

由于大小的原因,爬取所有这些链接有时需要超过 30 秒,所以我不能每 30 秒执行一次脚本,因为我最终可能会遇到多个并发蜘蛛。

有一种常见的做法是使用包含进程 PID 的文件作为互斥锁,如果文件存在并且进程仍在运行,则退出。如果您将爬虫代码放入具有这种结构的程序中...

import sys
import os

PIDFILE = '/tmp/mycrawler.pid'


def do_the_thing():
    # <your spider code here>


def main():

    # Check if we're already running
    if os.path.exists(PIDFILE):
        pid = int(open(PIDFILE, 'r').read())
        try:
            os.kill(pid, 0)
            print "We're already running as PID %d" % pid
            sys.exit(1)
        except OSError:
            pass

    # Write a PID file
    open(PIDFILE, 'w').write(str(os.getpid()))

    # Now do the thing, ensuring we delete PID file when done
    try:
        do_the_thing()
    finally:
        os.unlink(PIDFILE)


if __name__ == '__main__':
    main()

...然后您可以随意运行它cron,它会等到最后一个实例完成后再运行。

于 2013-05-18T14:22:55.830 回答