diff --git a/scrapy/command/commands/crawl.py b/scrapy/command/commands/crawl.py
index 3a04423fc..f53de139d 100644
--- a/scrapy/command/commands/crawl.py
+++ b/scrapy/command/commands/crawl.py
@@ -1,6 +1,7 @@
from scrapy.command import ScrapyCommand
from scrapy.core.manager import scrapymanager
from scrapy.conf import settings
+from scrapy.utils.url import is_url
class Command(ScrapyCommand):
@@ -24,4 +25,12 @@ class Command(ScrapyCommand):
settings.overrides['CRAWLSPIDER_FOLLOW_LINKS'] = False
def run(self, args, opts):
- scrapymanager.runonce(*args)
+ for arg in args:
+ # schedule arg as url or domain
+ if is_url(arg):
+ scrapymanager.crawl_url(arg)
+ else:
+ scrapymanager.crawl_domain(arg)
+
+ # crawl just scheduled arguments without keeping idle
+ scrapymanager.start()
diff --git a/scrapy/command/commands/runspider.py b/scrapy/command/commands/runspider.py
index e18f13cdd..2bfcd87f9 100644
--- a/scrapy/command/commands/runspider.py
+++ b/scrapy/command/commands/runspider.py
@@ -52,6 +52,10 @@ class Command(ScrapyCommand):
dispatcher.connect(exporter.export_item, signal=signals.item_passed)
exporter.start_exporting()
module = _import_file(args[0])
- scrapymanager.runonce(module.SPIDER)
+
+ # schedule spider and start engine
+ scrapymanager.crawl_spider(module.SPIDER)
+ scrapymanager.start()
+
if opts.output:
exporter.finish_exporting()
diff --git a/scrapy/command/commands/start.py b/scrapy/command/commands/start.py
index 032f12bcc..2c7304787 100644
--- a/scrapy/command/commands/start.py
+++ b/scrapy/command/commands/start.py
@@ -9,4 +9,4 @@ class Command(ScrapyCommand):
return "Start the Scrapy manager but don't run any spider (idle mode)"
def run(self, args, opts):
- scrapymanager.start(*args)
+ scrapymanager.start(keep_alive=True)
diff --git a/scrapy/contrib/webconsole/spiderctl.py b/scrapy/contrib/webconsole/spiderctl.py
index 9719d12f0..933801854 100644
--- a/scrapy/contrib/webconsole/spiderctl.py
+++ b/scrapy/contrib/webconsole/spiderctl.py
@@ -135,14 +135,14 @@ class Spiderctl(object):
if "add_pending_domains" in args:
for domain in args["add_pending_domains"]:
if domain not in scrapyengine.scheduler.pending_requests:
- scrapymanager.crawl(domain)
+ scrapymanager.crawl_domain(domain)
s += "
"
s += "Scheduled spiders:
" % "".join(args["add_pending_domains"])
s += ""
if "rerun_finished_domains" in args:
for domain in args["rerun_finished_domains"]:
if domain not in scrapyengine.scheduler.pending_requests:
- scrapymanager.crawl(domain)
+ scrapymanager.crawl_domain(domain)
self.finished.remove(domain)
s += ""
s += "Re-scheduled finished spiders:
" % "".join(args["rerun_finished_domains"])
diff --git a/scrapy/core/manager.py b/scrapy/core/manager.py
index 2078aaa95..05586a117 100644
--- a/scrapy/core/manager.py
+++ b/scrapy/core/manager.py
@@ -1,5 +1,4 @@
import signal
-from collections import defaultdict
from twisted.internet import reactor
@@ -12,40 +11,6 @@ from scrapy.utils.misc import arg_to_iter
from scrapy.utils.url import is_url
from scrapy.utils.ossignal import install_shutdown_handlers, signal_names
-def _get_spider_requests(*args):
- """Collect requests and spiders from the given arguments. Returns a dict of
- spider -> list of requests
- """
- spider_requests = defaultdict(list)
- for arg in args:
- if isinstance(arg, tuple):
- request, spider = arg
- spider_requests[spider] = request
- elif isinstance(arg, Request):
- spider = spiders.fromurl(arg.url) or BaseSpider('default')
- if spider:
- spider_requests[spider] += [arg]
- else:
- log.msg('Could not find spider for request: %s' % arg, log.ERROR)
- elif isinstance(arg, BaseSpider):
- spider_requests[arg] += arg.start_requests()
- elif is_url(arg):
- spider = spiders.fromurl(arg) or BaseSpider('default')
- if spider:
- for req in arg_to_iter(spider.make_requests_from_url(arg)):
- spider_requests[spider] += [req]
- else:
- log.msg('Could not find spider for url: %s' % arg, log.ERROR)
- elif isinstance(arg, basestring):
- spider = spiders.fromdomain(arg)
- if spider:
- spider_requests[spider] += spider.start_requests()
- else:
- log.msg('Could not find spider for domain: %s' % arg, log.ERROR)
- else:
- raise TypeError("Unsupported argument: %r" % arg)
- return spider_requests
-
class ExecutionManager(object):
"""Process a list of sites or urls.
@@ -78,24 +43,44 @@ class ExecutionManager(object):
scrapyengine.configure()
self.configured = True
- def crawl(self, *args):
- """Schedule the given args for crawling. args is a list of urls or domains"""
+ def crawl_url(self, url, spider=None):
+ """Schedule given url for crawling."""
+ spider = spider or spiders.fromurl(url)
+ if spider:
+ requests = arg_to_iter(spider.make_requests_from_url(url))
+ self._crawl_requests(requests, spider)
+ else:
+ log.msg('Could not find spider for url: %s' % url, log.ERROR)
+
+ def crawl_request(self, request, spider=None):
+ """Schedule request for crawling."""
assert self.configured, "Scrapy Manager not yet configured"
- spider_requests = _get_spider_requests(*args)
- for spider, requests in spider_requests.iteritems():
- for request in requests:
- scrapyengine.crawl(request, spider)
+ spider = spider or spiders.fromurl(request.url)
+ if spider:
+ scrapyengine.crawl(request, spider)
+ else:
+ log.msg('Could not find spider for request: %s' % url, log.ERROR)
- def runonce(self, *args):
- """Run the engine until it finishes scraping all domains and then exit"""
- self.crawl(*args)
- scrapyengine.start()
- if self.control_reactor:
- reactor.run(installSignalHandlers=False)
+ def crawl_domain(self, domain):
+ """Schedule given domain for crawling."""
+ spider = spiders.fromdomain(domain)
+ if spider:
+ self.crawl_spider(spider)
+ else:
+ log.msg('Could not find spider for domain: %s' % domain, log.ERROR)
- def start(self):
+ def crawl_spider(self, spider):
+ """Schedule spider for crawling."""
+ requests = spider.start_requests()
+ self._crawl_requests(requests, spider)
+
+ def _crawl_requests(self, requests, spider):
+ for req in requests:
+ self.crawl_request(req, spider)
+
+ def start(self, keep_alive=False):
"""Start the scrapy server, without scheduling any domains"""
- scrapyengine.keep_alive = True
+ scrapyengine.keep_alive = keep_alive
scrapyengine.start()
if self.control_reactor:
reactor.run(installSignalHandlers=False)
diff --git a/scrapy/shell.py b/scrapy/shell.py
index 8af6af006..82baf63eb 100644
--- a/scrapy/shell.py
+++ b/scrapy/shell.py
@@ -104,7 +104,7 @@ class Shell(object):
signal.signal(signal.SIGINT, signal.SIG_IGN)
reactor.callInThread(self._console_thread, url)
- scrapymanager.start()
+ scrapymanager.start(keep_alive=True)
def inspect_response(self, response):
print
diff --git a/scrapy/tests/test_engine.py b/scrapy/tests/test_engine.py
index f205ff264..873e0eb30 100644
--- a/scrapy/tests/test_engine.py
+++ b/scrapy/tests/test_engine.py
@@ -97,7 +97,8 @@ class CrawlingSession(object):
dispatcher.connect(self.response_downloaded, signals.response_downloaded)
scrapymanager.configure()
- scrapymanager.runonce(self.spider)
+ scrapymanager.crawl_spider(self.spider)
+ scrapymanager.start()
self.port.stopListening()
self.wasrun = True
diff --git a/scrapy/utils/fetch.py b/scrapy/utils/fetch.py
index b489c75bf..a1eed0fd8 100644
--- a/scrapy/utils/fetch.py
+++ b/scrapy/utils/fetch.py
@@ -10,8 +10,11 @@ def fetch(urls):
commands or standalone scripts.
"""
responses = []
- requests = [Request(url, callback=responses.append, dont_filter=True) \
- for url in urls]
- scrapymanager.runonce(*requests)
+ for url in urls:
+ req = Request(url, callback=responses.append, dont_filter=True)
+ # @@@ request will require a suitable spider.
+ # If not will not be schedule
+ scrapymanager.crawl_request(req)
+ scrapymanager.start()
return responses