more improvements to scrapy shell: added Request object, and support for modifying it and re-fetching it by issuing an empty 'get' command

--HG--
extra : convert_revision : svn%3Ab85faa78-f9eb-468e-a121-7cced6da292c%401037
This commit is contained in:
Pablo Hoffman 2009-04-03 04:13:21 +00:00
parent ef9f4961a1
commit 0fb3ee16d8
2 changed files with 72 additions and 33 deletions

View File

@ -50,8 +50,11 @@ Custom Shell Commands
* ``%shelp`` - show the status of your Scrapy objects and get a list of
all (Scrapy related) available objects.
* ``%get <url>``- download a new response from the given URL and update all
Scrapy objects accordingly
* ``%get [url]``- fetch a new response from the given URL and update all
Scrapy objects accordingly. If the url is omitted, the last request is
re-fetched. Since Requests are mutable objects, you can modify the Request
"in place" and issue ``get`` to fetch it again with the modifications you've
made.
These commands can be typed without the leading percent sign if you have
`automagic commands`_ enabled in IPython.
@ -73,7 +76,12 @@ Those objects are:
or a :class:`~scrapy.spider.BaseSpider` object if there is not spider
configured to process that URL
* ``response`` - a Response object of the downloaded page
* ``request`` - a :class:`~scrapy.http.Request` object of the last fetched
page. You can modify this Request "in place" and re-fetch it using the
command ``get`` without no argument.
* ``response`` - a :class:`~scrapy.http.Response` object of the last fetched
page
* ``hxs`` - a :class:`~scrapy.xpath.HtmlXPathSelector` object for the Response
of the downloaded page
@ -89,23 +97,29 @@ Example of shell session
========================
Here's an example of a typical shell session where we start by scraping the
http://scrapy.org page, and then the http://slashdot.org page. Note, however,
that the data extracted here may not be the same when you try, as those pages
are not static and could have changed by the time you test this. The purpose of
this example is just to get you familiarized with how the Scrapy shell works.
http://scrapy.org page, and then proceed to scrape the http://slashdot.org
page. Finally, we modify the (slashdot) request method to POST and re-fetch it
getting a HTTP 405 (method not allowed) error. We end the session by typing
Ctrl-D (in the ``In [6]`` prompt).
Keep in mind that the data extracted here may not be the same when you try it,
as those pages are not static and could have changed by the time you test this.
The only purpose of this example is to get you familiarized with how the Scrapy
shell works.
::
scrapy-ctl.py shell http://scrapy.org
2009-04-02 16:56:22-0300 [-] Log opened.
Starting Scrapy 0.7.0 shell...
Downloading URL... Done.
Welcome to Scrapy shell!
Fetching <http://scrapy.org>...
------------------------------------------------------------
Available Scrapy variables:
xxs: <XmlXPathSelector (http://scrapy.org)>
url: http://scrapy.org
request: <http://scrapy.org>
spider: <class 'scrapy.spider.models.BaseSpider'>
hxs: <HtmlXPathSelector (http://scrapy.org)>
item: <class 'myproject.models.Item'>
@ -127,11 +141,12 @@ this example is just to get you familiarized with how the Scrapy shell works.
Out[1]: u'Welcome to Scrapy'
In [2]: get http://slashdot.org
Downloading URL... Done.
Fetching <http://slashdot.org>...
------------------------------------------------------------
Available Scrapy variables:
xxs: <XmlXPathSelector (http://slashdot.org)>
url: http://slashdot.org
request: <http://slashdot.org>
spider: <class 'scrapy.spider.models.BaseSpider'>
hxs: <HtmlXPathSelector (http://slashdot.org)>
item: <class 'myproject.models.Item'>
@ -144,3 +159,16 @@ this example is just to get you familiarized with how the Scrapy shell works.
In [3]: hxs.x("//h2/text()").extract()
Out[3]: [u'News for nerds, stuff that matters']
In [3]: hxs.x("//h2/text()").extract()
Out[3]: [u'News for nerds, stuff that matters']
In [4]: request.method = "POST"
In [5]: get
Fetching <POST http://slashdot.org>...
2009-04-03 00:57:39-0300 [decobot/None] ERROR: Downloading <http://slashdot.org> from <None>: 405 Method Not Allowed
In [6]:
2009-04-03 01:07:12-0300 [-] Main loop terminated.

View File

@ -1,3 +1,9 @@
"""
Scrapy Shell
See documentation in docs/topics/shell.rst
"""
import os
import urllib
import urlparse
@ -28,32 +34,36 @@ class Command(ScrapyCommand):
""" You can use this function to update the Scrapy objects that will be available in the shell"""
pass
def _get_response(self, response):
self.response = response
return []
def get_url(self, url):
u = urlparse.urlparse(url)
if not u.scheme:
path = os.path.abspath(url).replace(os.sep, '/')
url = 'file://' + urllib.pathname2url(path)
self.response = None
url = url.strip()
if url:
u = urlparse.urlparse(url)
if not u.scheme:
path = os.path.abspath(url).replace(os.sep, '/')
url = 'file://' + urllib.pathname2url(path)
u = urlparse.urlparse(url)
if u.scheme not in ('http', 'https', 'file'):
print "Unsupported scheme '%s' in URL: <%s>" % (u.scheme, url)
return
if u.scheme not in ('http', 'https', 'file'):
print "Unsupported scheme '%s' in URL: <%s>" % (u.scheme, url)
return
request = Request(url, callback=self._get_response)
else:
request = self.user_ns['request'].replace(callback=self._get_response)
self.result = None
def _get_response(response):
self.result = response
return []
print "Downloading URL..."
r = Request(url, callback=_get_response)
spider = get_or_create_spider(url)
threads.blockingCallFromThread(reactor, scrapyengine.crawl, r, spider)
if self.result:
self.result.request = r
self.generate_vars(url, self.result)
print "Fetching %s..." % request
threads.blockingCallFromThread(reactor, scrapyengine.crawl, request, spider)
if self.response:
self.generate_vars(url, self.response, request)
return True
def generate_vars(self, url, response):
def generate_vars(self, url=None, response=None, request=None):
itemcls = load_object(settings['DEFAULT_ITEM_CLASS'])
item = itemcls()
self.vars['item'] = item
@ -62,6 +72,7 @@ class Command(ScrapyCommand):
self.vars['hxs'] = HtmlXPathSelector(response)
self.vars['url'] = url
self.vars['response'] = response
self.vars['request'] = request
self.vars['spider'] = spiders.fromurl(url)
self.update_vars()
self.user_ns.update(self.vars)
@ -73,7 +84,7 @@ class Command(ScrapyCommand):
for key, val in self.vars.iteritems():
print " %s: %s" % (key, val)
print "Available commands:"
print " get <url>: Fetches a new page and updates all Scrapy objects."
print " get [url]: Fetch a new URL or re-fetch current Request"
print " shelp: Prints this help."
print '-' * 60
@ -89,16 +100,16 @@ class Command(ScrapyCommand):
def _console_thread():
def _get_magic(shell, arg):
self.get_url(arg.strip())
self.get_url(arg)
def _help_magic(shell, _):
self.print_vars()
if url:
result = self.get_url(url)
if not result:
self.generate_vars(None, None)
self.generate_vars()
else:
self.generate_vars(None, None)
self.generate_vars()
try: # use IPython if available
import IPython
shell = IPython.Shell.IPShell(argv=[], user_ns=self.user_ns)