+ “The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”
+ by Albert Einstein
+ (about)
+
+
+ “There are only two ways to live your life. One is as though nothing is a miracle. The other is as though everything is a miracle.”
+ by Albert Einstein
+ (about)
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/conf.py b/docs/conf.py
index 914d1d05f..458bc6087 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -12,6 +12,7 @@
# serve to show the default.
import sys
+from datetime import datetime
from os import path
# If your extensions are in another directory, add it here. If the directory
@@ -49,8 +50,8 @@ source_suffix = '.rst'
master_doc = 'index'
# General information about the project.
-project = u'Scrapy'
-copyright = u'2008–2018, Scrapy developers'
+project = 'Scrapy'
+copyright = '2008–{}, Scrapy developers'.format(datetime.now().year)
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
@@ -194,8 +195,8 @@ htmlhelp_basename = 'Scrapydoc'
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, document class [howto/manual]).
latex_documents = [
- ('index', 'Scrapy.tex', u'Scrapy Documentation',
- u'Scrapy developers', 'manual'),
+ ('index', 'Scrapy.tex', 'Scrapy Documentation',
+ 'Scrapy developers', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
@@ -268,6 +269,10 @@ coverage_ignore_pyobjects = [
# Never documented before, and deprecated now.
r'^scrapy\.item\.DictItem$',
+ r'^scrapy\.linkextractors\.FilteringLinkExtractor$',
+
+ # Implementation detail of LxmlLinkExtractor
+ r'^scrapy\.linkextractors\.lxmlhtml\.LxmlParserLinkExtractor',
]
diff --git a/docs/contributing.rst b/docs/contributing.rst
index 234c4bcee..f40a6bba2 100644
--- a/docs/contributing.rst
+++ b/docs/contributing.rst
@@ -44,7 +44,7 @@ guidelines when you're going to report a new bug.
* check the :ref:`FAQ ` first to see if your issue is addressed in a
well-known question
-* if you have a general question about scrapy usage, please ask it at
+* if you have a general question about Scrapy usage, please ask it at
`Stack Overflow `__
(use "scrapy" tag).
@@ -203,17 +203,9 @@ Tests are implemented using the :doc:`Twisted unit-testing framework
Running tests
-------------
-Make sure you have a recent enough :doc:`tox ` installation:
+To run all tests::
- ``tox --version``
-
-If your version is older than 1.7.0, please update it first:
-
- ``pip install -U tox``
-
-To run all tests go to the root directory of Scrapy source code and run:
-
- ``tox``
+ tox
To run a specific test (say ``tests/test_loader.py``) use:
@@ -225,11 +217,11 @@ the tests with Python 3.6 use::
tox -e py36
-You can also specify a comma-separated list of environmets, and use :ref:`tox’s
+You can also specify a comma-separated list of environments, and use :ref:`tox’s
parallel mode ` to run the tests on multiple environments in
parallel::
- tox -e py27,py36 -p auto
+ tox -e py36,py38 -p auto
To pass command-line options to :doc:`pytest `, add them after
``--`` in your call to :doc:`tox `. Using ``--`` overrides the
diff --git a/docs/faq.rst b/docs/faq.rst
index 080d81981..aae2411e0 100644
--- a/docs/faq.rst
+++ b/docs/faq.rst
@@ -338,7 +338,7 @@ How to split an item into multiple items in an item pipeline?
input item. :ref:`Create a spider middleware `
instead, and use its
:meth:`~scrapy.spidermiddlewares.SpiderMiddleware.process_spider_output`
-method for this puspose. For example::
+method for this purpose. For example::
from copy import deepcopy
diff --git a/docs/index.rst b/docs/index.rst
index 6d5f9e77d..a4343b7e0 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -170,7 +170,7 @@ Solving specific problems
Get answers to most frequently asked questions.
:doc:`topics/debug`
- Learn how to debug common problems of your scrapy spider.
+ Learn how to debug common problems of your Scrapy spider.
:doc:`topics/contracts`
Learn how to use contracts for testing your spiders.
diff --git a/docs/intro/install.rst b/docs/intro/install.rst
index e924b5303..178be723c 100644
--- a/docs/intro/install.rst
+++ b/docs/intro/install.rst
@@ -78,9 +78,9 @@ TL;DR: We recommend installing Scrapy inside a virtual environment
on all platforms.
Python packages can be installed either globally (a.k.a system wide),
-or in user-space. We do not recommend installing scrapy system wide.
+or in user-space. We do not recommend installing Scrapy system wide.
-Instead, we recommend that you install scrapy within a so-called
+Instead, we recommend that you install Scrapy within a so-called
"virtual environment" (`virtualenv`_).
Virtualenvs allow you to not conflict with already-installed Python
system packages (which could break some of your system tools and scripts),
@@ -97,7 +97,7 @@ Check this `user guide`_ on how to create your virtualenv.
.. note::
If you use Linux or OS X, `virtualenvwrapper`_ is a handy tool to create virtualenvs.
-Once you have created a virtualenv, you can install scrapy inside it with ``pip``,
+Once you have created a virtualenv, you can install Scrapy inside it with ``pip``,
just like any other Python package.
(See :ref:`platform-specific guides `
below for non-Python dependencies that you may need to install beforehand).
@@ -144,7 +144,7 @@ albeit with potential issues with TLS connections.
typically too old and slow to catch up with latest Scrapy.
-To install scrapy on Ubuntu (or Ubuntu-based) systems, you need to install
+To install Scrapy on Ubuntu (or Ubuntu-based) systems, you need to install
these dependencies::
sudo apt-get install python3 python3-dev python3-pip libxml2-dev libxslt1-dev zlib1g-dev libffi-dev libssl-dev
@@ -225,17 +225,17 @@ PyPy
We recommend using the latest PyPy version. The version tested is 5.9.0.
For PyPy3, only Linux installation was tested.
-Most scrapy dependencides now have binary wheels for CPython, but not for PyPy.
+Most Scrapy dependencides now have binary wheels for CPython, but not for PyPy.
This means that these dependecies will be built during installation.
On OS X, you are likely to face an issue with building Cryptography dependency,
solution to this problem is described
`here `_,
that is to ``brew install openssl`` and then export the flags that this command
-recommends (only needed when installing scrapy). Installing on Linux has no special
+recommends (only needed when installing Scrapy). Installing on Linux has no special
issues besides installing build dependencies.
-Installing scrapy with PyPy on Windows is not tested.
+Installing Scrapy with PyPy on Windows is not tested.
-You can check that scrapy is installed correctly by running ``scrapy bench``.
+You can check that Scrapy is installed correctly by running ``scrapy bench``.
If this command gives errors such as
``TypeError: ... got 2 unexpected keyword arguments``, this means
that setuptools was unable to pick up one PyPy-specific dependency.
@@ -272,7 +272,7 @@ For details, see `Issue #2473 `_.
.. _Python: https://www.python.org/
.. _pip: https://pip.pypa.io/en/latest/installing/
-.. _lxml: http://lxml.de/
+.. _lxml: https://lxml.de/index.html
.. _parsel: https://pypi.python.org/pypi/parsel
.. _w3lib: https://pypi.python.org/pypi/w3lib
.. _twisted: https://twistedmatrix.com/
diff --git a/docs/intro/tutorial.rst b/docs/intro/tutorial.rst
index 2f97017fc..c4d8d717b 100644
--- a/docs/intro/tutorial.rst
+++ b/docs/intro/tutorial.rst
@@ -252,30 +252,30 @@ The result of running ``response.css('title')`` is a list-like object called
and allow you to run further queries to fine-grain the selection or extract the
data.
-To extract the text from the title above, you can do::
+To extract the text from the title above, you can do:
- >>> response.css('title::text').getall()
- ['Quotes to Scrape']
+>>> response.css('title::text').getall()
+['Quotes to Scrape']
There are two things to note here: one is that we've added ``::text`` to the
CSS query, to mean we want to select only the text elements directly inside
```` element. If we don't specify ``::text``, we'd get the full title
-element, including its tags::
+element, including its tags:
- >>> response.css('title').getall()
- ['Quotes to Scrape']
+>>> response.css('title').getall()
+['Quotes to Scrape']
The other thing is that the result of calling ``.getall()`` is a list: it is
possible that a selector returns more than one result, so we extract them all.
-When you know you just want the first result, as in this case, you can do::
+When you know you just want the first result, as in this case, you can do:
- >>> response.css('title::text').get()
- 'Quotes to Scrape'
+>>> response.css('title::text').get()
+'Quotes to Scrape'
-As an alternative, you could've written::
+As an alternative, you could've written:
- >>> response.css('title::text')[0].get()
- 'Quotes to Scrape'
+>>> response.css('title::text')[0].get()
+'Quotes to Scrape'
However, using ``.get()`` directly on a :class:`~scrapy.selector.SelectorList`
instance avoids an ``IndexError`` and returns ``None`` when it doesn't
@@ -288,14 +288,14 @@ to be scraped, you can at least get **some** data.
Besides the :meth:`~scrapy.selector.SelectorList.getall` and
:meth:`~scrapy.selector.SelectorList.get` methods, you can also use
the :meth:`~scrapy.selector.SelectorList.re` method to extract using `regular
-expressions`_::
+expressions`_:
- >>> response.css('title::text').re(r'Quotes.*')
- ['Quotes to Scrape']
- >>> response.css('title::text').re(r'Q\w+')
- ['Quotes']
- >>> response.css('title::text').re(r'(\w+) to (\w+)')
- ['Quotes', 'Scrape']
+>>> response.css('title::text').re(r'Quotes.*')
+['Quotes to Scrape']
+>>> response.css('title::text').re(r'Q\w+')
+['Quotes']
+>>> response.css('title::text').re(r'(\w+) to (\w+)')
+['Quotes', 'Scrape']
In order to find the proper CSS selectors to use, you might find useful opening
the response page from the shell in your web browser using ``view(response)``.
@@ -312,12 +312,12 @@ visually selected elements, which works in many browsers.
XPath: a brief intro
^^^^^^^^^^^^^^^^^^^^
-Besides `CSS`_, Scrapy selectors also support using `XPath`_ expressions::
+Besides `CSS`_, Scrapy selectors also support using `XPath`_ expressions:
- >>> response.xpath('//title')
- []
- >>> response.xpath('//title/text()').get()
- 'Quotes to Scrape'
+>>> response.xpath('//title')
+[]
+>>> response.xpath('//title/text()').get()
+'Quotes to Scrape'
XPath expressions are very powerful, and are the foundation of Scrapy
Selectors. In fact, CSS selectors are converted to XPath under-the-hood. You
@@ -372,35 +372,35 @@ we want::
$ scrapy shell 'http://quotes.toscrape.com'
-We get a list of selectors for the quote HTML elements with::
+We get a list of selectors for the quote HTML elements with:
- >>> response.css("div.quote")
- [,
- ,
- ...]
+>>> response.css("div.quote")
+[,
+ ,
+ ...]
Each of the selectors returned by the query above allows us to run further
queries over their sub-elements. Let's assign the first selector to a
-variable, so that we can run our CSS selectors directly on a particular quote::
+variable, so that we can run our CSS selectors directly on a particular quote:
- >>> quote = response.css("div.quote")[0]
+>>> quote = response.css("div.quote")[0]
Now, let's extract ``text``, ``author`` and the ``tags`` from that quote
-using the ``quote`` object we just created::
+using the ``quote`` object we just created:
- >>> text = quote.css("span.text::text").get()
- >>> text
- '“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”'
- >>> author = quote.css("small.author::text").get()
- >>> author
- 'Albert Einstein'
+>>> text = quote.css("span.text::text").get()
+>>> text
+'“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”'
+>>> author = quote.css("small.author::text").get()
+>>> author
+'Albert Einstein'
Given that the tags are a list of strings, we can use the ``.getall()`` method
-to get all of them::
+to get all of them:
- >>> tags = quote.css("div.tags a.tag::text").getall()
- >>> tags
- ['change', 'deep-thoughts', 'thinking', 'world']
+>>> tags = quote.css("div.tags a.tag::text").getall()
+>>> tags
+['change', 'deep-thoughts', 'thinking', 'world']
.. invisible-code-block: python
@@ -409,16 +409,16 @@ to get all of them::
.. skip: next if(version_info < (3, 6), reason="Only Python 3.6+ dictionaries match the output")
Having figured out how to extract each bit, we can now iterate over all the
-quotes elements and put them together into a Python dictionary::
+quotes elements and put them together into a Python dictionary:
- >>> for quote in response.css("div.quote"):
- ... text = quote.css("span.text::text").get()
- ... author = quote.css("small.author::text").get()
- ... tags = quote.css("div.tags a.tag::text").getall()
- ... print(dict(text=text, author=author, tags=tags))
- {'text': '“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”', 'author': 'Albert Einstein', 'tags': ['change', 'deep-thoughts', 'thinking', 'world']}
- {'text': '“It is our choices, Harry, that show what we truly are, far more than our abilities.”', 'author': 'J.K. Rowling', 'tags': ['abilities', 'choices']}
- ...
+>>> for quote in response.css("div.quote"):
+... text = quote.css("span.text::text").get()
+... author = quote.css("small.author::text").get()
+... tags = quote.css("div.tags a.tag::text").getall()
+... print(dict(text=text, author=author, tags=tags))
+{'text': '“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”', 'author': 'Albert Einstein', 'tags': ['change', 'deep-thoughts', 'thinking', 'world']}
+{'text': '“It is our choices, Harry, that show what we truly are, far more than our abilities.”', 'author': 'J.K. Rowling', 'tags': ['abilities', 'choices']}
+...
Extracting data in our spider
-----------------------------
@@ -516,23 +516,23 @@ markup:
-We can try extracting it in the shell::
+We can try extracting it in the shell:
- >>> response.css('li.next a').get()
- 'Next →'
+>>> response.css('li.next a').get()
+'Next →'
This gets the anchor element, but we want the attribute ``href``. For that,
Scrapy supports a CSS extension that lets you select the attribute contents,
-like this::
+like this:
- >>> response.css('li.next a::attr(href)').get()
- '/page/2/'
+>>> response.css('li.next a::attr(href)').get()
+'/page/2/'
There is also an ``attrib`` property available
-(see :ref:`selecting-attributes` for more)::
+(see :ref:`selecting-attributes` for more):
- >>> response.css('li.next a').attrib['href']
- '/page/2/'
+>>> response.css('li.next a').attrib['href']
+'/page/2/'
Let's see now our spider modified to recursively follow the link to the next
page, extracting data from it::
diff --git a/docs/news.rst b/docs/news.rst
index 9dfd28508..6d0d4b4ee 100644
--- a/docs/news.rst
+++ b/docs/news.rst
@@ -47,13 +47,13 @@ Backward-incompatible changes
(:issue:`2111`, :issue:`3392`, :issue:`3442`, :issue:`3450`)
* :class:`~scrapy.loader.ItemLoader` now turns the values of its input item
- into lists::
+ into lists:
- >>> item = MyItem()
- >>> item['field'] = 'value1'
- >>> loader = ItemLoader(item=item)
- >>> item['field']
- ['value1']
+ >>> item = MyItem()
+ >>> item['field'] = 'value1'
+ >>> loader = ItemLoader(item=item)
+ >>> item['field']
+ ['value1']
This is needed to allow adding values to existing fields
(``loader.add_value('field', 'value2')``).
@@ -678,7 +678,7 @@ Usability improvements
* a message is added to IgnoreRequest in RobotsTxtMiddleware (:issue:`3113`)
* better validation of ``url`` argument in ``Response.follow`` (:issue:`3131`)
* non-zero exit code is returned from Scrapy commands when error happens
- on spider inititalization (:issue:`3226`)
+ on spider initialization (:issue:`3226`)
* Link extraction improvements: "ftp" is added to scheme list (:issue:`3152`);
"flv" is added to common video extensions (:issue:`3165`)
* better error message when an exporter is disabled (:issue:`3358`);
@@ -1156,7 +1156,7 @@ Bug fixes
- Fix :command:`view` command ; it was a regression in v1.3.0 (:issue:`2503`).
- Fix tests regarding ``*_EXPIRES settings`` with Files/Images pipelines (:issue:`2460`).
- Fix name of generated pipeline class when using basic project template (:issue:`2466`).
-- Fix compatiblity with Twisted 17+ (:issue:`2496`, :issue:`2528`).
+- Fix compatibility with Twisted 17+ (:issue:`2496`, :issue:`2528`).
- Fix ``scrapy.Item`` inheritance on Python 3.6 (:issue:`2511`).
- Enforce numeric values for components order in ``SPIDER_MIDDLEWARES``,
``DOWNLOADER_MIDDLEWARES``, ``EXTENIONS`` and ``SPIDER_CONTRACTS`` (:issue:`2420`).
@@ -1164,7 +1164,7 @@ Bug fixes
Documentation
~~~~~~~~~~~~~
-- Reword Code of Coduct section and upgrade to Contributor Covenant v1.4
+- Reword Code of Conduct section and upgrade to Contributor Covenant v1.4
(:issue:`2469`).
- Clarify that passing spider arguments converts them to spider attributes
(:issue:`2483`).
@@ -1178,7 +1178,7 @@ Documentation
Cleanups
~~~~~~~~
-- Remove reduntant check in ``MetaRefreshMiddleware`` (:issue:`2542`).
+- Remove redundant check in ``MetaRefreshMiddleware`` (:issue:`2542`).
- Faster checks in ``LinkExtractor`` for allow/deny patterns (:issue:`2538`).
- Remove dead code supporting old Twisted versions (:issue:`2544`).
@@ -1204,7 +1204,7 @@ New Features
- ``MailSender`` now accepts single strings as values for ``to`` and ``cc``
arguments (:issue:`2272`)
- ``scrapy fetch url``, ``scrapy shell url`` and ``fetch(url)`` inside
- scrapy shell now follow HTTP redirections by default (:issue:`2290`);
+ Scrapy shell now follow HTTP redirections by default (:issue:`2290`);
See :command:`fetch` and :command:`shell` for details.
- ``HttpErrorMiddleware`` now logs errors with ``INFO`` level instead of ``DEBUG``;
this is technically **backward incompatible** so please check your log parsers.
@@ -1360,7 +1360,7 @@ Documentation
- Grammar fixes: :issue:`2128`, :issue:`1566`.
- Download stats badge removed from README (:issue:`2160`).
-- New scrapy :ref:`architecture diagram ` (:issue:`2165`).
+- New Scrapy :ref:`architecture diagram ` (:issue:`2165`).
- Updated ``Response`` parameters documentation (:issue:`2197`).
- Reworded misleading :setting:`RANDOMIZE_DOWNLOAD_DELAY` description (:issue:`2190`).
- Add StackOverflow as a support channel (:issue:`2257`).
@@ -1450,7 +1450,7 @@ Documentation
- Use "url" variable in downloader middleware example (:issue:`2015`)
- Grammar fixes (:issue:`2054`, :issue:`2120`)
- New FAQ entry on using BeautifulSoup in spider callbacks (:issue:`2048`)
-- Add notes about scrapy not working on Windows with Python 3 (:issue:`2060`)
+- Add notes about Scrapy not working on Windows with Python 3 (:issue:`2060`)
- Encourage complete titles in pull requests (:issue:`2026`)
Tests
@@ -1509,7 +1509,7 @@ This 1.1 release brings a lot of interesting features and bug fixes:
You can use :setting:`FILES_STORE_S3_ACL` to change it.
- We've reimplemented ``canonicalize_url()`` for more correct output,
especially for URLs with non-ASCII characters (:issue:`1947`).
- This could change link extractors output compared to previous scrapy versions.
+ This could change link extractors output compared to previous Scrapy versions.
This may also invalidate some cache entries you could still have from pre-1.1 runs.
**Warning: backward incompatible!**.
@@ -1705,7 +1705,7 @@ Scrapy 1.0.4 (2015-12-30)
- fix ValueError: Invalid XPath: //div/[id="not-exists"]/text() on selectors.rst (:commit:`ca8d60f`)
- Typos corrections (:commit:`7067117`)
- fix typos in downloader-middleware.rst and exceptions.rst, middlware -> middleware (:commit:`32f115c`)
-- Add note to ubuntu install section about debian compatibility (:commit:`23fda69`)
+- Add note to Ubuntu install section about Debian compatibility (:commit:`23fda69`)
- Replace alternative OSX install workaround with virtualenv (:commit:`98b63ee`)
- Reference Homebrew's homepage for installation instructions (:commit:`1925db1`)
- Add oldest supported tox version to contributing docs (:commit:`5d10d6d`)
@@ -1722,7 +1722,7 @@ Scrapy 1.0.4 (2015-12-30)
- Merge pull request #1513 from mgedmin/patch-2 (:commit:`5d4daf8`)
- Typo (:commit:`f8d0682`)
- Fix list formatting (:commit:`5f83a93`)
-- fix scrapy squeue tests after recent changes to queuelib (:commit:`3365c01`)
+- fix Scrapy squeue tests after recent changes to queuelib (:commit:`3365c01`)
- Merge pull request #1475 from rweindl/patch-1 (:commit:`2d688cd`)
- Update tutorial.rst (:commit:`fbc1f25`)
- Merge pull request #1449 from rhoekman/patch-1 (:commit:`7d6538c`)
@@ -1734,7 +1734,7 @@ Scrapy 1.0.4 (2015-12-30)
Scrapy 1.0.3 (2015-08-11)
-------------------------
-- add service_identity to scrapy install_requires (:commit:`cbc2501`)
+- add service_identity to Scrapy install_requires (:commit:`cbc2501`)
- Workaround for travis#296 (:commit:`66af9cd`)
.. _release-1.0.2:
@@ -1758,7 +1758,7 @@ Scrapy 1.0.1 (2015-07-01)
- include tests/ to source distribution in MANIFEST.in (:commit:`eca227e`)
- DOC Fix SelectJmes documentation (:commit:`b8567bc`)
- DOC Bring Ubuntu and Archlinux outside of Windows subsection (:commit:`392233f`)
-- DOC remove version suffix from ubuntu package (:commit:`5303c66`)
+- DOC remove version suffix from Ubuntu package (:commit:`5303c66`)
- DOC Update release date for 1.0 (:commit:`c89fa29`)
.. _release-1.0.0:
@@ -2211,7 +2211,7 @@ Scrapy 0.24.2 (2014-07-08)
- Use a mutable mapping to proxy deprecated settings.overrides and settings.defaults attribute (:commit:`e5e8133`)
- there is not support for python3 yet (:commit:`3cd6146`)
-- Update python compatible version set to debian packages (:commit:`fa5d76b`)
+- Update python compatible version set to Debian packages (:commit:`fa5d76b`)
- DOC fix formatting in release notes (:commit:`c6a9e20`)
Scrapy 0.24.1 (2014-06-27)
@@ -2229,12 +2229,12 @@ Enhancements
- Improve Scrapy top-level namespace (:issue:`494`, :issue:`684`)
- Add selector shortcuts to responses (:issue:`554`, :issue:`690`)
-- Add new lxml based LinkExtractor to replace unmantained SgmlLinkExtractor
+- Add new lxml based LinkExtractor to replace unmaintained SgmlLinkExtractor
(:issue:`559`, :issue:`761`, :issue:`763`)
- Cleanup settings API - part of per-spider settings **GSoC project** (:issue:`737`)
- Add UTF8 encoding header to templates (:issue:`688`, :issue:`762`)
- Telnet console now binds to 127.0.0.1 by default (:issue:`699`)
-- Update debian/ubuntu install instructions (:issue:`509`, :issue:`549`)
+- Update Debian/Ubuntu install instructions (:issue:`509`, :issue:`549`)
- Disable smart strings in lxml XPath evaluations (:issue:`535`)
- Restore filesystem based cache as default for http
cache middleware (:issue:`541`, :issue:`500`, :issue:`571`)
@@ -2267,7 +2267,7 @@ Enhancements
- Tests and docs for ``request_fingerprint`` function (:issue:`597`)
- Update SEP-19 for GSoC project ``per-spider settings`` (:issue:`705`)
- Set exit code to non-zero when contracts fails (:issue:`727`)
-- Add a setting to control what class is instanciated as Downloader component
+- Add a setting to control what class is instantiated as Downloader component
(:issue:`738`)
- Pass response in ``item_dropped`` signal (:issue:`724`)
- Improve ``scrapy check`` contracts command (:issue:`733`, :issue:`752`)
@@ -2276,7 +2276,7 @@ Enhancements
- Add a note about reporting security issues (:issue:`697`)
- Add LevelDB http cache storage backend (:issue:`626`, :issue:`500`)
- Sort spider list output of ``scrapy list`` command (:issue:`742`)
-- Multiple documentation enhancemens and fixes
+- Multiple documentation enhancements and fixes
(:issue:`575`, :issue:`587`, :issue:`590`, :issue:`596`, :issue:`610`,
:issue:`617`, :issue:`618`, :issue:`627`, :issue:`613`, :issue:`643`,
:issue:`654`, :issue:`675`, :issue:`663`, :issue:`711`, :issue:`714`)
@@ -2321,19 +2321,19 @@ Scrapy 0.22.1 (released 2014-02-08)
- BaseSgmlLinkExtractor: Added unit test of a link with an inner tag (:commit:`c1cb418`)
- BaseSgmlLinkExtractor: Fixed unknown_endtag() so that it only set current_link=None when the end tag match the opening tag (:commit:`7e4d627`)
- Fix tests for Travis-CI build (:commit:`76c7e20`)
-- replace unencodeable codepoints with html entities. fixes #562 and #285 (:commit:`5f87b17`)
+- replace unencodable codepoints with html entities. fixes #562 and #285 (:commit:`5f87b17`)
- RegexLinkExtractor: encode URL unicode value when creating Links (:commit:`d0ee545`)
- Updated the tutorial crawl output with latest output. (:commit:`8da65de`)
- Updated shell docs with the crawler reference and fixed the actual shell output. (:commit:`875b9ab`)
- PEP8 minor edits. (:commit:`f89efaf`)
-- Expose current crawler in the scrapy shell. (:commit:`5349cec`)
+- Expose current crawler in the Scrapy shell. (:commit:`5349cec`)
- Unused re import and PEP8 minor edits. (:commit:`387f414`)
- Ignore None's values when using the ItemLoader. (:commit:`0632546`)
- DOC Fixed HTTPCACHE_STORAGE typo in the default value which is now Filesystem instead Dbm. (:commit:`cde9a8c`)
-- show ubuntu setup instructions as literal code (:commit:`fb5c9c5`)
+- show Ubuntu setup instructions as literal code (:commit:`fb5c9c5`)
- Update Ubuntu installation instructions (:commit:`70fb105`)
- Merge pull request #550 from stray-leone/patch-1 (:commit:`6f70b6a`)
-- modify the version of scrapy ubuntu package (:commit:`725900d`)
+- modify the version of Scrapy Ubuntu package (:commit:`725900d`)
- fix 0.22.0 release date (:commit:`af0219a`)
- fix typos in news.rst and remove (not released yet) header (:commit:`b7f58f4`)
@@ -2354,7 +2354,7 @@ Enhancements
- Improve test coverage and forthcoming Python 3 support (:issue:`525`)
- Promote startup info on settings and middleware to INFO level (:issue:`520`)
- Support partials in ``get_func_args`` util (:issue:`506`, issue:`504`)
-- Allow running indiviual tests via tox (:issue:`503`)
+- Allow running individual tests via tox (:issue:`503`)
- Update extensions ignored by link extractors (:issue:`498`)
- Add middleware methods to get files/images/thumbs paths (:issue:`490`)
- Improve offsite middleware tests (:issue:`478`)
@@ -2411,7 +2411,7 @@ Enhancements
- scrapy.mail.MailSender now can connect over TLS or upgrade using STARTTLS (:issue:`327`)
- New FilesPipeline with functionality factored out from ImagesPipeline (:issue:`370`, :issue:`409`)
- Recommend Pillow instead of PIL for image handling (:issue:`317`)
-- Added debian packages for Ubuntu quantal and raring (:commit:`86230c0`)
+- Added Debian packages for Ubuntu Quantal and Raring (:commit:`86230c0`)
- Mock server (used for tests) can listen for HTTPS requests (:issue:`410`)
- Remove multi spider support from multiple core components
(:issue:`422`, :issue:`421`, :issue:`420`, :issue:`419`, :issue:`423`, :issue:`418`)
@@ -2430,7 +2430,7 @@ Bugfixes
- Fix tests under Django 1.6 (:commit:`b6bed44c`)
- Lot of bugfixes to retry middleware under disconnections using HTTP 1.1 download handler
- Fix inconsistencies among Twisted releases (:issue:`406`)
-- Fix scrapy shell bugs (:issue:`418`, :issue:`407`)
+- Fix Scrapy shell bugs (:issue:`418`, :issue:`407`)
- Fix invalid variable name in setup.py (:issue:`429`)
- Fix tutorial references (:issue:`387`)
- Improve request-response docs (:issue:`391`)
@@ -2512,15 +2512,15 @@ Scrapy 0.18.1 (released 2013-08-27)
- test PotentiaDataLoss errors on unbound responses (:commit:`b15470d`)
- Treat responses without content-length or Transfer-Encoding as good responses (:commit:`c4bf324`)
- do no include ResponseFailed if http11 handler is not enabled (:commit:`6cbe684`)
-- New HTTP client wraps connection losts in ResponseFailed exception. fix #373 (:commit:`1a20bba`)
+- New HTTP client wraps connection lost in ResponseFailed exception. fix #373 (:commit:`1a20bba`)
- limit travis-ci build matrix (:commit:`3b01bb8`)
- Merge pull request #375 from peterarenot/patch-1 (:commit:`fa766d7`)
- Fixed so it refers to the correct folder (:commit:`3283809`)
-- added quantal & raring to support ubuntu releases (:commit:`1411923`)
+- added Quantal & Raring to support Ubuntu releases (:commit:`1411923`)
- fix retry middleware which didn't retry certain connection errors after the upgrade to http1 client, closes GH-373 (:commit:`bb35ed0`)
- fix XmlItemExporter in Python 2.7.4 and 2.7.5 (:commit:`de3e451`)
- minor updates to 0.18 release notes (:commit:`c45e5f1`)
-- fix contributters list format (:commit:`0b60031`)
+- fix contributors list format (:commit:`0b60031`)
Scrapy 0.18.0 (released 2013-08-09)
-----------------------------------
@@ -2555,8 +2555,8 @@ Scrapy 0.18.0 (released 2013-08-09)
- Collect idle downloader slots (:issue:`297`)
- Add ``ftp://`` scheme downloader handler (:issue:`329`)
- Added downloader benchmark webserver and spider tools :ref:`benchmarking`
-- Moved persistent (on disk) queues to a separate project (queuelib_) which scrapy now depends on
-- Add scrapy commands using external libraries (:issue:`260`)
+- Moved persistent (on disk) queues to a separate project (queuelib_) which Scrapy now depends on
+- Add Scrapy commands using external libraries (:issue:`260`)
- Added ``--pdb`` option to ``scrapy`` command line tool
- Added :meth:`XPathSelector.remove_namespaces ` which allows to remove all namespaces from XML documents for convenience (to work with namespace-less XPaths). Documented in :ref:`topics-selectors`.
- Several improvements to spider contracts
@@ -2568,7 +2568,7 @@ Scrapy 0.18.0 (released 2013-08-09)
- several more cleanups to singletons and multi-spider support (thanks Nicolas Ramirez)
- support custom download slots
- added --spider option to "shell" command.
-- log overridden settings when scrapy starts
+- log overridden settings when Scrapy starts
Thanks to everyone who contribute to this release. Here is a list of
contributors sorted by number of commits::
@@ -2617,7 +2617,7 @@ contributors sorted by number of commits::
Scrapy 0.16.5 (released 2013-05-30)
-----------------------------------
-- obey request method when scrapy deploy is redirected to a new endpoint (:commit:`8c4fcee`)
+- obey request method when Scrapy deploy is redirected to a new endpoint (:commit:`8c4fcee`)
- fix inaccurate downloader middleware documentation. refs #280 (:commit:`40667cb`)
- doc: remove links to diveintopython.org, which is no longer available. closes #246 (:commit:`bd58bfa`)
- Find form nodes in invalid html5 documents (:commit:`e3d6945`)
@@ -2631,8 +2631,8 @@ Scrapy 0.16.4 (released 2013-01-23)
- Fixed error message formatting. log.err() doesn't support cool formatting and when error occurred, the message was: "ERROR: Error processing %(item)s" (:commit:`c16150c`)
- lint and improve images pipeline error logging (:commit:`56b45fc`)
- fixed doc typos (:commit:`243be84`)
-- add documentation topics: Broad Crawls & Common Practies (:commit:`1fbb715`)
-- fix bug in scrapy parse command when spider is not specified explicitly. closes #209 (:commit:`c72e682`)
+- add documentation topics: Broad Crawls & Common Practices (:commit:`1fbb715`)
+- fix bug in Scrapy parse command when spider is not specified explicitly. closes #209 (:commit:`c72e682`)
- Update docs/topics/commands.rst (:commit:`28eac7a`)
Scrapy 0.16.3 (released 2012-12-07)
@@ -2651,11 +2651,11 @@ Scrapy 0.16.3 (released 2012-12-07)
Scrapy 0.16.2 (released 2012-11-09)
-----------------------------------
-- scrapy contracts: python2.6 compat (:commit:`a4a9199`)
-- scrapy contracts verbose option (:commit:`ec41673`)
-- proper unittest-like output for scrapy contracts (:commit:`86635e4`)
+- Scrapy contracts: python2.6 compat (:commit:`a4a9199`)
+- Scrapy contracts verbose option (:commit:`ec41673`)
+- proper unittest-like output for Scrapy contracts (:commit:`86635e4`)
- added open_in_browser to debugging doc (:commit:`c9b690d`)
-- removed reference to global scrapy stats from settings doc (:commit:`dd55067`)
+- removed reference to global Scrapy stats from settings doc (:commit:`dd55067`)
- Fix SpiderState bug in Windows platforms (:commit:`58998f4`)
@@ -2665,7 +2665,7 @@ Scrapy 0.16.1 (released 2012-10-26)
- fixed LogStats extension, which got broken after a wrong merge before the 0.16 release (:commit:`8c780fd`)
- better backward compatibility for scrapy.conf.settings (:commit:`3403089`)
- extended documentation on how to access crawler stats from extensions (:commit:`c4da0b5`)
-- removed .hgtags (no longer needed now that scrapy uses git) (:commit:`d52c188`)
+- removed .hgtags (no longer needed now that Scrapy uses git) (:commit:`d52c188`)
- fix dashes under rst headers (:commit:`fa4f7f9`)
- set release date for 0.16.0 in news (:commit:`e292246`)
@@ -2680,8 +2680,7 @@ Scrapy changes:
- documented :doc:`topics/autothrottle` and added to extensions installed by default. You still need to enable it with :setting:`AUTOTHROTTLE_ENABLED`
- major Stats Collection refactoring: removed separation of global/per-spider stats, removed stats-related signals (``stats_spider_opened``, etc). Stats are much simpler now, backward compatibility is kept on the Stats Collector API and signals.
- added :meth:`~scrapy.spidermiddlewares.SpiderMiddleware.process_start_requests` method to spider middlewares
-- dropped Signals singleton. Signals should now be accesed through the Crawler.signals attribute. See the signals documentation for more info.
-- dropped Signals singleton. Signals should now be accesed through the Crawler.signals attribute. See the signals documentation for more info.
+- dropped Signals singleton. Signals should now be accessed through the Crawler.signals attribute. See the signals documentation for more info.
- dropped Stats Collector singleton. Stats can now be accessed through the Crawler.stats attribute. See the stats collection documentation for more info.
- documented :ref:`topics-api`
- ``lxml`` is now the default selectors backend instead of ``libxml2``
@@ -2715,7 +2714,7 @@ Scrapy changes:
Scrapy 0.14.4
-------------
-- added precise to supported ubuntu distros (:commit:`b7e46df`)
+- added precise to supported Ubuntu distros (:commit:`b7e46df`)
- fixed bug in json-rpc webservice reported in https://groups.google.com/forum/#!topic/scrapy-users/qgVBmFybNAQ/discussion. also removed no longer supported 'run' command from extras/scrapy-ws.py (:commit:`340fbdb`)
- meta tag attributes for content-type http equiv can be in any order. #123 (:commit:`0cb68af`)
- replace "import Image" by more standard "from PIL import Image". closes #88 (:commit:`4d17048`)
@@ -2728,11 +2727,11 @@ Scrapy 0.14.3
- include egg files used by testsuite in source distribution. #118 (:commit:`c897793`)
- update docstring in project template to avoid confusion with genspider command, which may be considered as an advanced feature. refs #107 (:commit:`2548dcc`)
- added note to docs/topics/firebug.rst about google directory being shut down (:commit:`668e352`)
-- dont discard slot when empty, just save in another dict in order to recycle if needed again. (:commit:`8e9f607`)
+- don't discard slot when empty, just save in another dict in order to recycle if needed again. (:commit:`8e9f607`)
- do not fail handling unicode xpaths in libxml2 backed selectors (:commit:`b830e95`)
- fixed minor mistake in Request objects documentation (:commit:`bf3c9ee`)
- fixed minor defect in link extractors documentation (:commit:`ba14f38`)
-- removed some obsolete remaining code related to sqlite support in scrapy (:commit:`0665175`)
+- removed some obsolete remaining code related to sqlite support in Scrapy (:commit:`0665175`)
Scrapy 0.14.2
-------------
diff --git a/docs/requirements.txt b/docs/requirements.txt
index 0ed11c4dc..773b92cea 100644
--- a/docs/requirements.txt
+++ b/docs/requirements.txt
@@ -1,4 +1,3 @@
--r ../requirements-py3.txt
Sphinx>=2.1
sphinx-hoverxref
sphinx-notfound-page
diff --git a/docs/topics/autothrottle.rst b/docs/topics/autothrottle.rst
index c9bece753..4317019fc 100644
--- a/docs/topics/autothrottle.rst
+++ b/docs/topics/autothrottle.rst
@@ -11,7 +11,7 @@ Design goals
============
1. be nicer to sites instead of using default download delay of zero
-2. automatically adjust scrapy to the optimum crawling speed, so the user
+2. automatically adjust Scrapy to the optimum crawling speed, so the user
doesn't have to tune the download delays to find the optimum one.
The user only needs to specify the maximum concurrent requests
it allows, and the extension does the rest.
diff --git a/docs/topics/commands.rst b/docs/topics/commands.rst
index 5b3cd7e75..a0dcba90d 100644
--- a/docs/topics/commands.rst
+++ b/docs/topics/commands.rst
@@ -29,7 +29,7 @@ in standard locations:
1. ``/etc/scrapy.cfg`` or ``c:\scrapy\scrapy.cfg`` (system-wide),
2. ``~/.config/scrapy.cfg`` (``$XDG_CONFIG_HOME``) and ``~/.scrapy.cfg`` (``$HOME``)
for global (user-wide) settings, and
-3. ``scrapy.cfg`` inside a scrapy project's root (see next section).
+3. ``scrapy.cfg`` inside a Scrapy project's root (see next section).
Settings from these files are merged in the listed order of preference:
user-defined values have higher priority than system-wide defaults
diff --git a/docs/topics/contracts.rst b/docs/topics/contracts.rst
index 371ae62d5..43db8f101 100644
--- a/docs/topics/contracts.rst
+++ b/docs/topics/contracts.rst
@@ -64,7 +64,7 @@ Use the :command:`check` command to run the contract checks.
Custom Contracts
================
-If you find you need more power than the built-in scrapy contracts you can
+If you find you need more power than the built-in Scrapy contracts you can
create and load your own contracts in the project by using the
:setting:`SPIDER_CONTRACTS` setting::
diff --git a/docs/topics/debug.rst b/docs/topics/debug.rst
index 4b2588518..d75f17301 100644
--- a/docs/topics/debug.rst
+++ b/docs/topics/debug.rst
@@ -5,7 +5,7 @@ Debugging Spiders
=================
This document explains the most common techniques for debugging spiders.
-Consider the following scrapy spider below::
+Consider the following Scrapy spider below::
import scrapy
from myproject.items import MyItem
diff --git a/docs/topics/developer-tools.rst b/docs/topics/developer-tools.rst
index bf14643be..b7d740c19 100644
--- a/docs/topics/developer-tools.rst
+++ b/docs/topics/developer-tools.rst
@@ -39,7 +39,7 @@ Therefore, you should keep in mind the following things:
.. _topics-inspector:
Inspecting a website
-===================================
+====================
By far the most handy feature of the Developer Tools is the `Inspector`
feature, which allows you to inspect the underlying HTML code of
@@ -79,13 +79,23 @@ sections and tags of a webpage, which greatly improves readability. You can
expand and collapse a tag by clicking on the arrow in front of it or by double
clicking directly on the tag. If we expand the ``span`` tag with the ``class=
"text"`` we will see the quote-text we clicked on. The `Inspector` lets you
-copy XPaths to selected elements. Let's try it out: Right-click on the ``span``
-tag, select ``Copy > XPath`` and paste it in the scrapy shell like so::
+copy XPaths to selected elements. Let's try it out.
+
+First open the Scrapy shell at http://quotes.toscrape.com/ in a terminal:
+
+.. code-block:: none
$ scrapy shell "http://quotes.toscrape.com/"
- (...)
- >>> response.xpath('/html/body/div/div[2]/div[1]/div[1]/span[1]/text()').getall()
- ['"The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”]
+
+Then, back to your web browser, right-click on the ``span`` tag, select
+``Copy > XPath`` and paste it in the Scrapy shell like so:
+
+.. invisible-code-block: python
+
+ response = load_response('http://quotes.toscrape.com/', 'quotes.html')
+
+>>> response.xpath('/html/body/div/div[2]/div[1]/div[1]/span[1]/text()').getall()
+['“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”']
Adding ``text()`` at the end we are able to extract the first quote with this
basic selector. But this XPath is not really that clever. All it does is
@@ -112,13 +122,13 @@ see each quote:
With this knowledge we can refine our XPath: Instead of a path to follow,
we'll simply select all ``span`` tags with the ``class="text"`` by using
-the `has-class-extension`_::
+the `has-class-extension`_:
- >>> response.xpath('//span[has-class("text")]/text()').getall()
- ['"The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”,
- '“It is our choices, Harry, that show what we truly are, far more than our abilities.”',
- '“There are only two ways to live your life. One is as though nothing is a miracle. The other is as though everything is a miracle.”',
- (...)]
+>>> response.xpath('//span[has-class("text")]/text()').getall()
+['“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”',
+'“It is our choices, Harry, that show what we truly are, far more than our abilities.”',
+'“There are only two ways to live your life. One is as though nothing is a miracle. The other is as though everything is a miracle.”',
+...]
And with one simple, cleverer XPath we are able to extract all quotes from
the page. We could have constructed a loop over our first XPath to increase
@@ -159,7 +169,11 @@ The page is quite similar to the basic `quotes.toscrape.com`_-page,
but instead of the above-mentioned ``Next`` button, the page
automatically loads new quotes when you scroll to the bottom. We
could go ahead and try out different XPaths directly, but instead
-we'll check another quite useful command from the scrapy shell::
+we'll check another quite useful command from the Scrapy shell:
+
+.. skip: next
+
+.. code-block:: none
$ scrapy shell "quotes.toscrape.com/scroll"
(...)
diff --git a/docs/topics/dynamic-content.rst b/docs/topics/dynamic-content.rst
index 8334ddcec..1c3607860 100644
--- a/docs/topics/dynamic-content.rst
+++ b/docs/topics/dynamic-content.rst
@@ -172,27 +172,27 @@ data from it:
data in JSON format, which you can then parse with `json.loads`_.
For example, if the JavaScript code contains a separate line like
- ``var data = {"field": "value"};`` you can extract that data as follows::
+ ``var data = {"field": "value"};`` you can extract that data as follows:
- >>> pattern = r'\bvar\s+data\s*=\s*(\{.*?\})\s*;\s*\n'
- >>> json_data = response.css('script::text').re_first(pattern)
- >>> json.loads(json_data)
- {'field': 'value'}
+ >>> pattern = r'\bvar\s+data\s*=\s*(\{.*?\})\s*;\s*\n'
+ >>> json_data = response.css('script::text').re_first(pattern)
+ >>> json.loads(json_data)
+ {'field': 'value'}
- Otherwise, use js2xml_ to convert the JavaScript code into an XML document
that you can parse using :ref:`selectors `.
For example, if the JavaScript code contains
- ``var data = {field: "value"};`` you can extract that data as follows::
+ ``var data = {field: "value"};`` you can extract that data as follows:
- >>> import js2xml
- >>> import lxml.etree
- >>> from parsel import Selector
- >>> javascript = response.css('script::text').get()
- >>> xml = lxml.etree.tostring(js2xml.parse(javascript), encoding='unicode')
- >>> selector = Selector(text=xml)
- >>> selector.css('var[name="data"]').get()
- ''
+ >>> import js2xml
+ >>> import lxml.etree
+ >>> from parsel import Selector
+ >>> javascript = response.css('script::text').get()
+ >>> xml = lxml.etree.tostring(js2xml.parse(javascript), encoding='unicode')
+ >>> selector = Selector(text=xml)
+ >>> selector.css('var[name="data"]').get()
+ ''
.. _topics-javascript-rendering:
diff --git a/docs/topics/items.rst b/docs/topics/items.rst
index cdf60208e..15313775b 100644
--- a/docs/topics/items.rst
+++ b/docs/topics/items.rst
@@ -84,77 +84,74 @@ notice the API is very similar to the `dict API`_.
Creating items
--------------
-::
+>>> product = Product(name='Desktop PC', price=1000)
+>>> print(product)
+Product(name='Desktop PC', price=1000)
- >>> product = Product(name='Desktop PC', price=1000)
- >>> print(product)
- Product(name='Desktop PC', price=1000)
Getting field values
--------------------
-::
+>>> product['name']
+Desktop PC
+>>> product.get('name')
+Desktop PC
- >>> product['name']
- Desktop PC
- >>> product.get('name')
- Desktop PC
+>>> product['price']
+1000
- >>> product['price']
- 1000
+>>> product['last_updated']
+Traceback (most recent call last):
+ ...
+KeyError: 'last_updated'
- >>> product['last_updated']
- Traceback (most recent call last):
- ...
- KeyError: 'last_updated'
+>>> product.get('last_updated', 'not set')
+not set
- >>> product.get('last_updated', 'not set')
- not set
+>>> product['lala'] # getting unknown field
+Traceback (most recent call last):
+ ...
+KeyError: 'lala'
- >>> product['lala'] # getting unknown field
- Traceback (most recent call last):
- ...
- KeyError: 'lala'
+>>> product.get('lala', 'unknown field')
+'unknown field'
- >>> product.get('lala', 'unknown field')
- 'unknown field'
+>>> 'name' in product # is name field populated?
+True
- >>> 'name' in product # is name field populated?
- True
+>>> 'last_updated' in product # is last_updated populated?
+False
- >>> 'last_updated' in product # is last_updated populated?
- False
+>>> 'last_updated' in product.fields # is last_updated a declared field?
+True
- >>> 'last_updated' in product.fields # is last_updated a declared field?
- True
+>>> 'lala' in product.fields # is lala a declared field?
+False
- >>> 'lala' in product.fields # is lala a declared field?
- False
Setting field values
--------------------
-::
+>>> product['last_updated'] = 'today'
+>>> product['last_updated']
+today
- >>> product['last_updated'] = 'today'
- >>> product['last_updated']
- today
+>>> product['lala'] = 'test' # setting unknown field
+Traceback (most recent call last):
+ ...
+KeyError: 'Product does not support field: lala'
- >>> product['lala'] = 'test' # setting unknown field
- Traceback (most recent call last):
- ...
- KeyError: 'Product does not support field: lala'
Accessing all populated values
------------------------------
-To access all populated values, just use the typical `dict API`_::
+To access all populated values, just use the typical `dict API`_:
- >>> product.keys()
- ['price', 'name']
+>>> product.keys()
+['price', 'name']
- >>> product.items()
- [('price', 1000), ('name', 'Desktop PC')]
+>>> product.items()
+[('price', 1000), ('name', 'Desktop PC')]
.. _copying-items:
@@ -194,20 +191,21 @@ To create a deep copy, call :meth:`~scrapy.item.Item.deepcopy` instead
Other common tasks
------------------
-Creating dicts from items::
+Creating dicts from items:
- >>> dict(product) # create a dict from all populated values
- {'price': 1000, 'name': 'Desktop PC'}
+>>> dict(product) # create a dict from all populated values
+{'price': 1000, 'name': 'Desktop PC'}
-Creating items from dicts::
+Creating items from dicts:
- >>> Product({'name': 'Laptop PC', 'price': 1500})
- Product(price=1500, name='Laptop PC')
+>>> Product({'name': 'Laptop PC', 'price': 1500})
+Product(price=1500, name='Laptop PC')
+
+>>> Product({'name': 'Laptop PC', 'lala': 1500}) # warning: unknown field in dict
+Traceback (most recent call last):
+ ...
+KeyError: 'Product does not support field: lala'
- >>> Product({'name': 'Laptop PC', 'lala': 1500}) # warning: unknown field in dict
- Traceback (most recent call last):
- ...
- KeyError: 'Product does not support field: lala'
Extending Items
===============
diff --git a/docs/topics/jobs.rst b/docs/topics/jobs.rst
index f5542495b..8816a028c 100644
--- a/docs/topics/jobs.rst
+++ b/docs/topics/jobs.rst
@@ -74,7 +74,7 @@ Request serialization
For persistence to work, :class:`~scrapy.http.Request` objects must be
serializable with :mod:`pickle`, except for the ``callback`` and ``errback``
values passed to their ``__init__`` method, which must be methods of the
-runnning :class:`~scrapy.spiders.Spider` class.
+running :class:`~scrapy.spiders.Spider` class.
If you wish to log the requests that couldn't be serialized, you can set the
:setting:`SCHEDULER_DEBUG` setting to ``True`` in the project's settings page.
diff --git a/docs/topics/leaks.rst b/docs/topics/leaks.rst
index 793636f59..9fee333ac 100644
--- a/docs/topics/leaks.rst
+++ b/docs/topics/leaks.rst
@@ -110,7 +110,7 @@ ties the response lifetime to the requests' one, and that would definitely
cause memory leaks.
Let's see how we can discover the cause (without knowing it
-a-priori, of course) by using the ``trackref`` tool.
+a priori, of course) by using the ``trackref`` tool.
After the crawler is running for a few minutes and we notice its memory usage
has grown a lot, we can enter its telnet console and check the live
@@ -132,21 +132,21 @@ and check the code of the spider to discover the nasty line that is
generating the leaks (passing response references inside requests).
Sometimes extra information about live objects can be helpful.
-Let's check the oldest response::
+Let's check the oldest response:
- >>> from scrapy.utils.trackref import get_oldest
- >>> r = get_oldest('HtmlResponse')
- >>> r.url
- 'http://www.somenastyspider.com/product.php?pid=123'
+>>> from scrapy.utils.trackref import get_oldest
+>>> r = get_oldest('HtmlResponse')
+>>> r.url
+'http://www.somenastyspider.com/product.php?pid=123'
If you want to iterate over all objects, instead of getting the oldest one, you
-can use the :func:`scrapy.utils.trackref.iter_all` function::
+can use the :func:`scrapy.utils.trackref.iter_all` function:
- >>> from scrapy.utils.trackref import iter_all
- >>> [r.url for r in iter_all('HtmlResponse')]
- ['http://www.somenastyspider.com/product.php?pid=123',
- 'http://www.somenastyspider.com/product.php?pid=584',
- ...
+>>> from scrapy.utils.trackref import iter_all
+>>> [r.url for r in iter_all('HtmlResponse')]
+['http://www.somenastyspider.com/product.php?pid=123',
+ 'http://www.somenastyspider.com/product.php?pid=584',
+...]
Too many spiders?
-----------------
@@ -155,10 +155,10 @@ If your project has too many spiders executed in parallel,
the output of :func:`prefs()` can be difficult to read.
For this reason, that function has a ``ignore`` argument which can be used to
ignore a particular class (and all its subclases). For
-example, this won't show any live references to spiders::
+example, this won't show any live references to spiders:
- >>> from scrapy.spiders import Spider
- >>> prefs(ignore=Spider)
+>>> from scrapy.spiders import Spider
+>>> prefs(ignore=Spider)
.. module:: scrapy.utils.trackref
:synopsis: Track references of live objects
@@ -214,41 +214,41 @@ If you use ``pip``, you can install Guppy with the following command::
The telnet console also comes with a built-in shortcut (``hpy``) for accessing
Guppy heap objects. Here's an example to view all Python objects available in
-the heap using Guppy::
+the heap using Guppy:
- >>> x = hpy.heap()
- >>> x.bytype
- Partition of a set of 297033 objects. Total size = 52587824 bytes.
- Index Count % Size % Cumulative % Type
- 0 22307 8 16423880 31 16423880 31 dict
- 1 122285 41 12441544 24 28865424 55 str
- 2 68346 23 5966696 11 34832120 66 tuple
- 3 227 0 5836528 11 40668648 77 unicode
- 4 2461 1 2222272 4 42890920 82 type
- 5 16870 6 2024400 4 44915320 85 function
- 6 13949 5 1673880 3 46589200 89 types.CodeType
- 7 13422 5 1653104 3 48242304 92 list
- 8 3735 1 1173680 2 49415984 94 _sre.SRE_Pattern
- 9 1209 0 456936 1 49872920 95 scrapy.http.headers.Headers
- <1676 more rows. Type e.g. '_.more' to view.>
+>>> x = hpy.heap()
+>>> x.bytype
+Partition of a set of 297033 objects. Total size = 52587824 bytes.
+ Index Count % Size % Cumulative % Type
+ 0 22307 8 16423880 31 16423880 31 dict
+ 1 122285 41 12441544 24 28865424 55 str
+ 2 68346 23 5966696 11 34832120 66 tuple
+ 3 227 0 5836528 11 40668648 77 unicode
+ 4 2461 1 2222272 4 42890920 82 type
+ 5 16870 6 2024400 4 44915320 85 function
+ 6 13949 5 1673880 3 46589200 89 types.CodeType
+ 7 13422 5 1653104 3 48242304 92 list
+ 8 3735 1 1173680 2 49415984 94 _sre.SRE_Pattern
+ 9 1209 0 456936 1 49872920 95 scrapy.http.headers.Headers
+<1676 more rows. Type e.g. '_.more' to view.>
You can see that most space is used by dicts. Then, if you want to see from
-which attribute those dicts are referenced, you could do::
+which attribute those dicts are referenced, you could do:
- >>> x.bytype[0].byvia
- Partition of a set of 22307 objects. Total size = 16423880 bytes.
- Index Count % Size % Cumulative % Referred Via:
- 0 10982 49 9416336 57 9416336 57 '.__dict__'
- 1 1820 8 2681504 16 12097840 74 '.__dict__', '.func_globals'
- 2 3097 14 1122904 7 13220744 80
- 3 990 4 277200 2 13497944 82 "['cookies']"
- 4 987 4 276360 2 13774304 84 "['cache']"
- 5 985 4 275800 2 14050104 86 "['meta']"
- 6 897 4 251160 2 14301264 87 '[2]'
- 7 1 0 196888 1 14498152 88 "['moduleDict']", "['modules']"
- 8 672 3 188160 1 14686312 89 "['cb_kwargs']"
- 9 27 0 155016 1 14841328 90 '[1]'
- <333 more rows. Type e.g. '_.more' to view.>
+>>> x.bytype[0].byvia
+Partition of a set of 22307 objects. Total size = 16423880 bytes.
+ Index Count % Size % Cumulative % Referred Via:
+ 0 10982 49 9416336 57 9416336 57 '.__dict__'
+ 1 1820 8 2681504 16 12097840 74 '.__dict__', '.func_globals'
+ 2 3097 14 1122904 7 13220744 80
+ 3 990 4 277200 2 13497944 82 "['cookies']"
+ 4 987 4 276360 2 13774304 84 "['cache']"
+ 5 985 4 275800 2 14050104 86 "['meta']"
+ 6 897 4 251160 2 14301264 87 '[2]'
+ 7 1 0 196888 1 14498152 88 "['moduleDict']", "['modules']"
+ 8 672 3 188160 1 14686312 89 "['cb_kwargs']"
+ 9 27 0 155016 1 14841328 90 '[1]'
+<333 more rows. Type e.g. '_.more' to view.>
As you can see, the Guppy module is very powerful but also requires some deep
knowledge about Python internals. For more info about Guppy, refer to the
@@ -269,32 +269,32 @@ If you use ``pip``, you can install muppy with the following command::
pip install Pympler
Here's an example to view all Python objects available in
-the heap using muppy::
+the heap using muppy:
- >>> from pympler import muppy
- >>> all_objects = muppy.get_objects()
- >>> len(all_objects)
- 28667
- >>> from pympler import summary
- >>> suml = summary.summarize(all_objects)
- >>> summary.print_(suml)
- types | # objects | total size
- ==================================== | =========== | ============
- >> from pympler import muppy
+>>> all_objects = muppy.get_objects()
+>>> len(all_objects)
+28667
+>>> from pympler import summary
+>>> suml = summary.summarize(all_objects)
+>>> summary.print_(suml)
+ types | # objects | total size
+==================================== | =========== | ============
+ ` returns a
+list of matching :class:`scrapy.link.Link` objects from a
+:class:`~scrapy.http.Response` object.
+Link extractors are used in :class:`~scrapy.spiders.CrawlSpider` spiders
+through a set of :class:`~scrapy.spiders.Rule` objects. You can also use link
+extractors in regular spiders.
.. _topics-link-extractors-ref:
-Built-in link extractors reference
-==================================
+Link extractor reference
+========================
.. module:: scrapy.linkextractors
:synopsis: Link extractors classes
-Link extractors classes bundled with Scrapy are provided in the
-:mod:`scrapy.linkextractors` module.
-
-The default link extractor is ``LinkExtractor``, which is the same as
-:class:`~.LxmlLinkExtractor`::
+The link extractor class is
+:class:`scrapy.linkextractors.lxmlhtml.LxmlLinkExtractor`. For convenience it
+can also be imported as ``scrapy.linkextractors.LinkExtractor``::
from scrapy.linkextractors import LinkExtractor
-There used to be other link extractor classes in previous Scrapy versions,
-but they are deprecated now.
-
LxmlLinkExtractor
-----------------
@@ -152,4 +139,6 @@ LxmlLinkExtractor
from elements or attributes which allow leading/trailing whitespaces).
:type strip: boolean
+ .. automethod:: extract_links
+
.. _scrapy.linkextractors: https://github.com/scrapy/scrapy/blob/master/scrapy/linkextractors/__init__.py
diff --git a/docs/topics/loaders.rst b/docs/topics/loaders.rst
index de3f38023..9d5fccbbc 100644
--- a/docs/topics/loaders.rst
+++ b/docs/topics/loaders.rst
@@ -206,14 +206,12 @@ metadata. Here is an example::
output_processor=TakeFirst(),
)
-::
-
- >>> from scrapy.loader import ItemLoader
- >>> il = ItemLoader(item=Product())
- >>> il.add_value('name', [u'Welcome to my', u'website'])
- >>> il.add_value('price', [u'€', u'1000'])
- >>> il.load_item()
- {'name': u'Welcome to my website', 'price': u'1000'}
+>>> from scrapy.loader import ItemLoader
+>>> il = ItemLoader(item=Product())
+>>> il.add_value('name', [u'Welcome to my', u'website'])
+>>> il.add_value('price', [u'€', u'1000'])
+>>> il.load_item()
+{'name': u'Welcome to my website', 'price': u'1000'}
The precedence order, for both input and output processors, is as follows:
@@ -314,11 +312,11 @@ ItemLoader objects
applied before processors
:type re: str or compiled regex
- Examples::
+ Examples:
- >>> from scrapy.loader.processors import TakeFirst
- >>> loader.get_value(u'name: foo', TakeFirst(), unicode.upper, re='name: (.+)')
- 'FOO`
+ >>> from scrapy.loader.processors import TakeFirst
+ >>> loader.get_value(u'name: foo', TakeFirst(), unicode.upper, re='name: (.+)')
+ 'FOO`
.. method:: add_value(field_name, value, \*processors, \**kwargs)
@@ -639,12 +637,12 @@ Here is a list of all built-in processors:
values unchanged. It doesn't receive any ``__init__`` method arguments, nor does it
accept Loader contexts.
- Example::
+ Example:
- >>> from scrapy.loader.processors import Identity
- >>> proc = Identity()
- >>> proc(['one', 'two', 'three'])
- ['one', 'two', 'three']
+ >>> from scrapy.loader.processors import Identity
+ >>> proc = Identity()
+ >>> proc(['one', 'two', 'three'])
+ ['one', 'two', 'three']
.. class:: TakeFirst
@@ -652,12 +650,12 @@ Here is a list of all built-in processors:
so it's typically used as an output processor to single-valued fields.
It doesn't receive any ``__init__`` method arguments, nor does it accept Loader contexts.
- Example::
+ Example:
- >>> from scrapy.loader.processors import TakeFirst
- >>> proc = TakeFirst()
- >>> proc(['', 'one', 'two', 'three'])
- 'one'
+ >>> from scrapy.loader.processors import TakeFirst
+ >>> proc = TakeFirst()
+ >>> proc(['', 'one', 'two', 'three'])
+ 'one'
.. class:: Join(separator=u' ')
@@ -667,15 +665,15 @@ Here is a list of all built-in processors:
When using the default separator, this processor is equivalent to the
function: ``u' '.join``
- Examples::
+ Examples:
- >>> from scrapy.loader.processors import Join
- >>> proc = Join()
- >>> proc(['one', 'two', 'three'])
- 'one two three'
- >>> proc = Join(' ')
- >>> proc(['one', 'two', 'three'])
- 'one two three'
+ >>> from scrapy.loader.processors import Join
+ >>> proc = Join()
+ >>> proc(['one', 'two', 'three'])
+ 'one two three'
+ >>> proc = Join(' ')
+ >>> proc(['one', 'two', 'three'])
+ 'one two three'
.. class:: Compose(\*functions, \**default_loader_context)
@@ -688,12 +686,12 @@ Here is a list of all built-in processors:
By default, stop process on ``None`` value. This behaviour can be changed by
passing keyword argument ``stop_on_none=False``.
- Example::
+ Example:
- >>> from scrapy.loader.processors import Compose
- >>> proc = Compose(lambda v: v[0], str.upper)
- >>> proc(['hello', 'world'])
- 'HELLO'
+ >>> from scrapy.loader.processors import Compose
+ >>> proc = Compose(lambda v: v[0], str.upper)
+ >>> proc(['hello', 'world'])
+ 'HELLO'
Each function can optionally receive a ``loader_context`` parameter. For
those which do, this processor will pass the currently active :ref:`Loader
@@ -732,15 +730,15 @@ Here is a list of all built-in processors:
:meth:`~scrapy.selector.Selector.extract` method of :ref:`selectors
`, which returns a list of unicode strings.
- The example below should clarify how it works::
+ The example below should clarify how it works:
- >>> def filter_world(x):
- ... return None if x == 'world' else x
- ...
- >>> from scrapy.loader.processors import MapCompose
- >>> proc = MapCompose(filter_world, str.upper)
- >>> proc(['hello', 'world', 'this', 'is', 'scrapy'])
- ['HELLO, 'THIS', 'IS', 'SCRAPY']
+ >>> def filter_world(x):
+ ... return None if x == 'world' else x
+ ...
+ >>> from scrapy.loader.processors import MapCompose
+ >>> proc = MapCompose(filter_world, str.upper)
+ >>> proc(['hello', 'world', 'this', 'is', 'scrapy'])
+ ['HELLO, 'THIS', 'IS', 'SCRAPY']
As with the Compose processor, functions can receive Loader contexts, and
``__init__`` method keyword arguments are used as default context values. See
@@ -752,21 +750,21 @@ Here is a list of all built-in processors:
Requires jmespath (https://github.com/jmespath/jmespath.py) to run.
This processor takes only one input at a time.
- Example::
+ Example:
- >>> from scrapy.loader.processors import SelectJmes, Compose, MapCompose
- >>> proc = SelectJmes("foo") #for direct use on lists and dictionaries
- >>> proc({'foo': 'bar'})
- 'bar'
- >>> proc({'foo': {'bar': 'baz'}})
- {'bar': 'baz'}
+ >>> from scrapy.loader.processors import SelectJmes, Compose, MapCompose
+ >>> proc = SelectJmes("foo") #for direct use on lists and dictionaries
+ >>> proc({'foo': 'bar'})
+ 'bar'
+ >>> proc({'foo': {'bar': 'baz'}})
+ {'bar': 'baz'}
- Working with Json::
+ Working with Json:
- >>> import json
- >>> proc_single_json_str = Compose(json.loads, SelectJmes("foo"))
- >>> proc_single_json_str('{"foo": "bar"}')
- 'bar'
- >>> proc_json_list = Compose(json.loads, MapCompose(SelectJmes('foo')))
- >>> proc_json_list('[{"foo":"bar"}, {"baz":"tar"}]')
- ['bar']
+ >>> import json
+ >>> proc_single_json_str = Compose(json.loads, SelectJmes("foo"))
+ >>> proc_single_json_str('{"foo": "bar"}')
+ 'bar'
+ >>> proc_json_list = Compose(json.loads, MapCompose(SelectJmes('foo')))
+ >>> proc_json_list('[{"foo":"bar"}, {"baz":"tar"}]')
+ ['bar']
diff --git a/docs/topics/logging.rst b/docs/topics/logging.rst
index dd09477b8..d4d22d889 100644
--- a/docs/topics/logging.rst
+++ b/docs/topics/logging.rst
@@ -171,9 +171,9 @@ listed in `logging's logrecord attributes docs
`_
respectively.
-If :setting:`LOG_SHORT_NAMES` is set, then the logs will not display the scrapy
+If :setting:`LOG_SHORT_NAMES` is set, then the logs will not display the Scrapy
component that prints the log. It is unset by default, hence logs contain the
-scrapy component responsible for that log output.
+Scrapy component responsible for that log output.
Command-line options
--------------------
diff --git a/docs/topics/media-pipeline.rst b/docs/topics/media-pipeline.rst
index 206e7cfa5..332a14eb7 100644
--- a/docs/topics/media-pipeline.rst
+++ b/docs/topics/media-pipeline.rst
@@ -97,7 +97,6 @@ For Files Pipeline, use::
ITEM_PIPELINES = {'scrapy.pipelines.files.FilesPipeline': 1}
-
.. note::
You can also use both the Files and Images Pipeline at the same time.
@@ -558,7 +557,7 @@ See here the methods that you can override in your custom Images Pipeline:
Custom Images pipeline example
==============================
-Here is a full example of the Images Pipeline whose methods are examplified
+Here is a full example of the Images Pipeline whose methods are exemplified
above::
import scrapy
@@ -578,4 +577,12 @@ above::
item['image_paths'] = image_paths
return item
+
+To enable your custom media pipeline component you must add its class import path to the
+:setting:`ITEM_PIPELINES` setting, like in the following example::
+
+ ITEM_PIPELINES = {
+ 'myproject.pipelines.MyImagesPipeline': 300
+ }
+
.. _MD5 hash: https://en.wikipedia.org/wiki/MD5
diff --git a/docs/topics/selectors.rst b/docs/topics/selectors.rst
index 282a585d4..8ec758b0e 100644
--- a/docs/topics/selectors.rst
+++ b/docs/topics/selectors.rst
@@ -51,18 +51,18 @@ Constructing selectors
.. highlight:: python
Response objects expose a :class:`~scrapy.selector.Selector` instance
-on ``.selector`` attribute::
+on ``.selector`` attribute:
- >>> response.selector.xpath('//span/text()').get()
- 'good'
+>>> response.selector.xpath('//span/text()').get()
+'good'
Querying responses using XPath and CSS is so common that responses include two
-more shortcuts: ``response.xpath()`` and ``response.css()``::
+more shortcuts: ``response.xpath()`` and ``response.css()``:
- >>> response.xpath('//span/text()').get()
- 'good'
- >>> response.css('span::text').get()
- 'good'
+>>> response.xpath('//span/text()').get()
+'good'
+>>> response.css('span::text').get()
+'good'
Scrapy selectors are instances of :class:`~scrapy.selector.Selector` class
constructed by passing either :class:`~scrapy.http.TextResponse` object or
@@ -74,21 +74,21 @@ shortcuts. By using ``response.selector`` or one of these shortcuts
you can also ensure the response body is parsed only once.
But if required, it is possible to use ``Selector`` directly.
-Constructing from text::
+Constructing from text:
- >>> from scrapy.selector import Selector
- >>> body = 'good'
- >>> Selector(text=body).xpath('//span/text()').get()
- 'good'
+>>> from scrapy.selector import Selector
+>>> body = 'good'
+>>> Selector(text=body).xpath('//span/text()').get()
+'good'
Constructing from response - :class:`~scrapy.http.HtmlResponse` is one of
-:class:`~scrapy.http.TextResponse` subclasses::
+:class:`~scrapy.http.TextResponse` subclasses:
- >>> from scrapy.selector import Selector
- >>> from scrapy.http import HtmlResponse
- >>> response = HtmlResponse(url='http://example.com', body=body)
- >>> Selector(response=response).xpath('//span/text()').get()
- 'good'
+>>> from scrapy.selector import Selector
+>>> from scrapy.http import HtmlResponse
+>>> response = HtmlResponse(url='http://example.com', body=body)
+>>> Selector(response=response).xpath('//span/text()').get()
+'good'
``Selector`` automatically chooses the best parsing rules
(XML vs HTML) based on input type.
@@ -123,118 +123,118 @@ Since we're dealing with HTML, the selector will automatically use an HTML parse
.. highlight:: python
So, by looking at the :ref:`HTML code ` of that
-page, let's construct an XPath for selecting the text inside the title tag::
+page, let's construct an XPath for selecting the text inside the title tag:
- >>> response.xpath('//title/text()')
- []
+>>> response.xpath('//title/text()')
+[]
To actually extract the textual data, you must call the selector ``.get()``
-or ``.getall()`` methods, as follows::
+or ``.getall()`` methods, as follows:
- >>> response.xpath('//title/text()').getall()
- ['Example website']
- >>> response.xpath('//title/text()').get()
- 'Example website'
+>>> response.xpath('//title/text()').getall()
+['Example website']
+>>> response.xpath('//title/text()').get()
+'Example website'
``.get()`` always returns a single result; if there are several matches,
content of a first match is returned; if there are no matches, None
is returned. ``.getall()`` returns a list with all results.
Notice that CSS selectors can select text or attribute nodes using CSS3
-pseudo-elements::
+pseudo-elements:
- >>> response.css('title::text').get()
- 'Example website'
+>>> response.css('title::text').get()
+'Example website'
As you can see, ``.xpath()`` and ``.css()`` methods return a
:class:`~scrapy.selector.SelectorList` instance, which is a list of new
-selectors. This API can be used for quickly selecting nested data::
+selectors. This API can be used for quickly selecting nested data:
- >>> response.css('img').xpath('@src').getall()
- ['image1_thumb.jpg',
- 'image2_thumb.jpg',
- 'image3_thumb.jpg',
- 'image4_thumb.jpg',
- 'image5_thumb.jpg']
+>>> response.css('img').xpath('@src').getall()
+['image1_thumb.jpg',
+ 'image2_thumb.jpg',
+ 'image3_thumb.jpg',
+ 'image4_thumb.jpg',
+ 'image5_thumb.jpg']
If you want to extract only the first matched element, you can call the
selector ``.get()`` (or its alias ``.extract_first()`` commonly used in
-previous Scrapy versions)::
+previous Scrapy versions):
- >>> response.xpath('//div[@id="images"]/a/text()').get()
- 'Name: My image 1 '
+>>> response.xpath('//div[@id="images"]/a/text()').get()
+'Name: My image 1 '
-It returns ``None`` if no element was found::
+It returns ``None`` if no element was found:
- >>> response.xpath('//div[@id="not-exists"]/text()').get() is None
- True
+>>> response.xpath('//div[@id="not-exists"]/text()').get() is None
+True
A default return value can be provided as an argument, to be used instead
of ``None``:
- >>> response.xpath('//div[@id="not-exists"]/text()').get(default='not-found')
- 'not-found'
+>>> response.xpath('//div[@id="not-exists"]/text()').get(default='not-found')
+'not-found'
Instead of using e.g. ``'@src'`` XPath it is possible to query for attributes
-using ``.attrib`` property of a :class:`~scrapy.selector.Selector`::
+using ``.attrib`` property of a :class:`~scrapy.selector.Selector`:
- >>> [img.attrib['src'] for img in response.css('img')]
- ['image1_thumb.jpg',
- 'image2_thumb.jpg',
- 'image3_thumb.jpg',
- 'image4_thumb.jpg',
- 'image5_thumb.jpg']
+>>> [img.attrib['src'] for img in response.css('img')]
+['image1_thumb.jpg',
+ 'image2_thumb.jpg',
+ 'image3_thumb.jpg',
+ 'image4_thumb.jpg',
+ 'image5_thumb.jpg']
As a shortcut, ``.attrib`` is also available on SelectorList directly;
-it returns attributes for the first matching element::
+it returns attributes for the first matching element:
- >>> response.css('img').attrib['src']
- 'image1_thumb.jpg'
+>>> response.css('img').attrib['src']
+'image1_thumb.jpg'
This is most useful when only a single result is expected, e.g. when selecting
-by id, or selecting unique elements on a web page::
+by id, or selecting unique elements on a web page:
- >>> response.css('base').attrib['href']
- 'http://example.com/'
+>>> response.css('base').attrib['href']
+'http://example.com/'
-Now we're going to get the base URL and some image links::
+Now we're going to get the base URL and some image links:
- >>> response.xpath('//base/@href').get()
- 'http://example.com/'
+>>> response.xpath('//base/@href').get()
+'http://example.com/'
- >>> response.css('base::attr(href)').get()
- 'http://example.com/'
+>>> response.css('base::attr(href)').get()
+'http://example.com/'
- >>> response.css('base').attrib['href']
- 'http://example.com/'
+>>> response.css('base').attrib['href']
+'http://example.com/'
- >>> response.xpath('//a[contains(@href, "image")]/@href').getall()
- ['image1.html',
- 'image2.html',
- 'image3.html',
- 'image4.html',
- 'image5.html']
+>>> response.xpath('//a[contains(@href, "image")]/@href').getall()
+['image1.html',
+ 'image2.html',
+ 'image3.html',
+ 'image4.html',
+ 'image5.html']
- >>> response.css('a[href*=image]::attr(href)').getall()
- ['image1.html',
- 'image2.html',
- 'image3.html',
- 'image4.html',
- 'image5.html']
+>>> response.css('a[href*=image]::attr(href)').getall()
+['image1.html',
+ 'image2.html',
+ 'image3.html',
+ 'image4.html',
+ 'image5.html']
- >>> response.xpath('//a[contains(@href, "image")]/img/@src').getall()
- ['image1_thumb.jpg',
- 'image2_thumb.jpg',
- 'image3_thumb.jpg',
- 'image4_thumb.jpg',
- 'image5_thumb.jpg']
+>>> response.xpath('//a[contains(@href, "image")]/img/@src').getall()
+['image1_thumb.jpg',
+ 'image2_thumb.jpg',
+ 'image3_thumb.jpg',
+ 'image4_thumb.jpg',
+ 'image5_thumb.jpg']
- >>> response.css('a[href*=image] img::attr(src)').getall()
- ['image1_thumb.jpg',
- 'image2_thumb.jpg',
- 'image3_thumb.jpg',
- 'image4_thumb.jpg',
- 'image5_thumb.jpg']
+>>> response.css('a[href*=image] img::attr(src)').getall()
+['image1_thumb.jpg',
+ 'image2_thumb.jpg',
+ 'image3_thumb.jpg',
+ 'image4_thumb.jpg',
+ 'image5_thumb.jpg']
.. _topics-selectors-css-extensions:
@@ -259,47 +259,47 @@ that Scrapy (parsel) implements a couple of **non-standard pseudo-elements**:
Examples:
-* ``title::text`` selects children text nodes of a descendant ```` element::
+* ``title::text`` selects children text nodes of a descendant ```` element:
- >>> response.css('title::text').get()
- 'Example website'
+>>> response.css('title::text').get()
+'Example website'
-* ``*::text`` selects all descendant text nodes of the current selector context::
+* ``*::text`` selects all descendant text nodes of the current selector context:
- >>> response.css('#images *::text').getall()
- ['\n ',
- 'Name: My image 1 ',
- '\n ',
- 'Name: My image 2 ',
- '\n ',
- 'Name: My image 3 ',
- '\n ',
- 'Name: My image 4 ',
- '\n ',
- 'Name: My image 5 ',
- '\n ']
+>>> response.css('#images *::text').getall()
+['\n ',
+ 'Name: My image 1 ',
+ '\n ',
+ 'Name: My image 2 ',
+ '\n ',
+ 'Name: My image 3 ',
+ '\n ',
+ 'Name: My image 4 ',
+ '\n ',
+ 'Name: My image 5 ',
+ '\n ']
* ``foo::text`` returns no results if ``foo`` element exists, but contains
- no text (i.e. text is empty)::
+ no text (i.e. text is empty):
- >>> response.css('img::text').getall()
- []
+>>> response.css('img::text').getall()
+[]
This means ``.css('foo::text').get()`` could return None even if an element
- exists. Use ``default=''`` if you always want a string::
+ exists. Use ``default=''`` if you always want a string:
- >>> response.css('img::text').get()
- >>> response.css('img::text').get(default='')
- ''
+>>> response.css('img::text').get()
+>>> response.css('img::text').get(default='')
+''
-* ``a::attr(href)`` selects the *href* attribute value of descendant links::
+* ``a::attr(href)`` selects the *href* attribute value of descendant links:
- >>> response.css('a::attr(href)').getall()
- ['image1.html',
- 'image2.html',
- 'image3.html',
- 'image4.html',
- 'image5.html']
+>>> response.css('a::attr(href)').getall()
+['image1.html',
+ 'image2.html',
+ 'image3.html',
+ 'image4.html',
+ 'image5.html']
.. note::
See also: :ref:`selecting-attributes`.
@@ -318,25 +318,24 @@ Nesting selectors
The selection methods (``.xpath()`` or ``.css()``) return a list of selectors
of the same type, so you can call the selection methods for those selectors
-too. Here's an example::
+too. Here's an example:
- >>> links = response.xpath('//a[contains(@href, "image")]')
- >>> links.getall()
- ['Name: My image 1 ',
- 'Name: My image 2 ',
- 'Name: My image 3 ',
- 'Name: My image 4 ',
- 'Name: My image 5 ']
+>>> links = response.xpath('//a[contains(@href, "image")]')
+>>> links.getall()
+['Name: My image 1 ',
+ 'Name: My image 2 ',
+ 'Name: My image 3 ',
+ 'Name: My image 4 ',
+ 'Name: My image 5 ']
- >>> for index, link in enumerate(links):
- ... args = (index, link.xpath('@href').get(), link.xpath('img/@src').get())
- ... print('Link number %d points to url %r and image %r' % args)
-
- Link number 0 points to url 'image1.html' and image 'image1_thumb.jpg'
- Link number 1 points to url 'image2.html' and image 'image2_thumb.jpg'
- Link number 2 points to url 'image3.html' and image 'image3_thumb.jpg'
- Link number 3 points to url 'image4.html' and image 'image4_thumb.jpg'
- Link number 4 points to url 'image5.html' and image 'image5_thumb.jpg'
+>>> for index, link in enumerate(links):
+... args = (index, link.xpath('@href').get(), link.xpath('img/@src').get())
+... print('Link number %d points to url %r and image %r' % args)
+Link number 0 points to url 'image1.html' and image 'image1_thumb.jpg'
+Link number 1 points to url 'image2.html' and image 'image2_thumb.jpg'
+Link number 2 points to url 'image3.html' and image 'image3_thumb.jpg'
+Link number 3 points to url 'image4.html' and image 'image4_thumb.jpg'
+Link number 4 points to url 'image5.html' and image 'image5_thumb.jpg'
.. _selecting-attributes:
@@ -344,42 +343,42 @@ Selecting element attributes
----------------------------
There are several ways to get a value of an attribute. First, one can use
-XPath syntax::
+XPath syntax:
- >>> response.xpath("//a/@href").getall()
- ['image1.html', 'image2.html', 'image3.html', 'image4.html', 'image5.html']
+>>> response.xpath("//a/@href").getall()
+['image1.html', 'image2.html', 'image3.html', 'image4.html', 'image5.html']
XPath syntax has a few advantages: it is a standard XPath feature, and
``@attributes`` can be used in other parts of an XPath expression - e.g.
it is possible to filter by attribute value.
Scrapy also provides an extension to CSS selectors (``::attr(...)``)
-which allows to get attribute values::
+which allows to get attribute values:
- >>> response.css('a::attr(href)').getall()
- ['image1.html', 'image2.html', 'image3.html', 'image4.html', 'image5.html']
+>>> response.css('a::attr(href)').getall()
+['image1.html', 'image2.html', 'image3.html', 'image4.html', 'image5.html']
In addition to that, there is a ``.attrib`` property of Selector.
You can use it if you prefer to lookup attributes in Python
-code, without using XPaths or CSS extensions::
+code, without using XPaths or CSS extensions:
- >>> [a.attrib['href'] for a in response.css('a')]
- ['image1.html', 'image2.html', 'image3.html', 'image4.html', 'image5.html']
+>>> [a.attrib['href'] for a in response.css('a')]
+['image1.html', 'image2.html', 'image3.html', 'image4.html', 'image5.html']
This property is also available on SelectorList; it returns a dictionary
with attributes of a first matching element. It is convenient to use when
a selector is expected to give a single result (e.g. when selecting by element
-ID, or when selecting an unique element on a page)::
+ID, or when selecting an unique element on a page):
- >>> response.css('base').attrib
- {'href': 'http://example.com/'}
- >>> response.css('base').attrib['href']
- 'http://example.com/'
+>>> response.css('base').attrib
+{'href': 'http://example.com/'}
+>>> response.css('base').attrib['href']
+'http://example.com/'
-``.attrib`` property of an empty SelectorList is empty::
+``.attrib`` property of an empty SelectorList is empty:
- >>> response.css('foo').attrib
- {}
+>>> response.css('foo').attrib
+{}
Using selectors with regular expressions
----------------------------------------
@@ -390,21 +389,21 @@ data using regular expressions. However, unlike using ``.xpath()`` or
can't construct nested ``.re()`` calls.
Here's an example used to extract image names from the :ref:`HTML code
-` above::
+` above:
- >>> response.xpath('//a[contains(@href, "image")]/text()').re(r'Name:\s*(.*)')
- ['My image 1',
- 'My image 2',
- 'My image 3',
- 'My image 4',
- 'My image 5']
+>>> response.xpath('//a[contains(@href, "image")]/text()').re(r'Name:\s*(.*)')
+['My image 1',
+ 'My image 2',
+ 'My image 3',
+ 'My image 4',
+ 'My image 5']
There's an additional helper reciprocating ``.get()`` (and its
alias ``.extract_first()``) for ``.re()``, named ``.re_first()``.
-Use it to extract just the first matching string::
+Use it to extract just the first matching string:
- >>> response.xpath('//a[contains(@href, "image")]/text()').re_first(r'Name:\s*(.*)')
- 'My image 1'
+>>> response.xpath('//a[contains(@href, "image")]/text()').re_first(r'Name:\s*(.*)')
+'My image 1'
.. _old-extraction-api:
@@ -422,28 +421,28 @@ and readable code.
The following examples show how these methods map to each other.
-1. ``SelectorList.get()`` is the same as ``SelectorList.extract_first()``::
+1. ``SelectorList.get()`` is the same as ``SelectorList.extract_first()``:
- >>> response.css('a::attr(href)').get()
- 'image1.html'
- >>> response.css('a::attr(href)').extract_first()
- 'image1.html'
+ >>> response.css('a::attr(href)').get()
+ 'image1.html'
+ >>> response.css('a::attr(href)').extract_first()
+ 'image1.html'
-2. ``SelectorList.getall()`` is the same as ``SelectorList.extract()``::
+2. ``SelectorList.getall()`` is the same as ``SelectorList.extract()``:
- >>> response.css('a::attr(href)').getall()
- ['image1.html', 'image2.html', 'image3.html', 'image4.html', 'image5.html']
- >>> response.css('a::attr(href)').extract()
- ['image1.html', 'image2.html', 'image3.html', 'image4.html', 'image5.html']
+ >>> response.css('a::attr(href)').getall()
+ ['image1.html', 'image2.html', 'image3.html', 'image4.html', 'image5.html']
+ >>> response.css('a::attr(href)').extract()
+ ['image1.html', 'image2.html', 'image3.html', 'image4.html', 'image5.html']
-3. ``Selector.get()`` is the same as ``Selector.extract()``::
+3. ``Selector.get()`` is the same as ``Selector.extract()``:
- >>> response.css('a::attr(href)')[0].get()
- 'image1.html'
- >>> response.css('a::attr(href)')[0].extract()
- 'image1.html'
+ >>> response.css('a::attr(href)')[0].get()
+ 'image1.html'
+ >>> response.css('a::attr(href)')[0].extract()
+ 'image1.html'
-4. For consistency, there is also ``Selector.getall()``, which returns a list::
+4. For consistency, there is also ``Selector.getall()``, which returns a list:
>>> response.css('a::attr(href)')[0].getall()
['image1.html']
@@ -481,26 +480,26 @@ with ``/``, that XPath will be absolute to the document and not relative to the
``Selector`` you're calling it from.
For example, suppose you want to extract all ``