diff --git a/AUTHORS b/AUTHORS
index 49182f68a..24b20a17d 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -27,3 +27,5 @@ Here is the list of the primary authors & contributors:
* Shuaib Khan
* Didier Deshommes
* Vikas Dhiman
+ * Jochen Maes
+ * Darian Moody
diff --git a/MANIFEST.in b/MANIFEST.in
index 3002ca360..bf6ec398c 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -3,7 +3,7 @@ include AUTHORS
include INSTALL
include LICENSE
include MANIFEST.in
-include scrapy/core/downloader/responsetypes/mime.types
+include scrapy/mime.types
include scrapyd/default_scrapyd.conf
recursive-include scrapy/templates *
recursive-include scrapy/tests/sample_data *
diff --git a/README b/README
index 694fd7e6f..d79e46bc2 100644
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
This is Scrapy, an opensource screen scraping framework written in Python.
-For more visit the project home page at http://scrapy.org
+For more info visit the project home page at http://scrapy.org
diff --git a/bin/scrapyd b/bin/scrapyd
new file mode 100755
index 000000000..fe440cbb5
--- /dev/null
+++ b/bin/scrapyd
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+repotac=$(cd $(dirname $0)/../extras; pwd)/scrapyd.tac
+
+if [ -f "$repotac" ]; then
+ tacfile="$repotac"
+elif [ -f "/usr/share/scrapyd/scrapyd.tac" ]; then
+ tacfile="/usr/share/scrapyd/scrapyd.tac"
+else
+ echo "Unable to find scrapy.tac file"
+ exit 1
+fi
+
+twistd -ny "$tacfile"
diff --git a/debian/control b/debian/control
index 70d6ca0e8..fa407cc84 100644
--- a/debian/control
+++ b/debian/control
@@ -2,13 +2,14 @@ Source: scrapy-SUFFIX
Section: python
Priority: optional
Maintainer: Insophia Team
-Build-Depends: debhelper (>= 7.0.50), python (>=2.5), python-twisted
+Build-Depends: debhelper (>= 7.0.50), python (>=2.6), python-twisted, python-w3lib
Standards-Version: 3.8.4
Homepage: http://scrapy.org/
Package: scrapy-SUFFIX
Architecture: all
-Depends: ${python:Depends}, python-libxml2, python-twisted, python-openssl
+Depends: ${python:Depends}, python-libxml2, python-twisted, python-openssl, python-w3lib
+Recommends: python-setuptools
Conflicts: python-scrapy, scrapy, scrapy-0.11
Provides: python-scrapy, scrapy
Description: Python web crawling and scraping framework
diff --git a/debian/scrapy.examples b/debian/scrapy.examples
deleted file mode 100644
index e39721e20..000000000
--- a/debian/scrapy.examples
+++ /dev/null
@@ -1 +0,0 @@
-examples/*
diff --git a/debian/scrapy.install b/debian/scrapy.install
index 8aa6bc81d..2ccb5ce19 100644
--- a/debian/scrapy.install
+++ b/debian/scrapy.install
@@ -1,3 +1,3 @@
-usr/lib/python*/*-packages/scrapy
+usr/lib/python*/*-packages/scrapy*
usr/bin
extras/scrapy_bash_completion etc/bash_completion.d/
diff --git a/debian/scrapyd.install b/debian/scrapyd.install
index d83e70b48..f46d4e3bd 100644
--- a/debian/scrapyd.install
+++ b/debian/scrapyd.install
@@ -1,3 +1,2 @@
-usr/lib/python*/*-packages/scrapyd
debian/scrapyd-files/000-default etc/scrapyd/conf.d
extras/scrapyd.tac usr/share/scrapyd
diff --git a/docs/_ext/scrapydocs.py b/docs/_ext/scrapydocs.py
index 3cc916972..6b1e6a9b4 100644
--- a/docs/_ext/scrapydocs.py
+++ b/docs/_ext/scrapydocs.py
@@ -1,3 +1,6 @@
+from docutils.parsers.rst.roles import set_classes
+from docutils import nodes
+
def setup(app):
app.add_crossref_type(
directivename = "setting",
@@ -19,3 +22,10 @@ def setup(app):
rolename = "reqmeta",
indextemplate = "pair: %s; reqmeta",
)
+ app.add_role('source', source_role)
+
+def source_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
+ url = 'http://dev.scrapy.org/browser/' + text
+ set_classes(options)
+ node = nodes.reference(rawtext, text, refuri=ref, **options)
+ return [node], []
diff --git a/docs/api-stability.rst b/docs/api-stability.rst
deleted file mode 100644
index f415bd8fa..000000000
--- a/docs/api-stability.rst
+++ /dev/null
@@ -1,34 +0,0 @@
-.. _api-stability:
-
-============================
-Versioning and API Stability
-============================
-
-API stability is one of Scrapy major goals.
-
-Versioning
-==========
-
-When Scrapy reaches 1.0, each release will consist of three version numbers:
-
- * major - big, backwards-incompatible changes
- * minor - new features and backwards-compatible changes
- * micro - bug fixes only
-
-Until Scrapy reaches 1.0, minor releases (0.7, 0.8, etc) will follow the same
-policy as major releases.
-
-Sometimes the micro version can be omitted, for brevity, when it's not
-relevant.
-
-API Stability
-=============
-
-Methods or functions that start with a single dash (``_``) are private and
-should never be relied as stable. Besides those, the plan is to stabilize and
-document the entire API, as we approach the 1.0 release.
-
-Also, keep in mind that stable doesn't mean complete: stable APIs could grow
-new methods or functionality but the existing methods should keep working the
-same way.
-
diff --git a/docs/experimental/crawlspider-v2.rst b/docs/experimental/crawlspider-v2.rst
deleted file mode 100644
index a1ea09c48..000000000
--- a/docs/experimental/crawlspider-v2.rst
+++ /dev/null
@@ -1,128 +0,0 @@
-.. _topics-crawlspider-v2:
-
-==============
-CrawlSpider v2
-==============
-
-Introduction
-============
-
-TODO: introduction
-
-Rules Matching
-==============
-
-TODO: describe purpose of rules
-
-Request Extractors & Processors
-===============================
-
-TODO: describe purpose of extractors & processors
-
-Examples
-========
-
-TODO: plenty of examples
-
-
-.. module:: scrapy.contrib_exp.crawlspider.spider
- :synopsis: CrawlSpider
-
-
-Reference
-=========
-
-CrawlSpider
------------
-
-TODO: describe crawlspider
-
-.. class:: CrawlSpider
-
- TODO: describe class
-
-
-.. module:: scrapy.contrib_exp.crawlspider.rules
- :synopsis: Rules
-
-Rules
------
-
-TODO: describe spider rules
-
-.. class:: Rule
-
- TODO: describe Rules class
-
-
-.. module:: scrapy.contrib_exp.crawlspider.reqext
- :synopsis: Request Extractors
-
-Request Extractors
-------------------
-
-TODO: describe extractors purpose
-
-.. class:: BaseSgmlRequestExtractor
-
- TODO: describe base extractor
-
-.. class:: SgmlRequestExtractor
-
- TODO: describe sgml extractor
-
-.. class:: XPathRequestExtractor
-
- TODO: describe xpath request extractor
-
-
-.. module:: scrapy.contrib_exp.crawlspider.reqproc
- :synopsis: Request Processors
-
-Request Processors
-------------------
-
-TODO: describe request processors
-
-.. class:: Canonicalize
-
- TODO: describe proc
-
-.. class:: Unique
-
- TODO: describe unique
-
-.. class:: FilterDomain
-
- TODO: describe filter domain
-
-.. class:: FilterUrl
-
- TODO: describe filter url
-
-
-.. module:: scrapy.contrib_exp.crawlspider.matchers
- :synopsis: Matchers
-
-Request/Response Matchers
--------------------------
-
-TODO: describe matchers
-
-.. class:: BaseMatcher
-
- TODO: describe base matcher
-
-.. class:: UrlMatcher
-
- TODO: describe url matcher
-
-.. class:: UrlRegexMatcher
-
- TODO: describe UrlListMatcher
-
-.. class:: UrlListMatcher
-
- TODO: describe url list matcher
-
-
diff --git a/docs/experimental/index.rst b/docs/experimental/index.rst
index f159e8c51..c28cdd9ed 100644
--- a/docs/experimental/index.rst
+++ b/docs/experimental/index.rst
@@ -20,4 +20,3 @@ it's properly merged) . Use at your own risk.
:maxdepth: 1
djangoitems
- crawlspider-v2
diff --git a/docs/faq.rst b/docs/faq.rst
index eae0d04a0..67c5241be 100644
--- a/docs/faq.rst
+++ b/docs/faq.rst
@@ -3,7 +3,7 @@
Frequently Asked Questions
==========================
-How does Scrapy compare to BeautifulSoul or lxml?
+How does Scrapy compare to BeautifulSoup or lxml?
-------------------------------------------------
`BeautifulSoup`_ and `lxml`_ are libraries for parsing HTML and XML. Scrapy is
@@ -84,10 +84,11 @@ How can I simulate a user login in my spider?
See :ref:`topics-request-response-ref-request-userlogin`.
-Can I crawl in breadth-first order instead of depth-first order?
-----------------------------------------------------------------
+Does Scrapy crawl in breath-first or depth-first order?
+-------------------------------------------------------
-Yes, there's a setting for that: :setting:`SCHEDULER_ORDER`.
+It crawls on breath-first order by default, but you can change it to
+depth-first order by setting the :setting:`DEPTH_PRIORITY` setting to ``-1``.
My Scrapy crawler has memory leaks. What can I do?
--------------------------------------------------
@@ -115,24 +116,10 @@ Try changing the default `Accept-Language`_ request header by overriding the
.. _Accept-Language: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4
-Where can I find some example code using Scrapy?
-------------------------------------------------
+Where can I find some example Scrapy projects?
+----------------------------------------------
-Scrapy comes with a built-in, fully functional project to scrape the `Google
-Directory`_. You can find it in the `examples/googledir`_ directory of the
-Scrapy distribution.
-
-Also, there's a site for sharing code snippets (spiders, middlewares,
-extensions) called `Scrapy snippets`_.
-
-Finally, you can find some example code for performing not-so-trivial tasks in
-the `Scrapy Recipes`_ wiki page.
-
-.. _Google Directory: http://www.google.com/dirhp
-.. _examples/googledir: http://dev.scrapy.org/browser/examples/googledir
-.. _Community Spiders: http://dev.scrapy.org/wiki/CommunitySpiders
-.. _Scrapy Recipes: http://dev.scrapy.org/wiki/ScrapyRecipes
-.. _Scrapy snippets: http://snippets.scrapy.org/
+See :ref:`intro-examples`.
Can I run a spider without creating a project?
----------------------------------------------
@@ -240,3 +227,48 @@ In order to avoid parsing all the entire feed at once in memory, you can use
the functions ``xmliter`` and ``csviter`` from ``scrapy.utils.iterators``
module. In fact, this is what the feed spiders (see :ref:`topics-spiders`) use
under the cover.
+
+Does Scrapy manage cookies automatically?
+-----------------------------------------
+
+Yes, Scrapy receives and keeps track of cookies sent by servers, and sends them
+back on subsequent requests, like any regular web browser does.
+
+For more info see :ref:`topics-request-response` and :ref:`cookies-mw`.
+
+How can I see the cookies being sent and received from Scrapy?
+--------------------------------------------------------------
+
+Enable the :setting:`COOKIES_DEBUG` setting.
+
+How can I instruct a spider to stop itself?
+-------------------------------------------
+
+Raise the :exc:`~scrapy.exceptions.CloseSpider` exception from a callback. For
+more info see: :exc:`~scrapy.exceptions.CloseSpider`.
+
+How can I prevent my Scrapy bot from getting banned?
+----------------------------------------------------
+
+Some websites implement certain measures to prevent bots from crawling them,
+with varying degrees of sophistication. Getting around those measures can be
+difficult and tricky, and may sometimes require special infrastructure.
+
+Here are some tips to keep in mind when dealing with these kind of sites:
+
+* rotate your user agent from a pool of well-known ones from browsers (google
+ around to get a list of them)
+* disable cookies (see :setting:`COOKIES_ENABLED`) as some sites may use
+ cookies to spot bot behaviour
+* use download delays (2 or higher). See :setting:`DOWNLOAD_DELAY` setting.
+* is possible, use `Google cache`_ to fetch pages, instead of hitting the sites
+ directly
+* use a pool of rotating IPs. For example, the free `Tor project`_.
+
+If you are still unable to prevent your bot getting banned, consider contacting
+`commercial support`_.
+
+.. _user agents: http://en.wikipedia.org/wiki/User_agent
+.. _Google cache: http://www.googleguide.com/cached_pages.html
+.. _Tor project: https://www.torproject.org/
+.. _commercial support: http://scrapy.org/support/
diff --git a/docs/index.rst b/docs/index.rst
index e50ffa15b..779647030 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -33,6 +33,7 @@ First steps
intro/overview
intro/install
intro/tutorial
+ intro/examples
:doc:`intro/overview`
Understand what Scrapy is and how it can help you.
@@ -43,9 +44,13 @@ First steps
:doc:`intro/tutorial`
Write your first Scrapy project.
+:doc:`intro/examples`
+ Learn more by playing with a pre-made Scrapy project.
-Scraping basics
-===============
+.. _section-basics:
+
+Basic concepts
+==============
.. toctree::
:hidden:
@@ -59,6 +64,7 @@ Scraping basics
topics/shell
topics/item-pipeline
topics/feed-exports
+ topics/link-extractors
:doc:`topics/commands`
Learn about the command-line tool used to manage your Scrapy project.
@@ -84,6 +90,8 @@ Scraping basics
:doc:`topics/feed-exports`
Output your scraped data using different formats and storages.
+:doc:`topics/link-extractors`
+ Convenient classes to extract links to follow from pages.
Built-in services
=================
@@ -213,13 +221,13 @@ All the rest
:hidden:
contributing
- api-stability
+ versioning
experimental/index
:doc:`contributing`
Learn how to contribute to the Scrapy project.
-:doc:`api-stability`
+:doc:`versioning`
Understand Scrapy versioning and API stability.
:doc:`experimental/index`
diff --git a/docs/intro/examples.rst b/docs/intro/examples.rst
new file mode 100644
index 000000000..cb54563d0
--- /dev/null
+++ b/docs/intro/examples.rst
@@ -0,0 +1,31 @@
+.. _intro-examples:
+
+========
+Examples
+========
+
+The best way to learn is with examples. For this reason, there is an example
+Scrapy project named dirbot_, that you can use to play and learn more about
+Scrapy. It contains the dmoz spider described in the tutorial.
+
+This dirbot_ project is available at: https://github.com/scrapy/dirbot
+
+It contains a README file with a detailed description of the project contents.
+
+If you're familiar with git, you can checkout the code. Otherwise you can
+download a tarball or zip file of the project by clicking on `Downloads`_.
+
+Other sources for examples
+==========================
+
+1. There is a site for sharing code snippets (spiders, middlewares, extensions)
+called `Scrapy snippets`_.
+
+2. There is also a `Scrapy Recipes`_ page on the wiki that contains code
+snippets for performing not-so-trivial tasks. This contains code posted before
+the `Scrapy snippets`_ site was lunched. New code should be posted there.
+
+.. _dirbot: https://github.com/scrapy/dirbot
+.. _Downloads: https://github.com/scrapy/dirbot/archives/master
+.. _Scrapy Recipes: http://dev.scrapy.org/wiki/ScrapyRecipes
+.. _Scrapy snippets: http://snippets.scrapy.org/
diff --git a/docs/intro/install.rst b/docs/intro/install.rst
index 278166ec0..46409a8ea 100644
--- a/docs/intro/install.rst
+++ b/docs/intro/install.rst
@@ -16,6 +16,8 @@ Requirements
* `Twisted`_ 2.5.0, 8.0 or above (Windows users: you'll need to install
`Zope.Interface`_ and maybe `pywin32`_ because of `this Twisted bug`_)
+* `w3lib`_
+
* `lxml`_ or `libxml2`_ (if using `libxml2`_, version 2.6.28 or above is highly recommended)
* `simplejson`_ (not required if using Python 2.6 or above)
@@ -111,6 +113,10 @@ If you're running Debian Linux, run the following command as root::
apt-get install python-twisted python-libxml2 python-pyopenssl python-simplejson
+Then::
+
+ easy_install -U w3lib
+
And then follow the instructions in :ref:`intro-install-scrapy`.
Arch Linux
@@ -120,13 +126,17 @@ If you are running Arch Linux, run the following command as root::
pacman -S twisted libxml2 pyopenssl python-simplejson
+Then::
+
+ easy_install -U w3lib
+
And then follow the instructions in :ref:`intro-install-scrapy`.
Other Linux distros
~~~~~~~~~~~~~~~~~~~
The easiest way to install Scrapy in other Linux distros is through
-``easy_install``, which will automatically install Twisted and lxml as
+``easy_install``, which will automatically install Twisted, w3lib and lxml as
dependencies. See :ref:`intro-install-easy`.
Another way would be to install dependencies, if you know the packages in your
@@ -135,8 +145,8 @@ distros that meets them. See :ref:`intro-install-requirements`.
Mac OS X
--------
-The easiest way to install Scrapy on Mac is through ``easy_install``, which
-will automatically install Twisted and lxml as dependencies.
+The easiest way to install Scrapy on Mac is through ``easy_install`` or
+``pip``, which will automatically install Twisted, w3lib and lxml dependencies.
See :ref:`intro-install-easy`.
@@ -164,6 +174,7 @@ There are two ways to install Scrapy in Windows:
.. _Python: http://www.python.org
.. _Twisted: http://twistedmatrix.com
+.. _w3lib: http://pypi.python.org/pypi/w3lib
.. _lxml: http://codespeak.net/lxml/
.. _libxml2: http://xmlsoft.org
.. _pywin32: http://sourceforge.net/projects/pywin32/
diff --git a/docs/intro/overview.rst b/docs/intro/overview.rst
index 2cff2cf46..46fb29bce 100644
--- a/docs/intro/overview.rst
+++ b/docs/intro/overview.rst
@@ -246,6 +246,10 @@ scraping easy and efficient, such as:
* :ref:`Logging ` facility that you can hook on to for catching
errors during the scraping process.
+* Support for crawling based on URLs discovered through `Sitemaps`_
+
+* A caching DNS resolver
+
What's next?
============
@@ -262,3 +266,4 @@ interest!
.. _XPath: http://www.w3.org/TR/xpath
.. _XPath reference: http://www.w3.org/TR/xpath
.. _Amazon S3: http://aws.amazon.com/s3/
+.. _Sitemaps: http://www.sitemaps.org
diff --git a/docs/intro/tutorial.rst b/docs/intro/tutorial.rst
index e29ac2e7b..a1b015bf1 100644
--- a/docs/intro/tutorial.rst
+++ b/docs/intro/tutorial.rst
@@ -36,13 +36,13 @@ Creating a project
Before you start scraping, you will have set up a new Scrapy project. Enter a
directory where you'd like to store your code and then run::
- scrapy startproject dmoz
+ scrapy startproject tutorial
-This will create a ``dmoz`` directory with the following contents::
+This will create a ``tutorial`` directory with the following contents::
- dmoz/
+ tutorial/
scrapy.cfg
- dmoz/
+ tutorial/
__init__.py
items.py
pipelines.py
@@ -54,19 +54,19 @@ This will create a ``dmoz`` directory with the following contents::
These are basically:
* ``scrapy.cfg``: the project configuration file
-* ``dmoz/``: the project's python module, you'll later import your code from
+* ``tutorial/``: the project's python module, you'll later import your code from
here.
-* ``dmoz/items.py``: the project's items file.
-* ``dmoz/pipelines.py``: the project's pipelines file.
-* ``dmoz/settings.py``: the project's settings file.
-* ``dmoz/spiders/``: a directory where you'll later put your spiders.
+* ``tutorial/items.py``: the project's items file.
+* ``tutorial/pipelines.py``: the project's pipelines file.
+* ``tutorial/settings.py``: the project's settings file.
+* ``tutorial/spiders/``: a directory where you'll later put your spiders.
Defining our Item
=================
`Items` are containers that will be loaded with the scraped data; they work
-like simple python dicts but they offer some additional features like providing
-default values.
+like simple python dicts but provide additional protecting against populating
+undeclared fields, to prevent typos.
They are declared by creating an :class:`scrapy.item.Item` class an defining
its attributes as :class:`scrapy.item.Field` objects, like you will in an ORM
@@ -78,8 +78,6 @@ from dmoz.org, as we want to capture the name, url and description of the
sites, we define fields for each of these three attributes. To do that, we edit
items.py, found in the dmoz directory. Our Item class looks like this::
- # Define here the models for your scraped items
-
from scrapy.item import Item, Field
class DmozItem(Item):
@@ -128,7 +126,7 @@ This is the code for our first Spider; save it in a file named
from scrapy.spider import BaseSpider
class DmozSpider(BaseSpider):
- name = "dmoz.org"
+ name = "dmoz"
allowed_domains = ["dmoz.org"]
start_urls = [
"http://www.dmoz.org/Computers/Programming/Languages/Python/Books/",
@@ -144,27 +142,25 @@ Crawling
To put our spider to work, go to the project's top level directory and run::
- scrapy crawl dmoz.org
+ scrapy crawl dmoz
-The ``crawl dmoz.org`` command runs the spider for the ``dmoz.org`` domain. You
+The ``crawl dmoz`` command runs the spider for the ``dmoz.org`` domain. You
will get an output similar to this::
2008-08-20 03:51:13-0300 [scrapy] INFO: Started project: dmoz
- 2008-08-20 03:51:13-0300 [dmoz] INFO: Enabled extensions: ...
- 2008-08-20 03:51:13-0300 [dmoz] INFO: Enabled scheduler middlewares: ...
- 2008-08-20 03:51:13-0300 [dmoz] INFO: Enabled downloader middlewares: ...
- 2008-08-20 03:51:13-0300 [dmoz] INFO: Enabled spider middlewares: ...
- 2008-08-20 03:51:13-0300 [dmoz] INFO: Enabled item pipelines: ...
- 2008-08-20 03:51:14-0300 [dmoz.org] INFO: Spider opened
- 2008-08-20 03:51:14-0300 [dmoz.org] DEBUG: Crawled (referer: )
- 2008-08-20 03:51:14-0300 [dmoz.org] DEBUG: Crawled (referer: )
- 2008-08-20 03:51:14-0300 [dmoz.org] INFO: Spider closed (finished)
+ 2008-08-20 03:51:13-0300 [tutorial] INFO: Enabled extensions: ...
+ 2008-08-20 03:51:13-0300 [tutorial] INFO: Enabled downloader middlewares: ...
+ 2008-08-20 03:51:13-0300 [tutorial] INFO: Enabled spider middlewares: ...
+ 2008-08-20 03:51:13-0300 [tutorial] INFO: Enabled item pipelines: ...
+ 2008-08-20 03:51:14-0300 [dmoz] INFO: Spider opened
+ 2008-08-20 03:51:14-0300 [dmoz] DEBUG: Crawled (referer: )
+ 2008-08-20 03:51:14-0300 [dmoz] DEBUG: Crawled (referer: )
+ 2008-08-20 03:51:14-0300 [dmoz] INFO: Spider closed (finished)
-Pay attention to the lines containing ``[dmoz.org]``, which corresponds to
-our spider (identified by the domain ``"dmoz.org"``). You can see a log line
-for each URL defined in ``start_urls``. Because these URLs are the starting
-ones, they have no referrers, which is shown at the end of the log line,
-where it says ``(referer: )``.
+Pay attention to the lines containing ``[dmoz]``, which corresponds to our
+spider. You can see a log line for each URL defined in ``start_urls``. Because
+these URLs are the starting ones, they have no referrers, which is shown at the
+end of the log line, where it says ``(referer: )``.
But more interesting, as our ``parse`` method instructs, two files have been
created: *Books* and *Resources*, with the content of both URLs.
@@ -342,7 +338,7 @@ Let's add this code to our spider::
from scrapy.selector import HtmlXPathSelector
class DmozSpider(BaseSpider):
- name = "dmoz.org"
+ name = "dmoz"
allowed_domains = ["dmoz.org"]
start_urls = [
"http://www.dmoz.org/Computers/Programming/Languages/Python/Books/",
@@ -361,7 +357,7 @@ Let's add this code to our spider::
Now try crawling the dmoz.org domain again and you'll see sites being printed
in your output, run::
- scrapy crawl dmoz.org
+ scrapy crawl dmoz
Using our item
--------------
@@ -376,16 +372,16 @@ standard dict syntax like::
'Example title'
Spiders are expected to return their scraped data inside
-:class:`~scrapy.item.Item` objects, so to actually return the data we've
-scraped so far, the code for our Spider should be like this::
+:class:`~scrapy.item.Item` objects. So, in order to returnthe data we've
+scraped so far, the final code for our Spider would be like this::
from scrapy.spider import BaseSpider
from scrapy.selector import HtmlXPathSelector
- from dmoz.items import DmozItem
+ from tutorial.items import DmozItem
class DmozSpider(BaseSpider):
- name = "dmoz.org"
+ name = "dmoz"
allowed_domains = ["dmoz.org"]
start_urls = [
"http://www.dmoz.org/Computers/Programming/Languages/Python/Books/",
@@ -404,10 +400,19 @@ scraped so far, the code for our Spider should be like this::
items.append(item)
return items
+.. note:: You can find a fully-functional variant of this spider in the dirbot_
+ project available at https://github.com/scrapy/dirbot
+
Now doing a crawl on the dmoz.org domain yields ``DmozItem``'s::
- [dmoz.org] DEBUG: Scraped DmozItem(desc=[u' - By David Mertz; Addison Wesley. Book in progress, full text, ASCII format. Asks for feedback. [author website, Gnosis Software, Inc.]\n'], link=[u'http://gnosis.cx/TPiP/'], title=[u'Text Processing in Python']) in
- [dmoz.org] DEBUG: Scraped DmozItem(desc=[u' - By Sean McGrath; Prentice Hall PTR, 2000, ISBN 0130211192, has CD-ROM. Methods to build XML applications fast, Python tutorial, DOM and SAX, new Pyxie open source XML processing library. [Prentice Hall PTR]\n'], link=[u'http://www.informit.com/store/product.aspx?isbn=0130211192'], title=[u'XML Processing with Python']) in
+ [dmoz] DEBUG: Scraped from <200 http://www.dmoz.org/Computers/Programming/Languages/Python/Books/>
+ {'desc': [u' - By David Mertz; Addison Wesley. Book in progress, full text, ASCII format. Asks for feedback. [author website, Gnosis Software, Inc.\n],
+ 'link': [u'http://gnosis.cx/TPiP/'],
+ 'title': [u'Text Processing in Python']}
+ [dmoz] DEBUG: Scraped from <200 http://www.dmoz.org/Computers/Programming/Languages/Python/Books/>
+ {'desc': [u' - By Sean McGrath; Prentice Hall PTR, 2000, ISBN 0130211192, has CD-ROM. Methods to build XML applications fast, Python tutorial, DOM and SAX, new Pyxie open source XML processing library. [Prentice Hall PTR]\n'],
+ 'link': [u'http://www.informit.com/store/product.aspx?isbn=0130211192'],
+ 'title': [u'XML Processing with Python']}
Storing the scraped data
========================
@@ -415,7 +420,7 @@ Storing the scraped data
The simplest way to store the scraped data is by using the :ref:`Feed exports
`, with the following command::
- scrapy crawl dmoz.org --set FEED_URI=items.json --set FEED_FORMAT=json
+ scrapy crawl dmoz --set FEED_URI=items.json --set FEED_FORMAT=json
That will generate a ``items.json`` file containing all scraped items,
serialized in `JSON`_.
@@ -424,14 +429,16 @@ In small projects (like the one in this tutorial), that should be enough.
However, if you want to perform more complex things with the scraped items, you
can write an :ref:`Item Pipeline `. As with Items, a
placeholder file for Item Pipelines has been set up for you when the project is
-created, in ``dmoz/pipelines.py``. Though you don't need to implement any item
+created, in ``tutorial/pipelines.py``. Though you don't need to implement any item
pipeline if you just want to store the scraped items.
-Finale
-======
+Next steps
+==========
This tutorial covers only the basics of Scrapy, but there's a lot of other
-features not mentioned here. We recommend you continue reading the section
-:ref:`topics-index`.
+features not mentioned here. We recommend you continue by playing with an
+example project (see :ref:`intro-examples`), and then continue with the section
+:ref:`section-basics`.
.. _JSON: http://en.wikipedia.org/wiki/JSON
+.. _dirbot: https://github.com/scrapy/dirbot
diff --git a/docs/topics/_images/scrapy_architecture.odg b/docs/topics/_images/scrapy_architecture.odg
index 90b67c405..37dbc8eb5 100644
Binary files a/docs/topics/_images/scrapy_architecture.odg and b/docs/topics/_images/scrapy_architecture.odg differ
diff --git a/docs/topics/_images/scrapy_architecture.png b/docs/topics/_images/scrapy_architecture.png
index a591d4126..d7fa1be84 100644
Binary files a/docs/topics/_images/scrapy_architecture.png and b/docs/topics/_images/scrapy_architecture.png differ
diff --git a/docs/topics/architecture.rst b/docs/topics/architecture.rst
index fd24e6c88..bdab8552c 100644
--- a/docs/topics/architecture.rst
+++ b/docs/topics/architecture.rst
@@ -77,14 +77,6 @@ requests). They provide a convenient mechanism for extending Scrapy
functionality by plugging custom code. For more information see
:ref:`topics-spider-middleware`.
-Scheduler middlewares
----------------------
-
-Scheduler middlewares are specific hooks that sit between the Engine and the
-Scheduler and process requests when they pass from the Engine to the Scheduler
-and vice-versa. They provide a convenient mechanism for extending Scrapy
-functionality by plugging custom code.
-
Data flow
=========
diff --git a/docs/topics/commands.rst b/docs/topics/commands.rst
index 6b30a4e59..22d84d2d3 100644
--- a/docs/topics/commands.rst
+++ b/docs/topics/commands.rst
@@ -151,6 +151,7 @@ Project-only commands:
* :command:`crawl`
* :command:`list`
+* :command:`edit`
* :command:`parse`
* :command:`genspider`
* :command:`server`
@@ -217,22 +218,16 @@ Usage example::
crawl
-----
-* Syntax: ``scrapy crawl ``
+* Syntax: ``scrapy crawl ``
* Requires project: *yes*
-Start crawling a spider. If a URL is passed instead of a spider, it will start
-from that URL instead of the spider start urls.
+Start crawling a spider.
Usage examples::
- $ scrapy crawl example.com
- [ ... example.com spider starts crawling ... ]
-
$ scrapy crawl myspider
[ ... myspider starts crawling ... ]
- $ scrapy crawl http://example.com/some/page.html
- [ ... spider that handles example.com starts crawling from that url ... ]
.. command:: server
@@ -269,6 +264,25 @@ Usage example::
spider1
spider2
+.. command:: edit
+
+edit
+----
+
+* Syntax: ``scrapy edit ``
+* Requires project: *yes*
+
+Edit the given spider using the editor defined in the :setting:`EDITOR`
+setting.
+
+This command is provided only as a convenient shortcut for the most common
+case, the developer is of course free to choose any tool or IDE to write and
+debug his spiders.
+
+Usage example::
+
+ $ scrapy edit spider1
+
.. command:: fetch
fetch
diff --git a/docs/topics/downloader-middleware.rst b/docs/topics/downloader-middleware.rst
index 242523829..d845d671c 100644
--- a/docs/topics/downloader-middleware.rst
+++ b/docs/topics/downloader-middleware.rst
@@ -158,6 +158,8 @@ middleware, see the :ref:`downloader middleware usage guide
For a list of the components enabled by default (and their orders) see the
:setting:`DOWNLOADER_MIDDLEWARES_BASE` setting.
+.. _cookies-mw:
+
CookiesMiddleware
-----------------
@@ -166,7 +168,48 @@ CookiesMiddleware
.. class:: CookiesMiddleware
- This middleware enables working with sites that need cookies.
+ This middleware enables working with sites that require cookies, such as
+ those that use sessions. It keeps track of cookies sent by web servers, and
+ send them back on subsequent requests (from that spider), just like web
+ browsers do.
+
+The following settings can be used to configure the cookie middleware:
+
+* :setting:`COOKIES_ENABLED`
+* :setting:`COOKIES_DEBUG`
+
+.. setting:: COOKIES_ENABLED
+
+COOKIES_ENABLED
+~~~~~~~~~~~~~~~
+
+Default: ``True``
+
+Whether to enable the cookies middleware. If disabled, no cookies will be sent
+to web servers.
+
+.. setting:: COOKIES_DEBUG
+
+COOKIES_DEBUG
+~~~~~~~~~~~~~
+
+Default: ``False``
+
+If enabled, Scrapy will log all cookies sent in requests (ie. ``Cookie``
+header) and all cookies received in responses (ie. ``Set-Cookie`` header).
+
+Here's an example of a log with :setting:`COOKIES_DEBUG` enabled::
+
+ 2011-04-06 14:35:10-0300 [diningcity] INFO: Spider opened
+ 2011-04-06 14:35:10-0300 [diningcity] DEBUG: Sending cookies to:
+ Cookie: clientlanguage_nl=en_EN
+ 2011-04-06 14:35:14-0300 [diningcity] DEBUG: Received cookies from: <200 http://www.diningcity.com/netherlands/index.html>
+ Set-Cookie: JSESSIONID=B~FA4DC0C496C8762AE4F1A620EAB34F38; Path=/
+ Set-Cookie: ip_isocode=US
+ Set-Cookie: clientlanguage_nl=en_EN; Expires=Thu, 07-Apr-2011 21:21:34 GMT; Path=/
+ 2011-04-06 14:49:50-0300 [diningcity] DEBUG: Crawled (200) (referer: None)
+ [...]
+
DefaultHeadersMiddleware
------------------------
@@ -233,8 +276,18 @@ HttpCacheMiddleware
downloads every time) and for trying your spider offline, when an Internet
connection is not available.
-File system storage
-~~~~~~~~~~~~~~~~~~~
+ Scrapy ships with two storage backends for the HTTP cache middleware:
+
+ * :ref:`httpcache-fs-backend`
+ * :ref:`httpcache-dbm-backend`
+
+ You can change the storage backend with the :setting:`HTTPCACHE_STORAGE`
+ setting. Or you can also implement your own backend.
+
+.. _httpcache-fs-backend:
+
+File system backend (default)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
By default, the :class:`HttpCacheMiddleware` uses a file system storage with the following structure:
@@ -257,11 +310,22 @@ inefficient in many file systems). An example directory could be::
/path/to/cache/dir/example.com/72/72811f648e718090f041317756c03adb0ada46c7
-The cache storage backend can be changed with the :setting:`HTTPCACHE_STORAGE`
-setting, but no other backend is provided with Scrapy yet.
+.. _httpcache-dbm-backend:
-Settings
-~~~~~~~~
+DBM storage backend
+~~~~~~~~~~~~~~~~~~~
+
+.. versionadded:: 0.13
+
+A DBM_ storage backend is also available for the HTTP cache middleware. To use
+it (instead of the default filesystem backend) set :setting:`HTTPCACHE_STORAGE`
+to ``scrapy.contrib.httpcache.DbmCacheStorage``.
+
+By default, it uses the anydbm_ module, but you can change it with the
+:setting:`HTTPCACHE_DBM_MODULE` setting.
+
+HTTPCache middleware settings
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The :class:`HttpCacheMiddleware` can be configured through the following
settings:
@@ -346,6 +410,18 @@ Default: ``'scrapy.contrib.downloadermiddleware.httpcache.FilesystemCacheStorage
The class which implements the cache storage backend.
+.. setting:: HTTPCACHE_DBM_MODULE
+
+HTTPCACHE_DBM_MODULE
+^^^^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 0.13
+
+Default: ``'anydbm'``
+
+The database module to use in the :ref:`DBM storage backend
+`. This setting is specific to the DBM backend.
+
HttpCompressionMiddleware
-------------------------
@@ -358,6 +434,16 @@ HttpCompressionMiddleware
This middleware allows compressed (gzip, deflate) traffic to be
sent/received from web sites.
+ChunkedTransferMiddleware
+-------------------------
+
+.. module:: scrapy.contrib.downloadermiddleware.chunked
+ :synopsis: Chunked Transfer Middleware
+
+.. class:: ChunkedTransferMiddleware
+
+ This middleware adds support for `chunked transfer encoding`_
+
HttpProxyMiddleware
-------------------
@@ -400,15 +486,48 @@ in the ``redirect_urls`` :attr:`Request.meta ` key.
The :class:`RedirectMiddleware` can be configured through the following
settings (see the settings documentation for more info):
-* :setting:`REDIRECT_MAX_METAREFRESH_DELAY` - Maximum meta-refresh delay that a page is allowed to have for redirection.
-* :setting:`REDIRECT_MAX_TIMES` - Maximum number of redirects to perform on a request.
-* :setting:`REDIRECT_PRIORITY_ADJUST` - Adjusts the redirected request priority by this amount.
+* :setting:`REDIRECT_ENABLED`
+* :setting:`REDIRECT_MAX_TIMES`
+* :setting:`REDIRECT_MAX_METAREFRESH_DELAY`
.. reqmeta:: dont_redirect
If :attr:`Request.meta ` contains the
``dont_redirect`` key, the request will be ignored by this middleware.
+
+RedirectMiddleware settings
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. setting:: REDIRECT_ENABLED
+
+REDIRECT_ENABLED
+^^^^^^^^^^^^^^^^
+
+.. versionadded:: 0.13
+
+Default: ``True``
+
+Whether the Redirect middleware will be enabled.
+
+.. setting:: REDIRECT_MAX_TIMES
+
+REDIRECT_MAX_TIMES
+^^^^^^^^^^^^^^^^^^
+
+Default: ``20``
+
+The maximum number of redirections that will be follow for a single request.
+
+.. setting:: REDIRECT_MAX_METAREFRESH_DELAY
+
+REDIRECT_MAX_METAREFRESH_DELAY
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Default: ``100``
+
+The maximum meta-refresh delay (in seconds) to follow the redirection.
+
RetryMiddleware
---------------
@@ -428,12 +547,13 @@ Once there are no more failed pages to retry, this middleware sends a signal
The :class:`RetryMiddleware` can be configured through the following
settings (see the settings documentation for more info):
-* :setting:`RETRY_TIMES` - how many times to retry a failed page
-* :setting:`RETRY_HTTP_CODES` - which HTTP response codes to retry
+* :setting:`RETRY_ENABLED`
+* :setting:`RETRY_TIMES`
+* :setting:`RETRY_HTTP_CODES`
About HTTP errors to consider:
-You may want to remove 400 from RETRY_HTTP_CODES, if you stick to the
+You may want to remove 400 from :setting:`RETRY_HTTP_CODES`, if you stick to the
HTTP protocol. It's included by default because it's a common code used
to indicate server overload, which would be something we want to retry.
@@ -442,6 +562,39 @@ to indicate server overload, which would be something we want to retry.
If :attr:`Request.meta ` contains the ``dont_retry``
key, the request will be ignored by this middleware.
+RetryMiddleware Settings
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. setting:: RETRY_ENABLED
+
+RETRY_ENABLED
+^^^^^^^^^^^^^
+
+.. versionadded:: 0.13
+
+Default: ``True``
+
+Whether the Retry middleware will be enabled.
+
+.. setting:: RETRY_TIMES
+
+RETRY_TIMES
+^^^^^^^^^^^
+
+Default: ``2``
+
+Maximum number of times to retry, in addition to the first download.
+
+.. setting:: RETRY_HTTP_CODES
+
+RETRY_HTTP_CODES
+^^^^^^^^^^^^^^^^
+
+Default: ``[500, 503, 504, 400, 408]``
+
+Which HTTP response codes to retry. Other errors (DNS lookup issues,
+connections lost, etc) are always retried.
+
.. _topics-dlmw-robots:
RobotsTxtMiddleware
@@ -491,3 +644,7 @@ UserAgentMiddleware
In order for a spider to override the default user agent, its `user_agent`
attribute must be set.
+
+.. _DBM: http://en.wikipedia.org/wiki/Dbm
+.. _anydbm: http://docs.python.org/library/anydbm.html
+.. _chunked transfer encoding: http://en.wikipedia.org/wiki/Chunked_transfer_encoding
diff --git a/docs/topics/exceptions.rst b/docs/topics/exceptions.rst
index d75f28fed..8a10ee796 100644
--- a/docs/topics/exceptions.rst
+++ b/docs/topics/exceptions.rst
@@ -22,6 +22,23 @@ DropItem
The exception that must be raised by item pipeline stages to stop processing an
Item. For more information see :ref:`topics-item-pipeline`.
+CloseSpider
+-----------
+
+.. exception:: CloseSpider(reason='cancelled')
+
+ This exception can be raised from a spider callback to request the spider to be
+ closed/stopped. Supported arguments:
+
+ :param reason: the reason for closing
+ :type reason: str
+
+For example::
+
+ def parse_page(self, response):
+ if 'Bandwidth exceeded' in response.body:
+ raise CloseSpider('bandwidth_exceeded')
+
IgnoreRequest
-------------
diff --git a/docs/topics/exporters.rst b/docs/topics/exporters.rst
index 9c6d292b6..4090b4ed8 100644
--- a/docs/topics/exporters.rst
+++ b/docs/topics/exporters.rst
@@ -264,7 +264,7 @@ XmlItemExporter
CsvItemExporter
---------------
-.. class:: CsvItemExporter(file, include_headers_line=True, \**kwargs)
+.. class:: CsvItemExporter(file, include_headers_line=True, join_multivalued=',', \**kwargs)
Exports Items in CSV format to the given file-like object. If the
:attr:`fields_to_export` attribute is set, it will be used to define the
@@ -278,6 +278,10 @@ CsvItemExporter
:attr:`BaseItemExporter.fields_to_export` or the first exported item fields.
:type include_headers_line: boolean
+ :param join_multivalued: The char (or chars) that will be used for joining
+ multi-valued fields, if found.
+ :type include_headers_line: str
+
The additional keyword arguments of this constructor are passed to the
:class:`BaseItemExporter` constructor, and the leftover arguments to the
`csv.writer`_ constructor, so you can use any `csv.writer` constructor
diff --git a/docs/topics/extensions.rst b/docs/topics/extensions.rst
index fc9993517..b227fa493 100644
--- a/docs/topics/extensions.rst
+++ b/docs/topics/extensions.rst
@@ -178,10 +178,20 @@ Built-in extensions reference
General purpose extensions
--------------------------
+Log Stats extension
+~~~~~~~~~~~~~~~~~~~
+
+.. module:: scrapy.contrib.logstats
+ :synopsis: Basic stats logging
+
+.. class:: LogStats
+
+Log basic stats like crawled pages and scraped items.
+
Core Stats extension
~~~~~~~~~~~~~~~~~~~~
-.. module:: scrapy.contrib.corestats.corestats
+.. module:: scrapy.contrib.corestats
:synopsis: Core stats collection
.. class:: CoreStats
@@ -256,11 +266,14 @@ Memory debugger extension
.. class:: scrapy.contrib.memdebug.MemoryDebugger
-A memory debugger which collects some info about objects uncollected by the
-garbage collector and libxml2 memory leaks. To enable this extension, turn on
-the :setting:`MEMDEBUG_ENABLED` setting. The report will be printed to standard
-output. If the :setting:`MEMDEBUG_NOTIFY` setting contains a list of e-mails the
-report will also be sent to those addresses.
+An extension for debugging memory usage. It collects information about:
+
+* objects uncollected by the Python garbage collector
+* libxml2 memory leaks
+* objects left alive that shouldn't. For more info, see :ref:`topics-leaks-trackrefs`
+
+To enable this extension, turn on the :setting:`MEMDEBUG_ENABLED` setting. The
+info will be stored in the stats.
Close spider extension
~~~~~~~~~~~~~~~~~~~~~~
@@ -277,7 +290,7 @@ The conditions for closing a spider can be configured through the following
settings:
* :setting:`CLOSESPIDER_TIMEOUT`
-* :setting:`CLOSESPIDER_ITEMPASSED`
+* :setting:`CLOSESPIDER_ITEMCOUNT`
* :setting:`CLOSESPIDER_PAGECOUNT`
* :setting:`CLOSESPIDER_ERRORCOUNT`
@@ -293,16 +306,16 @@ more than that number of second, it will be automatically closed with the
reason ``closespider_timeout``. If zero (or non set), spiders won't be closed by
timeout.
-.. setting:: CLOSESPIDER_ITEMPASSED
+.. setting:: CLOSESPIDER_ITEMCOUNT
-CLOSESPIDER_ITEMPASSED
-""""""""""""""""""""""
+CLOSESPIDER_ITEMCOUNT
+"""""""""""""""""""""
Default: ``0``
An integer which specifies a number of items. If the spider scrapes more than
that amount if items and those items are passed by the item pipeline, the
-spider will be closed with the reason ``closespider_itempassed``. If zero (or
+spider will be closed with the reason ``closespider_itemcount``. If zero (or
non set), spiders won't be closed by number of passed items.
.. setting:: CLOSESPIDER_PAGECOUNT
@@ -357,15 +370,25 @@ Stack trace dump extension
.. class:: scrapy.contrib.debug.StackTraceDump
-Dumps the stack trace of a runnning Scrapy process when a `SIGUSR2`_ signal is
-received. After the stack trace is dumped, the Scrapy process continues running
-normally.
+Dumps the stack trace and Scrapy engine status of a runnning process when a
+`SIGQUIT`_ or `SIGUSR2`_ signal is received. After the stack trace and engine
+status is dumped, the Scrapy process continues running normally.
-The stack trace is sent to standard output.
+The dump is sent to standard output.
This extension only works on POSIX-compliant platforms (ie. not Windows).
+There are at least two ways to send Scrapy the `SIGQUIT`_ signal:
+
+1. By pressing Ctrl-\ while a Scrapy process is running (Linux only?)
+
+2. By running this command (assuming ```` is the process id of the Scrapy
+ process)::
+
+ kill -QUIT
+
.. _SIGUSR2: http://en.wikipedia.org/wiki/SIGUSR1_and_SIGUSR2
+.. _SIGQUIT: http://en.wikipedia.org/wiki/SIGQUIT
Debugger extension
~~~~~~~~~~~~~~~~~~
diff --git a/docs/topics/feed-exports.rst b/docs/topics/feed-exports.rst
index 02d184e72..a97613e6e 100644
--- a/docs/topics/feed-exports.rst
+++ b/docs/topics/feed-exports.rst
@@ -64,6 +64,15 @@ XML
* :setting:`FEED_FORMAT`: ``xml``
* Exporter used: :class:`~scrapy.contrib.exporter.XmlItemExporter`
+.. _topics-feed-format-marshal:
+
+Marshal
+-------
+
+ * :setting:`FEED_FORMAT`: ``marshal``
+ * Exporter used: :class:`~scrapy.contrib.exporter.MarshalItemExporter`
+
+
.. _topics-feed-storage:
Storages
@@ -267,6 +276,7 @@ Default::
'jsonlines': 'scrapy.contrib.exporter.JsonLinesItemExporter',
'csv': 'scrapy.contrib.exporter.CsvItemExporter',
'xml': 'scrapy.contrib.exporter.XmlItemExporter',
+ 'marshal': 'scrapy.contrib.exporter.MarshalItemExporter',
}
A dict containing the built-in feed exporters supported by Scrapy.
diff --git a/docs/topics/items.rst b/docs/topics/items.rst
index 5142f649b..8969bf3e3 100644
--- a/docs/topics/items.rst
+++ b/docs/topics/items.rst
@@ -30,8 +30,8 @@ objects. Here is an example::
class Product(Item):
name = Field()
price = Field()
- stock = Field(default=0)
- last_updated = Field()
+ stock = Field()
+ last_updated = Field(serializer=str)
.. note:: Those familiar with `Django`_ will notice that Scrapy Items are
declared similar to `Django Models`_, except that Scrapy Items are much
@@ -46,8 +46,8 @@ Item Fields
===========
:class:`Field` objects are used to specify metadata for each field. For
-example, the default value for the ``stock`` field illustrated in the example
-above.
+example, the serializer function for the ``last_updated`` field illustrated in
+the example above.
You can specify any kind of metadata for each field. There is no restriction on
the values accepted by :class:`Field` objects. For this same
@@ -95,10 +95,7 @@ Getting field values
>>> product['price']
1000
- >>> product['stock'] # getting field with default value
- 0
-
- >>> product['last_updated'] # getting field with no default value
+ >>> product['last_updated']
Traceback (most recent call last):
...
KeyError: 'last_updated'
@@ -175,28 +172,6 @@ Creating items from dicts::
...
KeyError: 'Product does not support field: lala'
-Default values
-==============
-
-The only field metadata key supported by Items themselves is ``default``, which
-specifies the default value to return when trying to access a field which
-wasn't populated before.
-
-So, for the ``Product`` item declared above::
-
- >>> product = Product()
-
- >>> product['stock'] # field with default value
- 0
-
- >>> product['name'] # field with no default value
- Traceback (most recent call last):
- ...
- KeyError: 'name'
-
- >>> product.get('name') is None
- True
-
Extending Items
===============
@@ -206,16 +181,16 @@ fields) by declaring a subclass of your original Item.
For example::
class DiscountedProduct(Product):
- discount_percent = Field(default=0)
+ discount_percent = Field(serializer=str)
discount_expiration_date = Field()
You can also extend field metadata by using the previous field metadata and
appending more values, or changing existing values, like this::
class SpecificProduct(Product):
- name = Field(Product.fields['name'], default='product')
+ name = Field(Product.fields['name'], serializer=my_serializer)
-That adds (or replaces) the ``default`` metadata key for the ``name`` field,
+That adds (or replaces) the ``serializer`` metadata key for the ``name`` field,
keeping all the previously existing metadata values.
Item objects
diff --git a/docs/topics/link-extractors.rst b/docs/topics/link-extractors.rst
index 41160a57d..ac53eaa59 100644
--- a/docs/topics/link-extractors.rst
+++ b/docs/topics/link-extractors.rst
@@ -42,7 +42,7 @@ All available link extractors classes bundled with Scrapy are provided in the
SgmlLinkExtractor
-----------------
-.. class:: SgmlLinkExtractor(allow=(), deny=(), allow_domains=(), deny_domains=(), restrict_xpaths(), tags=('a', 'area'), attrs=('href'), canonicalize=True, unique=True, process_value=None)
+.. class:: SgmlLinkExtractor(allow=(), deny=(), allow_domains=(), deny_domains=(), deny_extensions=None, restrict_xpaths(), tags=('a', 'area'), attrs=('href'), canonicalize=True, unique=True, process_value=None)
The SgmlLinkExtractor extends the base :class:`BaseSgmlLinkExtractor` by
providing additional filters that you can specify to extract links,
@@ -59,15 +59,21 @@ SgmlLinkExtractor
that the (absolute) urls must match in order to be excluded (ie. not
extracted). It has precedence over the ``allow`` parameter. If not
given (or empty) it won't exclude any links.
- :type allow: a regular expression (or list of)
+ :type deny: a regular expression (or list of)
:param allow_domains: a single value or a list of string containing
domains which will be considered for extracting the links
- :type allow: str or list
+ :type allow_domains: str or list
:param deny_domains: a single value or a list of strings containing
domains which won't be considered for extracting the links
- :type allow: str or list
+ :type deny_domains: str or list
+
+ :param deny_extensions: a list of extensions that should be ignored when
+ extracting links. If not given, it will default to the
+ ``IGNORED_EXTENSIONS`` list defined in the `scrapy.linkextractor`_
+ module.
+ :type deny_extensions: list
:param restrict_xpaths: is a XPath (or list of XPath's) which defines
regions inside the response where links should be extracted from.
@@ -145,3 +151,4 @@ BaseSgmlLinkExtractor
:type process_value: callable
+.. _scrapy.linkextractor: http://dev.scrapy.org/browser/scrapy/linkextractor.py
diff --git a/docs/topics/request-response.rst b/docs/topics/request-response.rst
index a1092b8e6..baeec8701 100644
--- a/docs/topics/request-response.rst
+++ b/docs/topics/request-response.rst
@@ -68,6 +68,8 @@ Request objects
request_with_cookies = Request(url="http://www.example.com",
cookies={currency: 'USD', country: 'UY'},
meta={'dont_merge_cookies': True})
+
+ For more info see :ref:`cookies-mw`.
:type cookies: dict
:param encoding: the encoding of this request (defaults to ``'utf-8'``).
diff --git a/docs/topics/scrapyd.rst b/docs/topics/scrapyd.rst
index b44b0b47b..4e00ea978 100644
--- a/docs/topics/scrapyd.rst
+++ b/docs/topics/scrapyd.rst
@@ -86,7 +86,7 @@ in your Ubuntu servers.
So, if you plan to deploy Scrapyd on a Ubuntu server, just add the Ubuntu
repositories as described in :ref:`topics-ubuntu` and then run::
- aptitude install scrapyd-0.12
+ aptitude install scrapyd-0.13
This will install Scrapyd in your Ubuntu server creating a ``scrapy`` user
which Scrapyd will run as. It will also create some directories and files that
diff --git a/docs/topics/settings.rst b/docs/topics/settings.rst
index 2a1d9aeb2..8f4b194ce 100644
--- a/docs/topics/settings.rst
+++ b/docs/topics/settings.rst
@@ -242,15 +242,39 @@ Default: ``100``
Maximum number of concurrent items (per response) to process in parallel in the
Item Processor (also known as the :ref:`Item Pipeline `).
-.. setting:: CONCURRENT_REQUESTS_PER_SPIDER
+.. setting:: CONCURRENT_REQUESTS
-CONCURRENT_REQUESTS_PER_SPIDER
+CONCURRENT_REQUESTS
+-------------------
+
+Default: ``16``
+
+The maximum number of concurrent (ie. simultaneous) requests that will be
+performed by the Scrapy downloader.
+
+
+.. setting:: CONCURRENT_REQUESTS_PER_DOMAIN
+
+CONCURRENT_REQUESTS_PER_DOMAIN
------------------------------
Default: ``8``
-Specifies how many concurrent (ie. simultaneous) requests will be performed per
-open spider.
+The maximum number of concurrent (ie. simultaneous) requests that will be
+performed to any single domain.
+
+.. setting:: CONCURRENT_REQUESTS_PER_IP
+
+CONCURRENT_REQUESTS_PER_IP
+--------------------------
+
+Default: ``0``
+
+The maximum number of concurrent (ie. simultaneous) requests that will be
+performed to any single IP. If non-zero, the
+:setting:`CONCURRENT_REQUESTS_PER_DOMAIN` setting is ignored, and this one is
+used instead. In other words, concurrency limits will be applied per IP, not
+per domain.
.. setting:: CONCURRENT_SPIDERS
@@ -261,15 +285,6 @@ Default: ``8``
Maximum number of spiders to scrape in parallel.
-.. setting:: COOKIES_DEBUG
-
-COOKIES_DEBUG
--------------
-
-Default: ``False``
-
-Enable debugging message of Cookies Downloader Middleware.
-
.. setting:: DEFAULT_ITEM_CLASS
DEFAULT_ITEM_CLASS
@@ -316,6 +331,22 @@ Default: ``0``
The maximum depth that will be allowed to crawl for any site. If zero, no limit
will be imposed.
+.. setting:: DEPTH_PRIORITY
+
+DEPTH_PRIORITY
+--------------
+
+Default: ``1``
+
+An integer that is used to set the request priority based on request depth.
+
+To crawl in `breath-first order`_, set :setting:`DEPTH_PRIORITY` to ``1``.
+
+To crawl in `depth-first order`_, set :setting:`DEPTH_PRIORITY` to ``-1``.
+
+To disable any priority adjustment based on depth, set
+:setting:`DEPTH_PRIORITY` to ``0``.
+
.. setting:: DEPTH_STATS
DEPTH_STATS
@@ -323,7 +354,26 @@ DEPTH_STATS
Default: ``True``
-Whether to collect depth stats.
+Whether to collect maximum depth stats.
+
+.. setting:: DEPTH_STATS_VERBOSE
+
+DEPTH_STATS_VERBOSE
+-------------------
+
+Default: ``False``
+
+Whether to collect verbose depth stats. If this is enabled, the number of
+requests for each depth is collected in the stats.
+
+.. setting:: DNSCACHE_ENABLED
+
+DNSCACHE_ENABLED
+----------------
+
+Default: ``True``
+
+Whether to enable DNS in-memory cache.
.. setting:: DOWNLOADER_DEBUG
@@ -354,6 +404,7 @@ Default::
{
'scrapy.contrib.downloadermiddleware.robotstxt.RobotsTxtMiddleware': 100,
'scrapy.contrib.downloadermiddleware.httpauth.HttpAuthMiddleware': 300,
+ 'scrapy.contrib.downloadermiddleware.downloadtimeout.DownloadTimeoutMiddleware': 350,
'scrapy.contrib.downloadermiddleware.useragent.UserAgentMiddleware': 400,
'scrapy.contrib.downloadermiddleware.retry.RetryMiddleware': 500,
'scrapy.contrib.downloadermiddleware.defaultheaders.DefaultHeadersMiddleware': 550,
@@ -361,6 +412,7 @@ Default::
'scrapy.contrib.downloadermiddleware.cookies.CookiesMiddleware': 700,
'scrapy.contrib.downloadermiddleware.httpproxy.HttpProxyMiddleware': 750,
'scrapy.contrib.downloadermiddleware.httpcompression.HttpCompressionMiddleware': 800,
+ 'scrapy.contrib.downloadermiddleware.chunked.ChunkedTransferMiddleware': 830,
'scrapy.contrib.downloadermiddleware.stats.DownloaderStats': 850,
'scrapy.contrib.downloadermiddleware.httpcache.HttpCacheMiddleware': 900,
}
@@ -442,12 +494,21 @@ The amount of time (in secs) that the downloader will wait before timing out.
DUPEFILTER_CLASS
----------------
-Default: ``'scrapy.contrib.dupefilter.RequestFingerprintDupeFilter'``
+Default: ``'scrapy.dupefilter.RFPDupeFilter'``
The class used to detect and filter duplicate requests.
-The default (``RequestFingerprintDupeFilter``) filters based on request fingerprint
-(using ``scrapy.utils.request.request_fingerprint``) and grouping per domain.
+The default (``RFPDupeFilter``) filters based on request fingerprint using
+the ``scrapy.utils.request.request_fingerprint`` function.
+
+.. setting:: EDITOR
+
+EDITOR
+------
+
+The editor to use for editing spiders with the :command:`edit` command. It
+defaults to the ``EDITOR`` environment variable, if set. Otherwise, it defaults
+to ``vi`` (on Unix systems) or the IDLE editor (on Windows).
.. setting:: ENCODING_ALIASES
@@ -526,7 +587,7 @@ A dict containing the extensions enabled in your project, and their orders.
EXTENSIONS_BASE
---------------
-Default::
+Default::
{
'scrapy.contrib.corestats.CoreStats': 0,
@@ -534,7 +595,10 @@ Default::
'scrapy.telnet.TelnetConsole': 0,
'scrapy.contrib.memusage.MemoryUsage': 0,
'scrapy.contrib.memdebug.MemoryDebugger': 0,
- 'scrapy.contrib.closedomain.CloseDomain': 0,
+ 'scrapy.contrib.closespider.CloseSpider': 0,
+ 'scrapy.contrib.feedexport.FeedExporter': 0,
+ 'scrapy.contrib.spidercontext.SpiderContext': 0,
+ 'scrapy.contrib.logstats.LogStats': 0,
}
The list of available extensions. Keep in mind that some of them need to
@@ -687,7 +751,7 @@ Default: ``False``
Scope: ``scrapy.contrib.memusage``
-Whether to send a memory usage report after each domain has been closed.
+Whether to send a memory usage report after each spider has been closed.
See :ref:`topics-extensions-ref-memusage`.
@@ -789,51 +853,6 @@ Default: ``'scrapy.core.scheduler.Scheduler'``
The scheduler to use for crawling.
-.. setting:: SCHEDULER_ORDER
-
-SCHEDULER_ORDER
----------------
-
-Default: ``'DFO'``
-
-Scope: ``scrapy.core.scheduler``
-
-The order to use for the crawling scheduler. Available orders are:
-
-* ``'BFO'``: `Breadth-first order`_ - typically consumes more memory but
- reaches most relevant pages earlier.
-
-* ``'DFO'``: `Depth-first order`_ - typically consumes less memory than
- but takes longer to reach most relevant pages.
-
-.. _Breadth-first order: http://en.wikipedia.org/wiki/Breadth-first_search
-.. _Depth-first order: http://en.wikipedia.org/wiki/Depth-first_search
-
-.. setting:: SCHEDULER_MIDDLEWARES
-
-SCHEDULER_MIDDLEWARES
----------------------
-
-Default:: ``{}``
-
-A dict containing the scheduler middlewares enabled in your project, and their
-orders.
-
-.. setting:: SCHEDULER_MIDDLEWARES_BASE
-
-SCHEDULER_MIDDLEWARES_BASE
---------------------------
-
-Default::
-
- SCHEDULER_MIDDLEWARES_BASE = {
- 'scrapy.contrib.schedulermiddleware.duplicatesfilter.DuplicatesFilterMiddleware': 500,
- }
-
-A dict containing the scheduler middlewares enabled by default in Scrapy. You
-should never modify this setting in your project, modify
-:setting:`SCHEDULER_MIDDLEWARES` instead.
-
.. setting:: SPIDER_MIDDLEWARES
SPIDER_MIDDLEWARES
@@ -853,7 +872,6 @@ Default::
{
'scrapy.contrib.spidermiddleware.httperror.HttpErrorMiddleware': 50,
- 'scrapy.contrib.itemsampler.ItemSamplerMiddleware': 100,
'scrapy.contrib.spidermiddleware.offsite.OffsiteMiddleware': 500,
'scrapy.contrib.spidermiddleware.referer.RefererMiddleware': 700,
'scrapy.contrib.spidermiddleware.urllength.UrlLengthMiddleware': 800,
@@ -905,11 +923,13 @@ or subclass the StatsCollector class).
STATS_DUMP
----------
-Default: ``False``
+Default: ``True``
-Dump (to log) domain-specific stats collected when a domain is closed, and all
-global stats when the Scrapy process finishes (ie. when the engine is
-shutdown).
+Dump (to the Scrapy log) the :ref:`Scrapy stats ` collected
+during the crawl. The spider-specific stats are logged when the spider is
+closed, while the global stats are dumped when the Scrapy process finishes.
+
+For more info see: :ref:`topics-stats`.
.. setting:: STATS_ENABLED
@@ -927,7 +947,7 @@ STATSMAILER_RCPTS
Default: ``[]`` (empty list)
-Send Scrapy stats after domains finish scraping. See
+Send Scrapy stats after spiders finish scraping. See
:class:`~scrapy.contrib.statsmailer.StatsMailer` for more info.
.. setting:: TELNETCONSOLE_ENABLED
@@ -983,3 +1003,5 @@ Default: ``"%s/%s" % (BOT_NAME, BOT_VERSION)``
The default User-Agent to use when crawling, unless overridden.
.. _Amazon web services: http://aws.amazon.com/
+.. _breadth-first order: http://en.wikipedia.org/wiki/Breadth-first_search
+.. _depth-first order: http://en.wikipedia.org/wiki/Depth-first_search
diff --git a/docs/topics/signals.rst b/docs/topics/signals.rst
index d3875826b..f1eb00385 100644
--- a/docs/topics/signals.rst
+++ b/docs/topics/signals.rst
@@ -43,11 +43,14 @@ engine_started
.. signal:: engine_started
.. function:: engine_started()
- Sent when the Scrapy engine is started (for example, when a crawling
- process has started).
+ Sent when the Scrapy engine has started crawling.
This signal supports returning deferreds from their handlers.
+.. note:: This signal may be fired *after* the :signal:`spider_opened` signal,
+ depending on how the spider was started. So **don't** rely on this signal
+ getting fired before :signal:`spider_opened`.
+
engine_stopped
--------------
@@ -63,45 +66,22 @@ item_scraped
------------
.. signal:: item_scraped
-.. function:: item_scraped(item, spider, response)
+.. function:: item_scraped(item, response, spider)
- Sent when the engine receives a new scraped item from the spider, and right
- before the item is sent to the :ref:`topics-item-pipeline`.
+ Sent when an item has been scraped, after it has passed all the
+ :ref:`topics-item-pipeline` stages (without being dropped).
This signal supports returning deferreds from their handlers.
- :param item: is the item scraped
+ :param item: the item scraped
:type item: :class:`~scrapy.item.Item` object
- :param spider: the spider which scraped the item
- :type spider: :class:`~scrapy.spider.BaseSpider` object
-
- :param response: the response from which the item was scraped
+ :param response: the response from where the item was scraped
:type response: :class:`~scrapy.http.Response` object
-item_passed
------------
-
-.. signal:: item_passed
-.. function:: item_passed(item, spider, original_item)
-
- Sent after an item has passed all the :ref:`topics-item-pipeline` stages
- without being dropped. Same as :func:`item_scraped` if there are no
- pipelines enabled.
-
- This signal supports returning deferreds from their handlers.
-
- :param item: the item which passed the pipeline
- :type item: :class:`~scrapy.item.Item` object
-
:param spider: the spider which scraped the item
:type spider: :class:`~scrapy.spider.BaseSpider` object
- :param original_item: the input of the item pipeline. This is typically the
- same :class:`~scrapy.item.Item` object received in the ``item``
- parameter, unless some pipeline stage created a new item.
- :type spider: :class:`~scrapy.spider.BaseSpider` object
-
item_dropped
------------
@@ -186,6 +166,24 @@ spider_idle
:param spider: the spider which has gone idle
:type spider: :class:`~scrapy.spider.BaseSpider` object
+spider_error
+------------
+
+.. signal:: spider_error
+.. function:: spider_error(failure, response, spider)
+
+ Sent when a spider callback generates an error (ie. raises an exception).
+
+ :param failure: the exception raised as a Twisted `Failure`_ object
+ :type failure: `Failure`_ object
+
+ :param response: the response being processed when the exception was raised
+ :type response: :class:`~scrapy.http.Response` object
+
+ :param spider: the spider which raised the exception
+ :type spider: :class:`~scrapy.spider.BaseSpider` object
+
+
request_received
----------------
@@ -241,3 +239,4 @@ response_downloaded
:param spider: the spider for which the response is intended
:type spider: :class:`~scrapy.spider.BaseSpider` object
+.. _Failure: http://twistedmatrix.com/documents/current/api/twisted.python.failure.Failure.html
diff --git a/docs/topics/spider-middleware.rst b/docs/topics/spider-middleware.rst
index 1db93259a..66059e6af 100644
--- a/docs/topics/spider-middleware.rst
+++ b/docs/topics/spider-middleware.rst
@@ -106,7 +106,7 @@ single Python class that defines one or more of the following methods:
.. method:: process_spider_exception(response, exception, spider)
- This method is called when when a spider or :meth:process_spider_input:
+ This method is called when when a spider or :meth:`process_spider_input`
method (from other spider middleware) raises an exception.
:meth:`process_spider_exception` should return either ``None`` or an
@@ -164,6 +164,8 @@ DepthMiddleware
* :setting:`DEPTH_LIMIT` - The maximum depth that will be allowed to
crawl for any site. If zero, no limit will be imposed.
* :setting:`DEPTH_STATS` - Whether to collect depth stats.
+ * :setting:`DEPTH_PRIORITY` - Whether to prioritize the requests based on
+ their depth, to crawl in breadh-first or depth-first order.
HttpErrorMiddleware
-------------------
diff --git a/docs/topics/spiders.rst b/docs/topics/spiders.rst
index dd5f6a6e2..081930451 100644
--- a/docs/topics/spiders.rst
+++ b/docs/topics/spiders.rst
@@ -45,8 +45,13 @@ We will talk about those types here.
Built-in spiders reference
==========================
-For the examples used in the following spiders reference, we'll assume we have a
-``TestItem`` declared in a ``myproject.items`` module, in your project::
+Scrapy comes with some useful generic spiders that you can use, to subclass
+your spiders from. Their aim is to provide convenient functionality for a few
+common scraping cases, like following all links on a site based on certain
+rules, crawling from `Sitemaps`_, or parsing a XML/CSV feed.
+
+For the examples used in the following spiders, we'll assume you have a project
+with a ``TestItem`` declared in a ``myproject.items`` module::
from scrapy.item import Item
@@ -228,6 +233,7 @@ CrawlSpider
Crawling rules
~~~~~~~~~~~~~~
+
.. class:: Rule(link_extractor, callback=None, cb_kwargs=None, follow=None, process_links=None, process_request=None)
``link_extractor`` is a :ref:`Link Extractor ` object which
@@ -262,7 +268,7 @@ Crawling rules
filter out the request).
CrawlSpider example
--------------------
+~~~~~~~~~~~~~~~~~~~
Let's now take a look at an example CrawlSpider with rules::
@@ -465,3 +471,126 @@ Let's see an example similar to the previous one, but using a
item['name'] = row['name']
item['description'] = row['description']
return item
+
+
+SitemapSpider
+-------------
+
+.. class:: SitemapSpider
+
+ SitemapSpider allows you to crawl a site by discovering the URLs using
+ `Sitemaps`_.
+
+ It supports nested sitemaps and discovering sitemap urls from
+ `robots.txt`_.
+
+ .. attribute:: sitemap_urls
+
+ A list of urls pointing to the sitemaps whose urls you want to crawl.
+
+ You can also point to a `robots.txt`_ and it will be parsed to extract
+ sitemap urls from it.
+
+ .. attribute:: sitemap_rules
+
+ A list of tuples ``(regex, callback)`` where:
+
+ * ``regex`` is a regular expression to match urls extracted from sitemaps.
+ ``regex`` can be either a str or a compiled regex object.
+
+ * callback is the callback to use for processing the urls that match
+ the regular expression. ``callback`` can be a string (indicating the
+ name of a spider method) or a callable.
+
+ For example::
+
+ sitemap_rules = [('/product/', 'parse_product')]
+
+ Rules are applied in order, and only the first one that matches will be
+ used.
+
+ If you omit this attribute, all urls found in sitemaps will be
+ processed with the ``parse`` callback.
+
+ .. attribute:: sitemap_follow
+
+ A list of regexes of sitemap that should be followed. This is is only
+ for sites that use `Sitemap index files`_ that point to other sitemap
+ files.
+
+ By default, all sitemaps are followed.
+
+
+SitemapSpider examples
+~~~~~~~~~~~~~~~~~~~~~~
+
+Simplest example: process all urls discovered through sitemaps using the
+``parse`` callback::
+
+ from scrapy.contrib.spiders import SitemapSpider
+
+ class MySpider(SitemapSpider):
+ sitemap_urls = ['http://www.example.com/sitemap.xml']
+
+ def parse(self, response):
+ pass # ... scrape item here ...
+
+Process some urls with certain callback and other urls with a different
+callback::
+
+ from scrapy.contrib.spiders import SitemapSpider
+
+ class MySpider(SitemapSpider):
+ sitemap_urls = ['http://www.example.com/sitemap.xml']
+ sitemap_rules = [
+ ('/product/', 'parse_product'),
+ ('/category/', 'parse_category'),
+ ]
+
+ def parse_product(self, response):
+ pass # ... scrape product ...
+
+ def parse_category(self, response):
+ pass # ... scrape category ...
+
+Follow sitemaps defined in the `robots.txt`_ file and only follow sitemaps
+whose url contains ``/sitemap_shop``::
+
+ from scrapy.contrib.spiders import SitemapSpider
+
+ class MySpider(SitemapSpider):
+ sitemap_urls = ['http://www.example.com/robots.txt']
+ sitemap_rules = [
+ ('/shop/', 'parse_shop'),
+ ]
+ sitemap_follow = ['/sitemap_shops']
+
+ def parse_shop(self, response):
+ pass # ... scrape shop here ...
+
+Combine SitemapSpider with other sources of urls::
+
+ from scrapy.contrib.spiders import SitemapSpider
+
+ class MySpider(SitemapSpider):
+ sitemap_urls = ['http://www.example.com/robots.txt']
+ sitemap_rules = [
+ ('/shop/', 'parse_shop'),
+ ]
+
+ other_urls = ['http://www.example.com/about']
+
+ def start_requests(self):
+ requests = list(super(MySpider, self).start_requests())
+ requests += [Request(x, callback=self.parse_other) for x in self.other_urls]
+ return requests
+
+ def parse_shop(self, response):
+ pass # ... scrape shop here ...
+
+ def parse_other(self, response):
+ pass # ... scrape other here ...
+
+.. _Sitemaps: http://www.sitemaps.org
+.. _Sitemap index files: http://www.sitemaps.org/protocol.php#index
+.. _robots.txt: http://www.robotstxt.org/
diff --git a/docs/topics/stats.rst b/docs/topics/stats.rst
index 072164e5b..f493a2df8 100644
--- a/docs/topics/stats.rst
+++ b/docs/topics/stats.rst
@@ -185,6 +185,10 @@ class (which they all inherit from).
for this spider can be accessed. This method is called automatically on
the :signal:`spider_closed` signal.
+ .. method:: engine_stopped()
+
+ Called after the engine is stopped, to dump or persist global stats.
+
Available Stats Collectors
==========================
@@ -223,65 +227,6 @@ DummyStatsCollector
Stats Collector used when stats are disabled (through the
:setting:`STATS_ENABLED` setting).
-SimpledbStatsCollector
-----------------------
-
-.. module:: scrapy.contrib.statscol
- :synopsis: Additional Stats Collectors
-
-.. class:: SimpledbStatsCollector
-
- A Stats collector which persists stats to `Amazon SimpleDB`_, using one
- SimpleDB item per scraping run (ie. it keeps history of all scraping runs).
- The data is persisted to the SimpleDB domain specified by the
- :setting:`STATS_SDB_DOMAIN` setting. The domain will be created if it
- doesn't exist.
-
- In addition to the existing stats keys, the following keys are added at
- persitance time:
-
- * ``spider``: the spider name (so you can use it later for querying stats
- for that spider)
- * ``timestamp``: the timestamp when the stats were persisted
-
- Both the ``spider`` and ``timestamp`` are used to generate the SimpleDB
- item name in order to avoid overwriting stats of previous scraping runs.
-
- As `required by SimpleDB`_, datetimes are stored in ISO 8601 format and
- numbers are zero-padded to 16 digits. Negative numbers are not currently
- supported.
-
- This Stats Collector requires the `boto`_ library.
-
-.. _Amazon SimpleDB: http://aws.amazon.com/simpledb/
-.. _required by SimpleDB: http://docs.amazonwebservices.com/AmazonSimpleDB/2009-04-15/DeveloperGuide/ZeroPadding.html
-.. _boto: http://code.google.com/p/boto/
-
-This Stats Collector can be configured through the following settings:
-
-.. setting:: STATS_SDB_DOMAIN
-
-STATS_SDB_DOMAIN
-~~~~~~~~~~~~~~~~
-
-Default: ``'scrapy_stats'``
-
-A string containing the SimpleDB domain to use in the
-:class:`SimpledbStatsCollector`.
-
-.. setting:: STATS_SDB_ASYNC
-
-STATS_SDB_ASYNC
-~~~~~~~~~~~~~~~
-
-Default: ``False``
-
-If ``True``, communication with SimpleDB will be performed asynchronously. If
-``False`` blocking IO will be used instead. This is the default as using
-asynchronous communication can result in the stats not being persisted if the
-Scrapy engine is shut down in the middle (for example, when you run only one
-spider in a process and then exit).
-
Stats signals
=============
diff --git a/docs/topics/telnetconsole.rst b/docs/topics/telnetconsole.rst
index 27d170c77..4b8b9a9d8 100644
--- a/docs/topics/telnetconsole.rst
+++ b/docs/topics/telnetconsole.rst
@@ -43,9 +43,13 @@ convenience:
+----------------+-------------------------------------------------------------------+
| Shortcut | Description |
+================+===================================================================+
-| ``manager`` | the Project Crawler object (``scrapy.project.crawler``) |
+| ``crawler`` | the Scrapy Crawler object (``scrapy.crawler``) |
+----------------+-------------------------------------------------------------------+
-| ``engine`` | the Scrapy engine object (``scrapy.project.crawler.engine``) |
+| ``engine`` | the Scrapy Engine object (``scrapy.core.engine``) |
++----------------+-------------------------------------------------------------------+
+| ``spider`` | the spider object (only if there is a single spider opened) |
++----------------+-------------------------------------------------------------------+
+| ``slot`` | the engine slot (only if there is a single spider opened) |
+----------------+-------------------------------------------------------------------+
| ``extensions`` | the Extension Manager (``scrapy.project.crawler.extensions``) |
+----------------+-------------------------------------------------------------------+
@@ -79,30 +83,29 @@ using the telnet console::
>>> est()
Execution engine status
- datetime.now()-self.start_time : 0:00:09.051588
- self.is_idle() : False
- self.scheduler.is_idle() : False
- len(self.scheduler.pending_requests) : 1
- self.downloader.is_idle() : False
- len(self.downloader.sites) : 1
- self.downloader.has_capacity() : True
- self.pipeline.is_idle() : False
- len(self.pipeline.domaininfo) : 1
- len(self._scraping) : 1
+ time()-engine.start_time : 21.3188259602
+ engine.is_idle() : False
+ engine.has_capacity() : True
+ engine.scheduler.is_idle() : False
+ len(engine.scheduler.pending_requests) : 1
+ engine.downloader.is_idle() : False
+ len(engine.downloader.slots) : 1
+ engine.scraper.is_idle() : False
+ len(engine.scraper.slots) : 1
- example.com
- self.domain_is_idle(domain) : False
- self.closing.get(domain) : None
- self.scheduler.domain_has_pending_requests(domain) : True
- len(self.scheduler.pending_requests[domain]) : 97
- len(self.downloader.sites[domain].queue) : 17
- len(self.downloader.sites[domain].active) : 25
- len(self.downloader.sites[domain].transferring) : 8
- self.downloader.sites[domain].closing : False
- self.downloader.sites[domain].lastseen : 2009-06-23 15:20:16.563675
- self.pipeline.domain_is_idle(domain) : True
- len(self.pipeline.domaininfo[domain]) : 0
- len(self._scraping[domain]) : 0
+ Spider:
+ engine.spider_is_idle(spider) : False
+ engine.slots[spider].closing : False
+ len(engine.scheduler.pending_requests[spider]) : 11504
+ len(engine.downloader.slots[spider].queue) : 9
+ len(engine.downloader.slots[spider].active) : 17
+ len(engine.downloader.slots[spider].transferring) : 8
+ engine.downloader.slots[spider].lastseen : 1311311093.61
+ len(engine.scraper.slots[spider].queue) : 0
+ len(engine.scraper.slots[spider].active) : 0
+ engine.scraper.slots[spider].active_size : 0
+ engine.scraper.slots[spider].itemproc_size : 0
+ engine.scraper.slots[spider].needs_backout() : False
Pause, resume and stop the Scrapy engine
diff --git a/docs/topics/ubuntu.rst b/docs/topics/ubuntu.rst
index 5af4eb856..f554c8b6b 100644
--- a/docs/topics/ubuntu.rst
+++ b/docs/topics/ubuntu.rst
@@ -13,7 +13,7 @@ latest bug fixes.
To use the packages, just add the following line to your
``/etc/apt/sources.list``, and then run ``aptitude update`` and ``aptitude
-install scrapy-0.12``::
+install scrapy-0.13``::
deb http://archive.scrapy.org/ubuntu DISTRO main
diff --git a/docs/versioning.rst b/docs/versioning.rst
new file mode 100644
index 000000000..cbe670b35
--- /dev/null
+++ b/docs/versioning.rst
@@ -0,0 +1,47 @@
+.. _versioning:
+
+============================
+Versioning and API Stability
+============================
+
+Versioning
+==========
+
+Scrapy uses the `odd-numbered versions for development releases`_.
+
+There are 4 numbers in a Scrapy version: *A.B.C.D*
+
+* *A* is the major version. This will rarely change and will signify very
+ large changes. So far, only zero is available for *A*
+* *B* is the release number. This will include many changes including features
+ and things that possible break backwards compatibility. Even Bs will be
+ stable branches, and odd Bs will be development.
+* *C* is the bugfix release number, but it has been recently deprecated of
+ favor of using the revision number (*D*)
+* *D* is the revision number of the Mercurial repo from where the release was
+ taken
+
+For example:
+
+* *0.12.0.2542* is the stable release *12* at revision *2542* (safe to use in
+ production)
+* *0.13.0.2691* is the development release *13* at revision *2691* (use with
+ care in production)
+
+API Stability
+=============
+
+API stability is one of Scrapy major goals for the *1.0* release, which doesn't
+have a due date scheduled yet.
+
+Methods or functions that start with a single dash (``_``) are private and
+should never be relied as stable. Besides those, the plan is to stabilize and
+document the entire API, as we approach the 1.0 release.
+
+Also, keep in mind that stable doesn't mean complete: stable APIs could grow
+new methods or functionality but the existing methods should keep working the
+same way.
+
+
+.. _odd-numbered versions for development releases: http://en.wikipedia.org/wiki/Software_versioning#Odd-numbered_versions_for_development_releases
+
diff --git a/examples/experimental/googledir/googledir/__init__.py b/examples/experimental/googledir/googledir/__init__.py
deleted file mode 100644
index 3104ef709..000000000
--- a/examples/experimental/googledir/googledir/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-# googledir project
diff --git a/examples/experimental/googledir/googledir/items.py b/examples/experimental/googledir/googledir/items.py
deleted file mode 100644
index decc2c9ba..000000000
--- a/examples/experimental/googledir/googledir/items.py
+++ /dev/null
@@ -1,16 +0,0 @@
-# Define here the models for your scraped items
-#
-# See documentation in:
-# http://doc.scrapy.org/topics/items.html
-
-from scrapy.item import Item, Field
-
-class GoogledirItem(Item):
-
- name = Field(default='')
- url = Field(default='')
- description = Field(default='')
-
- def __str__(self):
- return "Google Category: name=%s url=%s" \
- % (self['name'], self['url'])
diff --git a/examples/experimental/googledir/googledir/pipelines.py b/examples/experimental/googledir/googledir/pipelines.py
deleted file mode 100644
index 51e4da0e1..000000000
--- a/examples/experimental/googledir/googledir/pipelines.py
+++ /dev/null
@@ -1,22 +0,0 @@
-# Define your item pipelines here
-#
-# Don't forget to add your pipeline to the ITEM_PIPELINES setting
-# See: http://doc.scrapy.org/topics/item-pipeline.html
-
-from scrapy.exceptions import DropItem
-
-class FilterWordsPipeline(object):
- """
- A pipeline for filtering out items which contain certain
- words in their description
- """
-
- # put all words in lowercase
- words_to_filter = ['politics', 'religion']
-
- def process_item(self, item, spider):
- for word in self.words_to_filter:
- if word in unicode(item['description']).lower():
- raise DropItem("Contains forbidden word: %s" % word)
- else:
- return item
diff --git a/examples/experimental/googledir/googledir/settings.py b/examples/experimental/googledir/googledir/settings.py
deleted file mode 100644
index 38f1df2a5..000000000
--- a/examples/experimental/googledir/googledir/settings.py
+++ /dev/null
@@ -1,16 +0,0 @@
-# Scrapy settings for googledir project
-#
-# For simplicity, this file contains only the most important settings by
-# default. All the other settings are documented here:
-#
-# http://doc.scrapy.org/topics/settings.html
-
-BOT_NAME = 'googledir'
-BOT_VERSION = '1.0'
-
-SPIDER_MODULES = ['googledir.spiders']
-NEWSPIDER_MODULE = 'googledir.spiders'
-DEFAULT_ITEM_CLASS = 'googledir.items.GoogledirItem'
-USER_AGENT = '%s/%s' % (BOT_NAME, BOT_VERSION)
-
-ITEM_PIPELINES = ['googledir.pipelines.FilterWordsPipeline']
diff --git a/examples/experimental/googledir/googledir/spiders/__init__.py b/examples/experimental/googledir/googledir/spiders/__init__.py
deleted file mode 100644
index c930799c0..000000000
--- a/examples/experimental/googledir/googledir/spiders/__init__.py
+++ /dev/null
@@ -1,8 +0,0 @@
-# This package will contain the spiders of your Scrapy project
-#
-# To create the first spider for your project use this command:
-#
-# scrapy genspider myspider myspider-domain.com
-#
-# For more info see:
-# http://doc.scrapy.org/topics/spiders.html
diff --git a/examples/experimental/googledir/googledir/spiders/google_directory.py b/examples/experimental/googledir/googledir/spiders/google_directory.py
deleted file mode 100644
index 53abcbd21..000000000
--- a/examples/experimental/googledir/googledir/spiders/google_directory.py
+++ /dev/null
@@ -1,38 +0,0 @@
-from scrapy.selector import HtmlXPathSelector
-from scrapy.contrib.loader import XPathItemLoader
-from scrapy.contrib_exp.crawlspider import CrawlSpider, Rule
-
-from googledir.items import GoogledirItem
-
-class GoogleDirectorySpider(CrawlSpider):
-
- name = 'google_directory'
- allowed_domains = ['directory.google.com']
- start_urls = ['http://directory.google.com/']
-
- rules = (
- # search for categories pattern and follow links
- Rule(r'/[A-Z][a-zA-Z_/]+$', 'parse_category', follow=True),
- )
-
- def parse_category(self, response):
- # The main selector we're using to extract data from the page
- main_selector = HtmlXPathSelector(response)
-
- # The XPath to website links in the directory page
- xpath = '//td[descendant::a[contains(@href, "#pagerank")]]/following-sibling::td/font'
-
- # Get a list of (sub) selectors to each website node pointed by the XPath
- sub_selectors = main_selector.select(xpath)
-
- # Iterate over the sub-selectors to extract data for each website
- for selector in sub_selectors:
- item = GoogledirItem()
-
- l = XPathItemLoader(item=item, selector=selector)
- l.add_xpath('name', 'a/text()')
- l.add_xpath('url', 'a/@href')
- l.add_xpath('description', 'font[2]/text()')
-
- # Here we populate the item and yield it
- yield l.load_item()
diff --git a/examples/experimental/googledir/scrapy.cfg b/examples/experimental/googledir/scrapy.cfg
deleted file mode 100644
index 164e66589..000000000
--- a/examples/experimental/googledir/scrapy.cfg
+++ /dev/null
@@ -1,2 +0,0 @@
-[settings]
-default = googledir.settings
diff --git a/examples/experimental/imdb/imdb/__init__.py b/examples/experimental/imdb/imdb/__init__.py
deleted file mode 100644
index 5bb534f79..000000000
--- a/examples/experimental/imdb/imdb/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-# package
diff --git a/examples/experimental/imdb/imdb/items.py b/examples/experimental/imdb/imdb/items.py
deleted file mode 100644
index 03bb5c2c3..000000000
--- a/examples/experimental/imdb/imdb/items.py
+++ /dev/null
@@ -1,12 +0,0 @@
-# Define here the models for your scraped items
-#
-# See documentation in:
-# http://doc.scrapy.org/topics/items.html
-
-from scrapy.item import Item, Field
-
-class ImdbItem(Item):
- # define the fields for your item here like:
- # name = Field()
- title = Field()
- url = Field()
diff --git a/examples/experimental/imdb/imdb/pipelines.py b/examples/experimental/imdb/imdb/pipelines.py
deleted file mode 100644
index 23740eba9..000000000
--- a/examples/experimental/imdb/imdb/pipelines.py
+++ /dev/null
@@ -1,8 +0,0 @@
-# Define your item pipelines here
-#
-# Don't forget to add your pipeline to the ITEM_PIPELINES setting
-# See: http://doc.scrapy.org/topics/item-pipeline.html
-
-class ImdbPipeline(object):
- def process_item(self, item, spider):
- return item
diff --git a/examples/experimental/imdb/imdb/settings.py b/examples/experimental/imdb/imdb/settings.py
deleted file mode 100644
index e0a8db52a..000000000
--- a/examples/experimental/imdb/imdb/settings.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# Scrapy settings for imdb project
-#
-# For simplicity, this file contains only the most important settings by
-# default. All the other settings are documented here:
-#
-# http://doc.scrapy.org/topics/settings.html
-
-BOT_NAME = 'imdb'
-BOT_VERSION = '1.0'
-
-SPIDER_MODULES = ['imdb.spiders']
-NEWSPIDER_MODULE = 'imdb.spiders'
-DEFAULT_ITEM_CLASS = 'imdb.items.ImdbItem'
-USER_AGENT = '%s/%s' % (BOT_NAME, BOT_VERSION)
-
diff --git a/examples/experimental/imdb/imdb/spiders/__init__.py b/examples/experimental/imdb/imdb/spiders/__init__.py
deleted file mode 100644
index c930799c0..000000000
--- a/examples/experimental/imdb/imdb/spiders/__init__.py
+++ /dev/null
@@ -1,8 +0,0 @@
-# This package will contain the spiders of your Scrapy project
-#
-# To create the first spider for your project use this command:
-#
-# scrapy genspider myspider myspider-domain.com
-#
-# For more info see:
-# http://doc.scrapy.org/topics/spiders.html
diff --git a/examples/experimental/imdb/imdb/spiders/imdb_site.py b/examples/experimental/imdb/imdb/spiders/imdb_site.py
deleted file mode 100644
index fed14ab07..000000000
--- a/examples/experimental/imdb/imdb/spiders/imdb_site.py
+++ /dev/null
@@ -1,139 +0,0 @@
-from scrapy.http import Request
-from scrapy.selector import HtmlXPathSelector
-from scrapy.contrib.loader import XPathItemLoader
-from scrapy.contrib_exp.crawlspider import CrawlSpider, Rule
-from scrapy.contrib_exp.crawlspider.reqext import SgmlRequestExtractor
-from scrapy.contrib_exp.crawlspider.reqproc import Canonicalize, \
- FilterDupes, FilterUrl
-from scrapy.utils.url import urljoin_rfc
-
-from imdb.items import ImdbItem, Field
-
-from itertools import chain, imap, izip
-
-class UsaOpeningWeekMovie(ImdbItem):
- pass
-
-class UsaTopWeekMovie(ImdbItem):
- pass
-
-class Top250Movie(ImdbItem):
- rank = Field()
- rating = Field()
- year = Field()
- votes = Field()
-
-class MovieItem(ImdbItem):
- release_date = Field()
- tagline = Field()
-
-
-class ImdbSiteSpider(CrawlSpider):
- name = 'imdb.com'
- allowed_domains = ['imdb.com']
- start_urls = ['http://www.imdb.com/']
-
- # extract requests using this classes from urls matching 'follow' flag
- request_extractors = [
- SgmlRequestExtractor(tags=['a'], attrs=['href']),
- ]
-
- # process requests using this classes from urls matching 'follow' flag
- request_processors = [
- Canonicalize(),
- FilterDupes(),
- FilterUrl(deny=r'/tt\d+/$'), # deny movie url as we will dispatch
- # manually the movie requests
- ]
-
- # include domain bit for demo purposes
- rules = (
- # these two rules expects requests from start url
- Rule(r'imdb.com/nowplaying/$', 'parse_now_playing'),
- Rule(r'imdb.com/chart/top$', 'parse_top_250'),
- # this rule will parse requests manually dispatched
- Rule(r'imdb.com/title/tt\d+/$', 'parse_movie_info'),
- )
-
- def parse_now_playing(self, response):
- """Scrapes USA openings this week and top 10 in week"""
- self.log("Parsing USA Top Week")
- hxs = HtmlXPathSelector(response)
-
- _urljoin = lambda url: self._urljoin(response, url)
-
- #
- # openings this week
- #
- openings = hxs.select('//table[@class="movies"]//a[@class="title"]')
- boxoffice = hxs.select('//table[@class="boxoffice movies"]//a[@class="title"]')
-
- opening_titles = openings.select('text()').extract()
- opening_urls = imap(_urljoin, openings.select('@href').extract())
-
- box_titles = boxoffice.select('text()').extract()
- box_urls = imap(_urljoin, boxoffice.select('@href').extract())
-
- # items
- opening_items = (UsaOpeningWeekMovie(title=title, url=url)
- for (title, url)
- in izip(opening_titles, opening_urls))
-
- box_items = (UsaTopWeekMovie(title=title, url=url)
- for (title, url)
- in izip(box_titles, box_urls))
-
- # movie requests
- requests = imap(self.make_requests_from_url,
- chain(opening_urls, box_urls))
-
- return chain(opening_items, box_items, requests)
-
- def parse_top_250(self, response):
- """Scrapes movies from top 250 list"""
- self.log("Parsing Top 250")
- hxs = HtmlXPathSelector(response)
-
- # scrap each row in the table
- rows = hxs.select('//div[@id="main"]/table/tr//a/ancestor::tr')
- for row in rows:
- fields = row.select('td//text()').extract()
- url, = row.select('td//a/@href').extract()
- url = self._urljoin(response, url)
-
- item = Top250Movie()
- item['title'] = fields[2]
- item['url'] = url
- item['rank'] = fields[0]
- item['rating'] = fields[1]
- item['year'] = fields[3]
- item['votes'] = fields[4]
-
- # scrapped top250 item
- yield item
- # fetch movie
- yield self.make_requests_from_url(url)
-
- def parse_movie_info(self, response):
- """Scrapes movie information"""
- self.log("Parsing Movie Info")
- hxs = HtmlXPathSelector(response)
- selector = hxs.select('//div[@class="maindetails"]')
-
- item = MovieItem()
- # set url
- item['url'] = response.url
-
- # use item loader for other attributes
- l = XPathItemLoader(item=item, selector=selector)
- l.add_xpath('title', './/h1/text()')
- l.add_xpath('release_date', './/h5[text()="Release Date:"]'
- '/following-sibling::div/text()')
- l.add_xpath('tagline', './/h5[text()="Tagline:"]'
- '/following-sibling::div/text()')
-
- yield l.load_item()
-
- def _urljoin(self, response, url):
- """Helper to convert relative urls to absolute"""
- return urljoin_rfc(response.url, url, response.encoding)
diff --git a/examples/experimental/imdb/scrapy.cfg b/examples/experimental/imdb/scrapy.cfg
deleted file mode 100644
index fa607228e..000000000
--- a/examples/experimental/imdb/scrapy.cfg
+++ /dev/null
@@ -1,2 +0,0 @@
-[settings]
-default = imdb.settings
diff --git a/examples/googledir/googledir/__init__.py b/examples/googledir/googledir/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/examples/googledir/googledir/items.py b/examples/googledir/googledir/items.py
deleted file mode 100644
index c5d11b2cd..000000000
--- a/examples/googledir/googledir/items.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from scrapy.item import Item, Field
-
-class GoogledirItem(Item):
-
- name = Field()
- url = Field()
- description = Field()
-
- def __str__(self):
- return "Google Category: name=%s url=%s" % (self['name'], self['url'])
diff --git a/examples/googledir/googledir/pipelines.py b/examples/googledir/googledir/pipelines.py
deleted file mode 100644
index b842bb5cf..000000000
--- a/examples/googledir/googledir/pipelines.py
+++ /dev/null
@@ -1,15 +0,0 @@
-from scrapy.exceptions import DropItem
-
-class FilterWordsPipeline(object):
- """A pipeline for filtering out items which contain certain words in their
- description"""
-
- # put all words in lowercase
- words_to_filter = ['politics', 'religion']
-
- def process_item(self, item, spider):
- for word in self.words_to_filter:
- if word in unicode(item['description']).lower():
- raise DropItem("Contains forbidden word: %s" % word)
- else:
- return item
diff --git a/examples/googledir/googledir/settings.py b/examples/googledir/googledir/settings.py
deleted file mode 100644
index 6c4d6ef8a..000000000
--- a/examples/googledir/googledir/settings.py
+++ /dev/null
@@ -1,14 +0,0 @@
-# - Scrapy settings for googledir project
-
-import googledir
-
-BOT_NAME = 'googledir'
-BOT_VERSION = '1.0'
-
-SPIDER_MODULES = ['googledir.spiders']
-NEWSPIDER_MODULE = 'googledir.spiders'
-DEFAULT_ITEM_CLASS = 'scrapy.item.Item'
-USER_AGENT = '%s/%s' % (BOT_NAME, BOT_VERSION)
-
-ITEM_PIPELINES = ['googledir.pipelines.FilterWordsPipeline']
-
diff --git a/examples/googledir/googledir/spiders/__init__.py b/examples/googledir/googledir/spiders/__init__.py
deleted file mode 100644
index 59d02a55f..000000000
--- a/examples/googledir/googledir/spiders/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-# Place here all your scrapy spiders
diff --git a/examples/googledir/googledir/spiders/google_directory.py b/examples/googledir/googledir/spiders/google_directory.py
deleted file mode 100644
index ceb370e3e..000000000
--- a/examples/googledir/googledir/spiders/google_directory.py
+++ /dev/null
@@ -1,40 +0,0 @@
-from scrapy.selector import HtmlXPathSelector
-from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor
-from scrapy.contrib.spiders import CrawlSpider, Rule
-from scrapy.contrib.loader import XPathItemLoader
-from googledir.items import GoogledirItem
-
-class GoogleDirectorySpider(CrawlSpider):
-
- name = 'directory.google.com'
- allowed_domains = ['directory.google.com']
- start_urls = ['http://directory.google.com/']
-
- rules = (
- Rule(SgmlLinkExtractor(allow='directory.google.com/[A-Z][a-zA-Z_/]+$'),
- 'parse_category',
- follow=True,
- ),
- )
-
- def parse_category(self, response):
- # The main selector we're using to extract data from the page
- main_selector = HtmlXPathSelector(response)
-
- # The XPath to website links in the directory page
- xpath = '//td[descendant::a[contains(@href, "#pagerank")]]/following-sibling::td/font'
-
- # Get a list of (sub) selectors to each website node pointed by the XPath
- sub_selectors = main_selector.select(xpath)
-
- # Iterate over the sub-selectors to extract data for each website
- for selector in sub_selectors:
- item = GoogledirItem()
-
- l = XPathItemLoader(item=item, selector=selector)
- l.add_xpath('name', 'a/text()')
- l.add_xpath('url', 'a/@href')
- l.add_xpath('description', 'font[2]/text()')
-
- # Here we populate the item and yield it
- yield l.load_item()
diff --git a/examples/googledir/scrapy.cfg b/examples/googledir/scrapy.cfg
deleted file mode 100644
index 164e66589..000000000
--- a/examples/googledir/scrapy.cfg
+++ /dev/null
@@ -1,2 +0,0 @@
-[settings]
-default = googledir.settings
diff --git a/extras/makedeb.py b/extras/makedeb.py
index 054204cf2..ca1b69470 100644
--- a/extras/makedeb.py
+++ b/extras/makedeb.py
@@ -16,7 +16,9 @@ def build(suffix):
with open(ifn, 'w') as of:
of.write(s)
- check_call('debchange -m -D unstable --force-distribution -v $(python setup.py --version)-r$(hg tip --template "{rev}")+$(date +%s) "Automatic build"', shell=True)
+ env={'SCRAPY_VERSION_FROM_HG': '1'}
+ check_call('debchange -m -D unstable --force-distribution -v $(python setup.py --version)+$(date +%s) "Automatic build"', \
+ shell=True, env=env)
check_call('debuild -us -uc -b', shell=True)
def clean(suffix):
diff --git a/extras/scrapy_bash_completion b/extras/scrapy_bash_completion
index b0654ee6a..17e162510 100644
--- a/extras/scrapy_bash_completion
+++ b/extras/scrapy_bash_completion
@@ -5,7 +5,7 @@ _scrapy_completion() {
cmd=${COMP_WORDS[1]}
cur=${COMP_WORDS[2]}
case "$cmd" in
- crawl)
+ crawl|edit)
spiders=$(scrapy list 2>/dev/null) || spiders=""
COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W "$spiders" -- "$cur"))
;;
diff --git a/profiling/priorityqueue/pq_classes.py b/profiling/priorityqueue/pq_classes.py
deleted file mode 100644
index ff2747822..000000000
--- a/profiling/priorityqueue/pq_classes.py
+++ /dev/null
@@ -1,370 +0,0 @@
-from collections import deque, defaultdict
-from heapq import heappush, heappop
-import time
-from itertools import chain
-
-#------------------------------------------------------------------------------
-
-class PriorityQueue1(object):
- """heapq
-
- A simple priority queue
- """
-
- def __init__(self, size=1):
- self.items = []
-
- def push(self, item, priority=0):
- heappush(self.items, (priority, time.time(), item))
-
- def pop(self):
- priority, _, item = heappop(self.items)
- return item, priority
-
- def __len__(self):
- return len(self.items)
-
- def __iter__(self):
- return ((item, priority) for priority, _, item in self.items)
-
- def __nonzero__(self):
- return bool(self.items)
-
-
-class PriorityQueue1b(PriorityQueue1):
- """heapq+int
-
- A simple priority queue using incremental integer instead of time.time()
- """
- time = 0
-
- def push(self, item, priority=0):
- self.time += 1
- heappush(self.items, (priority, time, item))
-
-#------------------------------------------------------------------------------
-
-class PriorityQueue2(object):
- """dict+deque
-
- @author: Federico Feroldi
- """
- def __init__(self, size=1):
- self.items = defaultdict(deque)
-
- def push(self, item, priority=0):
- self.items[priority].appendleft(item)
-
- def pop(self):
- priorities = self.items.keys()
- priorities.sort()
-
- for priority in priorities:
- if len(self.items[priority]) > 0:
- return (self.items[priority].pop(), priority)
-
- raise IndexError
-
- def __len__(self):
- totlen = 0
- for q in self.items.values():
- totlen += len(q)
- return totlen
-
- def __iter__(self):
- priorities = self.items.keys()
- priorities.sort()
-
- for priority in priorities:
- for i in self.items[priority]:
- yield (i, priority)
-
- def __nonzero__(self):
- for q in self.items.values():
- if len(q) > 0:
- return True
- return False
-
-#------------------------------------------------------------------------------
-
-class PriorityQueue3(object):
- """deque+heapq"""
-
- def __init__(self, size=1):
- self.negitems = []
- self.pzero = deque()
- self.positems = []
-
- def push(self, item, priority=0):
- if priority == 0:
- self.pzero.appendleft(item)
- elif priority < 0:
- heappush(self.negitems, (priority, time.time(), item))
- else:
- heappush(self.positems, (priority, time.time(), item))
-
- def pop(self):
- if self.negitems:
- priority, _, item = heappop(self.negitems)
- return item, priority
- elif self.pzero:
- return (self.pzero.pop(), 0)
- else:
- priority, _, item = heappop(self.positems)
- return item, priority
-
- def __len__(self):
- return len(self.negitems) + len(self.pzero) + len(self.positems)
-
- def __iter__(self):
- for priority, _, item in self.negitems:
- yield (item, priority)
- for item in self.pzero:
- yield (item, 0)
- for priority, _, item in self.positems:
- yield (item, priority)
-
- def __nonzero__(self):
- return bool(self.negitems and self.pzero and self.positems)
-
-
-class PriorityQueue3b(PriorityQueue3):
- """deque+heapq+int"""
-
- left_time = 0
- right_time = 0
-
- def push(self, item, priority=0):
- if priority == 0:
- self.pzero.appendleft(item)
- elif priority < 0:
- self.left_time += 1
- heappush(self.negitems, (priority, self.left_time, item))
- else:
- self.right_time += 1
- heappush(self.positems, (priority, self.right_time, item))
-
-
-#------------------------------------------------------------------------------
-
-class PriorityQueue4(object):
- """deque+defaultdict+deque"""
-
- def __init__(self, size=1):
- self.negitems = defaultdict(deque)
- self.pzero = deque()
- self.positems = defaultdict(deque)
-
- def push(self, item, priority=0):
- if priority == 0:
- self.pzero.appendleft(item)
- elif priority < 0:
- self.negitems[priority].appendleft(item)
- else:
- self.positems[priority].appendleft(item)
-
- def pop(self):
- if self.negitems:
- priorities = self.negitems.keys()
- priorities.sort()
- for priority in priorities:
- deq = self.negitems[priority]
- if deq:
- t = (deq.pop(), priority)
- if not deq:
- del self.negitems[priority]
- return t
- elif self.pzero:
- return (self.pzero.pop(), 0)
- else:
- priorities = self.positems.keys()
- priorities.sort()
- for priority in priorities:
- deq = self.positems[priority]
- if deq:
- t = (deq.pop(), priority)
- if not deq:
- del self.positems[priority]
- return t
- raise IndexError("pop from an empty queue")
-
- def __len__(self):
- total = sum(len(v) for v in self.negitems.values()) + \
- len(self.pzero) + \
- sum(len(v) for v in self.positems.values())
- return total
-
- def __iter__(self):
- gen_negs = ((i, priority)
- for priority in sorted(self.negitems.keys())
- for i in reversed(self.negitems[priority]))
- gen_zeros = ((item,0) for item in self.pzero)
- gen_pos = ((i, priority)
- for priority in sorted(self.positems.keys())
- for i in reversed(self.positems[priority]))
- return chain(gen_negs, gen_zeros, gen_pos)
-
-
- def __nonzero__(self):
- return bool(self.negitems or self.pzero or self.positems)
-
-class PriorityQueue4b(object):
- """deque+defaultdict+deque+cache"""
-
- def __init__(self, size=1):
- self.negitems = defaultdict(deque)
- self.pzero = deque()
- self.positems = defaultdict(deque)
- self._sort_neg = False
- self._sort_pos = False
- self._cached_sorted_negitems = []
- self._cached_sorted_positems = []
-
- def push(self, item, priority=0):
- if priority == 0:
- self.pzero.appendleft(item)
- elif priority < 0:
- if priority not in self.negitems:
- self._sort_neg = True
- self.negitems[priority].appendleft(item)
- else:
- if priority not in self.positems:
- self._sort_pos = True
- self.positems[priority].appendleft(item)
-
- def pop(self):
- if self.negitems:
- if self._sort_neg:
- priorities = self.negitems.keys()
- priorities.sort()
- self._cached_sorted_negitems = priorities
- self._sort_neg = False
- else:
- priorities = self._cached_sorted_negitems
-
- for priority in priorities:
- deq = self.negitems[priority]
- if deq:
- t = (deq.pop(), priority)
- if not deq:
- self._sort_neg = True
- del self.negitems[priority]
- return t
- elif self.pzero:
- return (self.pzero.pop(), 0)
- else:
- if self._sort_pos:
- priorities = self.positems.keys()
- priorities.sort()
- self._cached_sorted_positems = priorities
- self._sort_pos = False
- else:
- priorities = self._cached_sorted_positems
-
- priorities = self.positems.keys()
- priorities.sort()
- for priority in priorities:
- deq = self.positems[priority]
- if deq:
- t = (deq.pop(), priority)
- if not deq:
- self._sort_pos = True
- del self.positems[priority]
- return t
- raise IndexError("pop from an empty queue")
-
- def __len__(self):
- total = sum(len(v) for v in self.negitems.values()) + \
- len(self.pzero) + \
- sum(len(v) for v in self.positems.values())
- return total
-
- def __iter__(self):
- gen_negs = ((i, priority)
- for priority in sorted(self.negitems.keys())
- for i in reversed(self.negitems[priority]))
- gen_zeros = ((item,0) for item in self.pzero)
- gen_pos = ((i, priority)
- for priority in sorted(self.positems.keys())
- for i in reversed(self.positems[priority]))
- return chain(gen_negs, gen_zeros, gen_pos)
-
-
- def __nonzero__(self):
- return bool(self.negitems or self.pzero or self.positems)
-
-#------------------------------------------------------------------------------
-
-class PriorityQueue5(object):
- """list+deque"""
-
- def __init__(self, size=1):
- # preallocate deques for a fixed number of priorities
- size = size if size % 2 else size + 1
- self.zero = size // 2
- self.priolist = [deque() for _ in range(size)]
-
- def push(self, item, priority=0):
- self.priolist[priority + self.zero].appendleft(item)
-
- def pop(self):
- for prio, queue in enumerate(self.priolist):
- if len(queue):
- final = prio - self.zero
- return (queue.pop(), final)
-
- raise IndexError("pop from an empty queue")
-
- def __len__(self):
- return sum(len(v) for v in self.priolist)
-
- def __iter__(self):
- for prio, queue in enumerate(self.priolist):
- final = prio - self.zero
- for i in reversed(queue):
- yield (i, final)
-
- def __nonzero__(self):
- return any(d for d in self.priolist)
-
-class PriorityQueue5b(PriorityQueue5):
- """list+deque+cache"""
- index = 0
-
- def push(self, item, priority=0):
- i = priority + self.zero
- self.priolist[i].appendleft(item)
- self.index = min(self.index, i)
-
- def pop(self):
- cached = self.priolist[self.index]
- if cached:
- return (cached.pop(), self.index - self.zero)
-
- for prio, queue in enumerate(self.priolist[self.index:]):
- if queue:
- self.index += prio
- return (queue.pop(), self.index - self.zero)
-
- raise IndexError("pop from an empty queue")
-
-
-from itertools import islice
-class PriorityQueue5c(PriorityQueue5b):
- """list+deque+cache+islice"""
-
- def pop(self):
- cached = self.priolist[self.index]
- if cached:
- return (cached.pop(), self.index - self.zero)
-
- for prio, queue in enumerate(islice(self.priolist, self.index, None), self.index):
- if queue:
- self.index = prio
- return (queue.pop(), prio - self.zero)
-
- raise IndexError("pop from an empty queue")
-
-#------------------------------------------------------------------------------
-
-__all__ = [name for name in globals().keys() if name.startswith('PriorityQueue')]
diff --git a/profiling/priorityqueue/run.py b/profiling/priorityqueue/run.py
deleted file mode 100644
index 2cc5f9ed2..000000000
--- a/profiling/priorityqueue/run.py
+++ /dev/null
@@ -1,157 +0,0 @@
-from __future__ import with_statement
-import os
-import timeit
-import random
-from optparse import OptionParser
-from tempfile import mktemp
-from pq_classes import *
-
-TESTID = os.getpid()
-
-TESTCASES = (
- ("heapq", PriorityQueue1),
- #("heapq+int", PriorityQueue1b),
- ("dict+deque", PriorityQueue2),
- ("deque+heapq", PriorityQueue3),
- #("deque+heapq+int", PriorityQueue3b),
- ("deque+defaultdict+deque", PriorityQueue4),
- ("deque+defaultdict+deque+cache", PriorityQueue4b),
- #('list+deque', PriorityQueue5),
- ('list+deque+cache', PriorityQueue5b),
- #('list+deque+cache+islice', PriorityQueue5c),
- )
-
-
-stmt_fmt = """
-for n, prio in enumerate(randomprio):
- q.push(n, prio)
-
-try:
- while True:
- q.pop()
-except IndexError:
- pass
-"""
-
-setup_fmt = """
-from collections import deque
-from __main__ import %(PriorityClass)s as PriorityQueue
-q = PriorityQueue(%(priorities)i)
-
-randomprio = deque()
-for line in open('%(samplefile)s'):
- prio = int(line.strip())
- randomprio.append(prio)
-"""
-
-
-def _distribution(priorities, distribution):
- half = priorities // 2
- prio = -priorities
- while not (-half <= prio <= half):
- prio = round(distribution())
- return min(max(prio, -half), half)
-
-def normal_priority(priorities):
- sigma = priorities / 4.0
- dist = lambda: random.normalvariate(mu=0, sigma=sigma)
- return _distribution(priorities, dist)
-
-def gauss_priority(priorities):
- sigma = priorities / 4.0
- dist = lambda: random.gauss(mu=0, sigma=sigma)
- return _distribution(priorities, dist)
-
-def triangular_priority(priorities):
- half = priorities // 2
- return random.triangular(-half-1, half+1, 0)
-
-def uniform_priority(priorities):
- return int(random.random() * priorities) - (priorities / 2)
-
-
-PRIORITY_DISTRIBUTIONS = {
- 'uniform': uniform_priority,
- 'normal': normal_priority,
- 'gauss': gauss_priority,
- 'triangular': triangular_priority,
- }
-
-
-def gen_samples(count, priorities, priority_distribution=uniform_priority):
- fn = '/tmp/pq-%i-%i-%i' % (TESTID, priorities, count)
-
- with open(fn, 'w') as samplefile:
- for n in xrange(count):
- prio = priority_distribution(priorities)
- samplefile.write('%i\n' % prio)
- return fn
-
-def runtests(pushpops=50*1000, times=30, priorities=1, samplefile=None, priority_distribution=uniform_priority):
- samplefile = samplefile or gen_samples(pushpops, priorities, priority_distribution)
-
- print "\n== With %s priorities (%s) ==\n" % (priorities, samplefile)
- print "pushpops = %s, times = %s" % (pushpops, times)
-
-
- stmt = stmt_fmt
- for name, cls in TESTCASES:
- setup = setup_fmt % {
- 'PriorityClass': cls.__name__,
- 'priorities': priorities,
- 'samplefile': samplefile,
- }
- t = timeit.Timer(stmt, setup)
- print "%s implementation: %s" % (name, t.timeit(number=times))
-
-
-if __name__ == '__main__':
- o = OptionParser()
- o.add_option('-n', '--samples-count', type='int', default=50000, metavar='NUMBER',
- help='The max number or samples to generate')
- o.add_option('-r', '--retry-times', type='int', default=30, metavar='NUMBER',
- help='the times to retry each test')
- o.add_option('-s', '--samplefile', default=None, metavar='FILENAME',
- help='load samples from file, default: use sample generator')
- o.add_option('-p', '--priorities', default='1,3,5,10,100', metavar='CSV_PRIOLIST',
- help='a comma separated list of priorities to test')
- o.add_option('-d', '--priority-distribution', default='uniform', metavar='DISTRIBUTION',
- help='distribution used for random priority generator, default: uniform. possibles: %s' \
- % ','.join(PRIORITY_DISTRIBUTIONS.keys()))
-
- opt, args = o.parse_args()
-
- priolist = map(int, opt.priorities.split(','))
- distribution = PRIORITY_DISTRIBUTIONS[opt.priority_distribution]
- for prio in priolist:
- runtests(pushpops=opt.samples_count, priorities=prio, times=opt.retry_times,
- samplefile=opt.samplefile, priority_distribution=distribution)
-
-# Results (in seconds, on an intel core2 2.16ghz):
-# == Without priorities ==
-
-# pushpops = 50000, times = 30
-# heapq implementation: 7.7959010601
-# dict+deque implementation: 5.6420109272
-# deque+heapq implementation: 3.57563900948
-
-# == With 5 priorities ==
-
-# pushpops = 50000, times = 30
-# heapq implementation: 9.83902192116
-# dict+deque implementation: 9.21094298363
-# deque+heapq implementation: 9.05321097374
-
-# == With 10 priorities ==
-
-# pushpops = 50000, times = 30
-# heapq implementation: 9.97831392288
-# dict+deque implementation: 11.9721341133
-# deque+heapq implementation: 9.79048800468
-
-# == With 100 priorities ==
-
-# pushpops = 50000, times = 30
-# heapq implementation: 10.4782910347
-# dict+deque implementation: 64.6989660263
-# deque+heapq implementation: 10.858932972
diff --git a/profiling/priorityqueue/test_cases.py b/profiling/priorityqueue/test_cases.py
deleted file mode 100644
index 4b87f3e0c..000000000
--- a/profiling/priorityqueue/test_cases.py
+++ /dev/null
@@ -1,71 +0,0 @@
-import sys
-import unittest
-from pq_classes import *
-
-# (ITEM, PRIORITY)
-INPUT = [(1, -5), (30, -1), (80, -3), (4, 1), (6, 3), (20, 0), (50, -1)]
-OUTPUT = [(1, -5), (80, -3), (30, -1), (50, -1), (20, 0), (4, 1), (6, 3)]
-
-PRIOSIZE = reduce(max, (abs(i[1]) for i in INPUT + OUTPUT)) * 2
-
-class TestPriorityQueue(object):
-
- def test_popping(self):
- pq = self.PriorityQueue(PRIOSIZE)
- for item, pr in INPUT:
- pq.push(item, pr)
- l = []
- while pq:
- l.append(pq.pop())
- self.assertEquals(l, OUTPUT)
-
- def test_iter(self):
- pq = self.PriorityQueue(PRIOSIZE)
- for item, pr in INPUT:
- pq.push(item, pr)
- result = [x for x in pq]
- self.assertEquals(result, OUTPUT)
-
- def test_nonzero(self):
- pq = self.PriorityQueue(PRIOSIZE)
- pq.push(80, -1)
- pq.push(20, 0)
- pq.push(30, 1)
-
- pq.pop()
- self.assertEquals(bool(pq), True)
- pq.pop()
- self.assertEquals(bool(pq), True)
- pq.pop()
- self.assertEquals(bool(pq), False)
-
- def test_len(self):
- pq = self.PriorityQueue(PRIOSIZE)
- pq.push(80, -1)
- pq.push(20, 0)
- pq.push(30, 1)
-
- self.assertEquals(len(pq), 3)
- pq.pop()
- self.assertEquals(len(pq), 2)
- pq.pop()
- self.assertEquals(len(pq), 1)
- pq.pop()
- self.assertEquals(len(pq), 0)
-
- def test_indexerror(self):
- pq = self.PriorityQueue(PRIOSIZE)
- self.assertRaises(IndexError, pq.pop)
-
-
-# automatically test any PriorityQueueN class defined at pq_classes
-prioclasses = [(name, cls) for name, cls in globals().items() if name.startswith('PriorityQueue')]
-for name, cls in prioclasses:
- testname = '%sTestCase' % name
- testcase = type(testname, (TestPriorityQueue, unittest.TestCase), {'PriorityQueue': cls})
- setattr(sys.modules[__name__], testname, testcase)
-
-
-if __name__ == '__main__':
- print "\n== Unit testing for every implementation =="
- unittest.main()
diff --git a/scrapy/__init__.py b/scrapy/__init__.py
index 3d8a7a4ae..c73dae498 100644
--- a/scrapy/__init__.py
+++ b/scrapy/__init__.py
@@ -2,8 +2,8 @@
Scrapy - a screen scraping framework written in Python
"""
-version_info = (0, 12, 0)
-__version__ = "0.12.0"
+version_info = (0, 13, 0)
+__version__ = "0.13.0"
import sys, os, warnings
diff --git a/scrapy/cmdline.py b/scrapy/cmdline.py
index e381bf537..4ff61fd86 100644
--- a/scrapy/cmdline.py
+++ b/scrapy/cmdline.py
@@ -11,7 +11,7 @@ from scrapy.crawler import CrawlerProcess
from scrapy.xlib import lsprofcalltree
from scrapy.conf import settings
from scrapy.command import ScrapyCommand
-from scrapy.exceptions import UsageError
+from scrapy.exceptions import UsageError, ScrapyDeprecationWarning
from scrapy.utils.misc import walk_modules
from scrapy.utils.project import inside_project
@@ -82,7 +82,7 @@ def _check_deprecated_scrapy_ctl(argv, inproject):
return
import warnings
warnings.warn("`scrapy-ctl.py` command-line tool is deprecated and will be removed in Scrapy 0.11, use `scrapy` instead",
- DeprecationWarning, stacklevel=3)
+ ScrapyDeprecationWarning, stacklevel=3)
if inproject:
projpath = os.path.abspath(os.path.dirname(os.path.dirname(settings.settings_module.__file__)))
cfg_path = os.path.join(projpath, 'scrapy.cfg')
diff --git a/scrapy/commands/crawl.py b/scrapy/commands/crawl.py
index d27ba7f9b..f97f907ee 100644
--- a/scrapy/commands/crawl.py
+++ b/scrapy/commands/crawl.py
@@ -1,33 +1,21 @@
-import sys
-
-from scrapy import log
from scrapy.command import ScrapyCommand
-from scrapy.conf import settings
-from scrapy.http import Request
-from scrapy.utils.url import is_url
from scrapy.utils.conf import arglist_to_dict
from scrapy.exceptions import UsageError
-from collections import defaultdict
-
class Command(ScrapyCommand):
requires_project = True
def syntax(self):
- return "[options] ..."
+ return "[options] "
def short_desc(self):
return "Start crawling from a spider or URL"
def add_options(self, parser):
ScrapyCommand.add_options(self, parser)
- parser.add_option("--spider", dest="spider", default=None, \
- help="always use this spider when arguments are urls")
parser.add_option("-a", dest="spargs", action="append", default=[], metavar="NAME=VALUE", \
help="set spider argument (may be repeated)")
- parser.add_option("-n", "--nofollow", dest="nofollow", action="store_true", \
- help="don't follow links (for use with URLs only)")
def process_options(self, args, opts):
ScrapyCommand.process_options(self, args, opts)
@@ -35,49 +23,13 @@ class Command(ScrapyCommand):
opts.spargs = arglist_to_dict(opts.spargs)
except ValueError:
raise UsageError("Invalid -a value, use -a NAME=VALUE", print_help=False)
- if opts.nofollow:
- settings.overrides['CRAWLSPIDER_FOLLOW_LINKS'] = False
def run(self, args, opts):
- q = self.crawler.queue
- urls, names = self._split_urls_and_names(args)
- for name in names:
- q.append_spider_name(name, **opts.spargs)
-
- if opts.spider:
- try:
- spider = self.crawler.spiders.create(opts.spider, **opts.spargs)
- for url in urls:
- q.append_url(url, spider)
- except KeyError:
- log.msg('Unable to find spider: %s' % opts.spider, log.ERROR)
- else:
- for name, urls in self._group_urls_by_spider(urls):
- spider = self.crawler.spiders.create(name, **opts.spargs)
- for url in urls:
- q.append_url(url, spider)
+ if len(args) < 1:
+ raise UsageError()
+ elif len(args) > 1:
+ raise UsageError("running 'scrapy crawl' with more than one spider is no longer supported")
+ for spname in args:
+ spider = self.crawler.spiders.create(spname, **opts.spargs)
+ self.crawler.crawl(spider)
self.crawler.start()
-
- def _group_urls_by_spider(self, urls):
- spider_urls = defaultdict(list)
- for url in urls:
- spider_names = self.crawler.spiders.find_by_request(Request(url))
- if not spider_names:
- log.msg('Could not find spider that handles url: %s' % url,
- log.ERROR)
- elif len(spider_names) > 1:
- log.msg('More than one spider can handle url: %s - %s' % \
- (url, ", ".join(spider_names)), log.ERROR)
- else:
- spider_urls[spider_names[0]].append(url)
- return spider_urls.items()
-
- def _split_urls_and_names(self, args):
- urls = []
- names = []
- for arg in args:
- if is_url(arg):
- urls.append(arg)
- else:
- names.append(arg)
- return urls, names
diff --git a/scrapy/commands/deploy.py b/scrapy/commands/deploy.py
index 0dcf5037f..46c67902f 100644
--- a/scrapy/commands/deploy.py
+++ b/scrapy/commands/deploy.py
@@ -11,10 +11,11 @@ import netrc
from urlparse import urlparse, urljoin
from subprocess import Popen, PIPE, check_call
+from w3lib.form import encode_multipart
+
from scrapy.command import ScrapyCommand
from scrapy.exceptions import UsageError
from scrapy.utils.py26 import json
-from scrapy.utils.multipart import encode_multipart
from scrapy.utils.http import basic_auth_header
from scrapy.utils.conf import get_config, closest_scrapy_cfg
@@ -57,6 +58,8 @@ class Command(ScrapyCommand):
help="list available projects on TARGET")
parser.add_option("--egg", metavar="FILE",
help="use the given egg, instead of building it")
+ parser.add_option("--build-egg", metavar="FILE",
+ help="only build the egg, don't deploy it")
def run(self, args, opts):
try:
@@ -75,18 +78,26 @@ class Command(ScrapyCommand):
projects = json.loads(f.read())['projects']
print os.linesep.join(projects)
return
- target_name = _get_target_name(args)
- target = _get_target(target_name)
- project = _get_project(target, opts)
- version = _get_version(target, opts)
+
tmpdir = None
- if opts.egg:
- _log("Using egg: %s" % opts.egg)
- egg = opts.egg
- else:
- _log("Building egg of %s-%s" % (project, version))
+
+ if opts.build_egg: # build egg only
egg, tmpdir = _build_egg()
- _upload_egg(target, egg, project, version)
+ _log("Writing egg to %s" % opts.build_egg)
+ shutil.copyfile(egg, opts.build_egg)
+ else: # buld egg and deploy
+ target_name = _get_target_name(args)
+ target = _get_target(target_name)
+ project = _get_project(target, opts)
+ version = _get_version(target, opts)
+ if opts.egg:
+ _log("Using egg: %s" % opts.egg)
+ egg = opts.egg
+ else:
+ _log("Building egg of %s-%s" % (project, version))
+ egg, tmpdir = _build_egg()
+ _upload_egg(target, egg, project, version)
+
if tmpdir:
shutil.rmtree(tmpdir)
diff --git a/scrapy/commands/edit.py b/scrapy/commands/edit.py
new file mode 100644
index 000000000..90f5e6d4c
--- /dev/null
+++ b/scrapy/commands/edit.py
@@ -0,0 +1,35 @@
+import sys, os
+
+from scrapy.command import ScrapyCommand
+from scrapy.exceptions import UsageError
+
+class Command(ScrapyCommand):
+
+ requires_project = True
+ default_settings = {'LOG_ENABLED': False}
+
+ def syntax(self):
+ return ""
+
+ def short_desc(self):
+ return "Edit spider"
+
+ def long_desc(self):
+ return "Edit a spider using the editor defined in EDITOR setting"
+
+ def _err(self, msg):
+ sys.stderr.write(msg + os.linesep)
+ self.exitcode = 1
+
+ def run(self, args, opts):
+ if len(args) != 1:
+ raise UsageError()
+ editor = self.crawler.settings['EDITOR']
+ try:
+ spider = self.crawler.spiders.create(args[0])
+ except KeyError:
+ return self._err("Spider not found: %s" % args[0])
+
+ sfile = sys.modules[spider.__module__].__file__
+ sfile = sfile.replace('.pyc', '.py')
+ self.exitcode = os.system('%s "%s"' % (editor, sfile))
diff --git a/scrapy/commands/fetch.py b/scrapy/commands/fetch.py
index 4d1abe14e..cc4d00f94 100644
--- a/scrapy/commands/fetch.py
+++ b/scrapy/commands/fetch.py
@@ -1,11 +1,10 @@
-import pprint
+from w3lib.url import is_url
-from scrapy import log
from scrapy.command import ScrapyCommand
from scrapy.http import Request
from scrapy.spider import BaseSpider
-from scrapy.utils.url import is_url
from scrapy.exceptions import UsageError
+from scrapy.utils.spider import create_spider_for_request
class Command(ScrapyCommand):
@@ -28,9 +27,16 @@ class Command(ScrapyCommand):
parser.add_option("--headers", dest="headers", action="store_true", \
help="print response HTTP headers instead of body")
+ def _print_headers(self, headers, prefix):
+ for key, values in headers.items():
+ for value in values:
+ print '%s %s: %s' % (prefix, key, value)
+
def _print_response(self, response, opts):
if opts.headers:
- pprint.pprint(response.headers)
+ self._print_headers(response.request.headers, '>')
+ print '>'
+ self._print_headers(response.headers, '<')
else:
print response.body
@@ -39,15 +45,14 @@ class Command(ScrapyCommand):
raise UsageError()
cb = lambda x: self._print_response(x, opts)
request = Request(args[0], callback=cb, dont_filter=True)
+ request.meta['handle_httpstatus_all'] = True
spider = None
if opts.spider:
- try:
- spider = self.crawler.spiders.create(opts.spider)
- except KeyError:
- log.msg("Could not find spider: %s" % opts.spider, log.ERROR)
-
- self.crawler.queue.append_request(request, spider, \
- default_spider=BaseSpider('default'))
+ spider = self.crawler.spiders.create(opts.spider)
+ else:
+ spider = create_spider_for_request(self.crawler.spiders, request, \
+ default_spider=BaseSpider('default'))
+ self.crawler.crawl(spider, [request])
self.crawler.start()
diff --git a/scrapy/commands/genspider.py b/scrapy/commands/genspider.py
index e3f869f4c..710ac19a7 100644
--- a/scrapy/commands/genspider.py
+++ b/scrapy/commands/genspider.py
@@ -1,6 +1,6 @@
+import os
import shutil
import string
-from os import listdir
from os.path import join, dirname, abspath, exists, splitext
import scrapy
@@ -38,6 +38,8 @@ class Command(ScrapyCommand):
ScrapyCommand.add_options(self, parser)
parser.add_option("-l", "--list", dest="list", action="store_true",
help="List available templates")
+ parser.add_option("-e", "--edit", dest="edit", action="store_true",
+ help="Edit spider after creating it")
parser.add_option("-d", "--dump", dest="dump", metavar="TEMPLATE",
help="Dump template to standard output")
parser.add_option("-t", "--template", dest="template", default="crawl",
@@ -72,6 +74,8 @@ class Command(ScrapyCommand):
template_file = self._find_template(opts.template)
if template_file:
self._genspider(module, name, domain, opts.template, template_file)
+ if opts.edit:
+ self.exitcode = os.system('scrapy edit "%s"' % name)
def _genspider(self, module, name, domain, template_name, template_file):
"""Generate the spider module, based on the given template"""
@@ -102,7 +106,7 @@ class Command(ScrapyCommand):
def _list_templates(self):
print "Available templates:"
- for filename in sorted(listdir(self.templates_dir)):
+ for filename in sorted(os.listdir(self.templates_dir)):
if filename.endswith('.tmpl'):
print " %s" % splitext(filename)[0]
diff --git a/scrapy/commands/list.py b/scrapy/commands/list.py
index 319265658..beb4d2ab0 100644
--- a/scrapy/commands/list.py
+++ b/scrapy/commands/list.py
@@ -1,5 +1,3 @@
-import os
-
from scrapy.command import ScrapyCommand
from scrapy.utils.misc import load_object
from scrapy.conf import settings
@@ -15,4 +13,5 @@ class Command(ScrapyCommand):
def run(self, args, opts):
spman_cls = load_object(settings['SPIDER_MANAGER_CLASS'])
spiders = spman_cls.from_settings(settings)
- print os.linesep.join(spiders.list())
+ for s in spiders.list():
+ print s
diff --git a/scrapy/commands/parse.py b/scrapy/commands/parse.py
index a39f12afa..3dbda5fe3 100644
--- a/scrapy/commands/parse.py
+++ b/scrapy/commands/parse.py
@@ -1,9 +1,9 @@
+from w3lib.url import is_url
from scrapy.command import ScrapyCommand
from scrapy.http import Request
from scrapy.item import BaseItem
from scrapy.utils import display
from scrapy.utils.spider import iterate_spider_output, create_spider_for_request
-from scrapy.utils.url import is_url
from scrapy.exceptions import UsageError
from scrapy import log
@@ -84,7 +84,7 @@ class Command(ScrapyCommand):
spider = self.get_spider(request, opts)
if not spider:
return None, None
- self.crawler.queue.append_request(request, spider)
+ self.crawler.crawl(spider, [request])
self.crawler.start()
if not responses:
log.msg('No response downloaded for: %s' % request, log.ERROR, \
diff --git a/scrapy/commands/queue.py b/scrapy/commands/queue.py
deleted file mode 100644
index 63cf3b5c8..000000000
--- a/scrapy/commands/queue.py
+++ /dev/null
@@ -1,68 +0,0 @@
-from twisted.internet import reactor, threads
-
-from scrapy.command import ScrapyCommand
-from scrapy.commands import runserver
-from scrapy.exceptions import UsageError
-from scrapy.utils.conf import arglist_to_dict
-
-class Command(runserver.Command):
-
- requires_project = True
- default_settings = {'LOG_LEVEL': 'WARNING'}
-
- def syntax(self):
- return "[options] "
-
- def short_desc(self):
- return "Deprecated command. See Scrapyd documentation."
-
- def add_options(self, parser):
- ScrapyCommand.add_options(self, parser)
- parser.add_option("-a", "--arg", dest="spargs", action="append", default=[], \
- help="set spider argument (may be repeated)")
-
- def process_options(self, args, opts):
- ScrapyCommand.process_options(self, args, opts)
- try:
- opts.spargs = arglist_to_dict(opts.spargs)
- except ValueError:
- raise UsageError("Invalid -a value, use -a NAME=VALUE", print_help=False)
-
- def run(self, args, opts):
- if len(args) < 1:
- raise UsageError()
- cmd = args[0]
-
- import warnings
- warnings.warn("Scrapy queue command is deprecated - use Scrapyd instead.", \
- DeprecationWarning)
-
- q = self.crawler.queue._queue
-
- if cmd == 'add' and len(args) < 2:
- raise UsageError()
-
- d = threads.deferToThread(self._run_in_thread, args, opts, q, cmd)
- d.addBoth(lambda _: reactor.stop())
- from scrapy import log
- log.start()
- reactor.run()
-
- def _run_in_thread(self, args, opts, q, cmd):
- if cmd == 'add':
- for x in args[1:]:
- self._call(q.add, x, **opts.spargs)
- print "Added: name=%s args=%s" % (x, opts.spargs)
- elif cmd == 'list':
- x = self._call(q.list)
- print "\n".join(map(str, x))
- elif cmd == 'count':
- print self._call(q.count)
- elif cmd == 'clear':
- self._call(q.clear)
- else:
- raise UsageError()
-
- def _call(self, f, *a, **kw):
- return threads.blockingCallFromThread(reactor, f, *a, **kw)
-
diff --git a/scrapy/commands/runserver.py b/scrapy/commands/runserver.py
deleted file mode 100644
index 9d7fd0615..000000000
--- a/scrapy/commands/runserver.py
+++ /dev/null
@@ -1,16 +0,0 @@
-from scrapy.command import ScrapyCommand
-from scrapy.conf import settings
-
-class Command(ScrapyCommand):
-
- requires_project = True
- default_settings = {'KEEP_ALIVE': True}
-
- def short_desc(self):
- return "Deprecated command. Use 'server' command instead"
-
- def run(self, args, opts):
- import warnings
- warnings.warn("Scrapy queue command is deprecated - use 'server' command instead.", \
- DeprecationWarning)
- self.crawler.start()
diff --git a/scrapy/commands/runspider.py b/scrapy/commands/runspider.py
index e9804e061..183855029 100644
--- a/scrapy/commands/runspider.py
+++ b/scrapy/commands/runspider.py
@@ -4,6 +4,7 @@ import os
from scrapy.utils.spider import iter_spider_classes
from scrapy.command import ScrapyCommand
from scrapy.exceptions import UsageError
+from scrapy.utils.conf import arglist_to_dict
def _import_file(filepath):
abspath = os.path.abspath(filepath)
@@ -33,8 +34,17 @@ class Command(ScrapyCommand):
def long_desc(self):
return "Run the spider defined in the given file"
+ def add_options(self, parser):
+ ScrapyCommand.add_options(self, parser)
+ parser.add_option("-a", dest="spargs", action="append", default=[], metavar="NAME=VALUE", \
+ help="set spider argument (may be repeated)")
+
def process_options(self, args, opts):
ScrapyCommand.process_options(self, args, opts)
+ try:
+ opts.spargs = arglist_to_dict(opts.spargs)
+ except ValueError:
+ raise UsageError("Invalid -a value, use -a NAME=VALUE", print_help=False)
def run(self, args, opts):
if len(args) != 1:
@@ -49,7 +59,7 @@ class Command(ScrapyCommand):
spclasses = list(iter_spider_classes(module))
if not spclasses:
raise UsageError("No spider found in file: %s\n" % filename)
- spider = spclasses.pop()()
- # schedule spider and start engine
- self.crawler.queue.append_spider(spider)
+ spider = spclasses.pop()(**opts.spargs)
+
+ self.crawler.crawl(spider)
self.crawler.start()
diff --git a/scrapy/commands/shell.py b/scrapy/commands/shell.py
index ae4426d2f..6600dfc5d 100644
--- a/scrapy/commands/shell.py
+++ b/scrapy/commands/shell.py
@@ -11,7 +11,7 @@ from scrapy import log
class Command(ScrapyCommand):
requires_project = False
- default_settings = {'KEEP_ALIVE': True}
+ default_settings = {'KEEP_ALIVE': True, 'LOGSTATS_INTERVAL': 0}
def syntax(self):
return "[url|file]"
diff --git a/scrapy/contrib/closespider.py b/scrapy/contrib/closespider.py
index 49fe6ecb7..e07224e7a 100644
--- a/scrapy/contrib/closespider.py
+++ b/scrapy/contrib/closespider.py
@@ -4,6 +4,7 @@ conditions are met.
See documentation in docs/topics/extensions.rst
"""
+import warnings
from collections import defaultdict
from twisted.internet import reactor
@@ -11,14 +12,19 @@ from twisted.python import log as txlog
from scrapy.xlib.pydispatch import dispatcher
from scrapy import signals, log
-from scrapy.project import crawler
+from scrapy.exceptions import ScrapyDeprecationWarning
from scrapy.conf import settings
class CloseSpider(object):
- def __init__(self):
+ def __init__(self, crawler):
+ self.crawler = crawler
self.timeout = settings.getint('CLOSESPIDER_TIMEOUT')
- self.itempassed = settings.getint('CLOSESPIDER_ITEMPASSED')
+ self.itemcount = settings.getint('CLOSESPIDER_ITEMCOUNT')
+ # XXX: legacy support - remove for future releases
+ if settings.getint('CLOSESPIDER_ITEMPASSED'):
+ warnings.warn("CLOSESPIDER_ITEMPASSED setting is deprecated, use CLOSESPIDER_ITEMCOUNT instead", ScrapyDeprecationWarning)
+ self.pagecount = settings.getint('CLOSESPIDER_ITEMPASSED')
self.pagecount = settings.getint('CLOSESPIDER_PAGECOUNT')
self.errorcount = settings.getint('CLOSESPIDER_ERRORCOUNT')
@@ -33,32 +39,36 @@ class CloseSpider(object):
dispatcher.connect(self.page_count, signal=signals.response_received)
if self.timeout:
dispatcher.connect(self.spider_opened, signal=signals.spider_opened)
- if self.itempassed:
- dispatcher.connect(self.item_passed, signal=signals.item_passed)
+ if self.itemcount:
+ dispatcher.connect(self.item_scraped, signal=signals.item_scraped)
dispatcher.connect(self.spider_closed, signal=signals.spider_closed)
+ @classmethod
+ def from_crawler(cls, crawler):
+ return cls(crawler)
+
def catch_log(self, event):
if event.get('logLevel') == log.ERROR:
spider = event.get('spider')
if spider:
self.errorcounts[spider] += 1
if self.errorcounts[spider] == self.errorcount:
- crawler.engine.close_spider(spider, 'closespider_errorcount')
+ self.crawler.engine.close_spider(spider, 'closespider_errorcount')
def page_count(self, response, request, spider):
self.pagecounts[spider] += 1
if self.pagecounts[spider] == self.pagecount:
- crawler.engine.close_spider(spider, 'closespider_pagecount')
+ self.crawler.engine.close_spider(spider, 'closespider_pagecount')
def spider_opened(self, spider):
self.tasks[spider] = reactor.callLater(self.timeout, \
- crawler.engine.close_spider, spider=spider, \
+ self.crawler.engine.close_spider, spider=spider, \
reason='closespider_timeout')
- def item_passed(self, item, spider):
+ def item_scraped(self, item, spider):
self.counts[spider] += 1
- if self.counts[spider] == self.itempassed:
- crawler.engine.close_spider(spider, 'closespider_itempassed')
+ if self.counts[spider] == self.itemcount:
+ self.crawler.engine.close_spider(spider, 'closespider_itemcount')
def spider_closed(self, spider):
self.counts.pop(spider, None)
diff --git a/scrapy/contrib/corestats.py b/scrapy/contrib/corestats.py
index bafadd65a..da25d6a97 100644
--- a/scrapy/contrib/corestats.py
+++ b/scrapy/contrib/corestats.py
@@ -1,52 +1,32 @@
"""
-Scrapy extension for collecting scraping stats
+Extension for collecting core stats like items scraped and start/finish times
"""
-import os
-import getpass
-import socket
import datetime
from scrapy.xlib.pydispatch import dispatcher
from scrapy import signals
from scrapy.stats import stats
-from scrapy.conf import settings
class CoreStats(object):
- """Scrapy core stats collector"""
def __init__(self):
- stats.set_value('envinfo/user', getpass.getuser())
- stats.set_value('envinfo/host', socket.gethostname())
- stats.set_value('envinfo/logfile', settings['LOG_FILE'])
- stats.set_value('envinfo/pid', os.getpid())
-
dispatcher.connect(self.stats_spider_opened, signal=signals.stats_spider_opened)
dispatcher.connect(self.stats_spider_closing, signal=signals.stats_spider_closing)
dispatcher.connect(self.item_scraped, signal=signals.item_scraped)
- dispatcher.connect(self.item_passed, signal=signals.item_passed)
dispatcher.connect(self.item_dropped, signal=signals.item_dropped)
def stats_spider_opened(self, spider):
stats.set_value('start_time', datetime.datetime.utcnow(), spider=spider)
- stats.set_value('envinfo/host', stats.get_value('envinfo/host'), spider=spider)
- stats.inc_value('spider_count/opened')
def stats_spider_closing(self, spider, reason):
stats.set_value('finish_time', datetime.datetime.utcnow(), spider=spider)
- stats.set_value('finish_status', 'OK' if reason == 'finished' else reason, spider=spider)
- stats.inc_value('spider_count/%s' % reason, spider=spider)
+ stats.set_value('finish_reason', reason, spider=spider)
def item_scraped(self, item, spider):
stats.inc_value('item_scraped_count', spider=spider)
- stats.inc_value('item_scraped_count')
-
- def item_passed(self, item, spider):
- stats.inc_value('item_passed_count', spider=spider)
- stats.inc_value('item_passed_count')
def item_dropped(self, item, spider, exception):
reason = exception.__class__.__name__
stats.inc_value('item_dropped_count', spider=spider)
stats.inc_value('item_dropped_reasons_count/%s' % reason, spider=spider)
- stats.inc_value('item_dropped_count')
diff --git a/scrapy/contrib/debug.py b/scrapy/contrib/debug.py
index 27048efe2..99abb86c3 100644
--- a/scrapy/contrib/debug.py
+++ b/scrapy/contrib/debug.py
@@ -4,22 +4,30 @@ Extensions for debugging Scrapy
See documentation in docs/topics/extensions.rst
"""
+import os
import signal
import traceback
from pdb import Pdb
+from scrapy.utils.engine import format_engine_status
+from scrapy import log
+
class StackTraceDump(object):
def __init__(self):
try:
signal.signal(signal.SIGUSR2, self.dump_stacktrace)
+ signal.signal(signal.SIGQUIT, self.dump_stacktrace)
except AttributeError:
# win32 platforms don't support SIGUSR signals
pass
def dump_stacktrace(self, signum, frame):
- print "Got signal. Dumping stack trace..."
- traceback.print_stack(frame)
+ msg = "Dumping stack trace and engine status" + os.linesep
+ msg += "".join(traceback.format_stack(frame))
+ msg += os.linesep
+ msg += format_engine_status()
+ log.msg(msg)
class Debugger(object):
diff --git a/scrapy/contrib/downloadermiddleware/chunked.py b/scrapy/contrib/downloadermiddleware/chunked.py
new file mode 100644
index 000000000..57e97e4d2
--- /dev/null
+++ b/scrapy/contrib/downloadermiddleware/chunked.py
@@ -0,0 +1,13 @@
+from scrapy.utils.http import decode_chunked_transfer
+
+
+class ChunkedTransferMiddleware(object):
+ """This middleware adds support for chunked transfer encoding, as
+ documented in: http://en.wikipedia.org/wiki/Chunked_transfer_encoding
+ """
+
+ def process_response(self, request, response, spider):
+ if response.headers.get('Transfer-Encoding') == 'chunked':
+ body = decode_chunked_transfer(response.body)
+ return response.replace(body=body)
+ return response
diff --git a/scrapy/contrib/downloadermiddleware/cookies.py b/scrapy/contrib/downloadermiddleware/cookies.py
index b99c4b338..d9ca178c2 100644
--- a/scrapy/contrib/downloadermiddleware/cookies.py
+++ b/scrapy/contrib/downloadermiddleware/cookies.py
@@ -1,7 +1,9 @@
+import os
from collections import defaultdict
from scrapy.xlib.pydispatch import dispatcher
from scrapy import signals
+from scrapy.exceptions import NotConfigured
from scrapy.http import Response
from scrapy.http.cookies import CookieJar
from scrapy.conf import settings
@@ -13,6 +15,8 @@ class CookiesMiddleware(object):
debug = settings.getbool('COOKIES_DEBUG')
def __init__(self):
+ if not settings.getbool('COOKIES_ENABLED'):
+ raise NotConfigured
self.jars = defaultdict(CookieJar)
dispatcher.connect(self.spider_closed, signals.spider_closed)
@@ -28,7 +32,7 @@ class CookiesMiddleware(object):
# set Cookie header
request.headers.pop('Cookie', None)
jar.add_cookie_header(request)
- self._debug_cookie(request)
+ self._debug_cookie(request, spider)
def process_response(self, request, response, spider):
if 'dont_merge_cookies' in request.meta:
@@ -37,31 +41,28 @@ class CookiesMiddleware(object):
# extract cookies from Set-Cookie and drop invalid/expired cookies
jar = self.jars[spider]
jar.extract_cookies(response, request)
- self._debug_set_cookie(response)
+ self._debug_set_cookie(response, spider)
return response
def spider_closed(self, spider):
self.jars.pop(spider, None)
- def _debug_cookie(self, request):
- """log Cookie header for request"""
+ def _debug_cookie(self, request, spider):
if self.debug:
- c = request.headers.get('Cookie')
- c = c and [p.split('=')[0] for p in c.split(';')]
- log.msg('Cookie: %s for %s' % (c, request.url), level=log.DEBUG)
+ cl = request.headers.getlist('Cookie')
+ if cl:
+ msg = "Sending cookies to: %s" % request + os.linesep
+ msg += os.linesep.join("Cookie: %s" % c for c in cl)
+ log.msg(msg, spider=spider, level=log.DEBUG)
- def _debug_set_cookie(self, response):
- """log Set-Cookies headers but exclude cookie values"""
+ def _debug_set_cookie(self, response, spider):
if self.debug:
cl = response.headers.getlist('Set-Cookie')
- res = []
- for c in cl:
- kv, tail = c.split(';', 1)
- k = kv.split('=', 1)[0]
- res.append('%s %s' % (k, tail))
- log.msg('Set-Cookie: %s from %s' % (res, response.url))
-
+ if cl:
+ msg = "Received cookies from: %s" % response + os.linesep
+ msg += os.linesep.join("Set-Cookie: %s" % c for c in cl)
+ log.msg(msg, spider=spider, level=log.DEBUG)
def _get_request_cookies(self, jar, request):
headers = {'Set-Cookie': ['%s=%s;' % (k, v) for k, v in request.cookies.iteritems()]}
diff --git a/scrapy/contrib/downloadermiddleware/httpauth.py b/scrapy/contrib/downloadermiddleware/httpauth.py
index 23f27ea34..b956838f1 100644
--- a/scrapy/contrib/downloadermiddleware/httpauth.py
+++ b/scrapy/contrib/downloadermiddleware/httpauth.py
@@ -4,7 +4,7 @@ HTTP basic auth downloader middleware
See documentation in docs/topics/downloader-middleware.rst
"""
-from scrapy.utils.http import basic_auth_header
+from w3lib.http import basic_auth_header
from scrapy.utils.python import WeakKeyCache
diff --git a/scrapy/contrib/downloadermiddleware/httpcache.py b/scrapy/contrib/downloadermiddleware/httpcache.py
index e27db5d80..b7c3bbd2e 100644
--- a/scrapy/contrib/downloadermiddleware/httpcache.py
+++ b/scrapy/contrib/downloadermiddleware/httpcache.py
@@ -5,13 +5,14 @@ from os.path import join, exists
from time import time
import cPickle as pickle
+from w3lib.http import headers_dict_to_raw, headers_raw_to_dict
+
from scrapy.xlib.pydispatch import dispatcher
from scrapy import signals
from scrapy.http import Headers
from scrapy.exceptions import NotConfigured, IgnoreRequest
-from scrapy.core.downloader.responsetypes import responsetypes
+from scrapy.responsetypes import responsetypes
from scrapy.utils.request import request_fingerprint
-from scrapy.utils.http import headers_dict_to_raw, headers_raw_to_dict
from scrapy.utils.httpobj import urlparse_cached
from scrapy.utils.misc import load_object
from scrapy.utils.project import data_path
@@ -80,8 +81,7 @@ class FilesystemCacheStorage(object):
body = f.read()
with open(join(rpath, 'response_headers'), 'rb') as f:
rawheaders = f.read()
- # We failback to metadata['url'] to support old generated caches. TODO: remove for Scrapy 0.11
- url = metadata.get('response_url') or metadata['url']
+ url = metadata.get('response_url')
status = metadata['status']
headers = Headers(headers_raw_to_dict(rawheaders))
respcls = responsetypes.from_args(headers=headers, url=url)
diff --git a/scrapy/contrib/downloadermiddleware/httpcompression.py b/scrapy/contrib/downloadermiddleware/httpcompression.py
index 26069d437..25af3e051 100644
--- a/scrapy/contrib/downloadermiddleware/httpcompression.py
+++ b/scrapy/contrib/downloadermiddleware/httpcompression.py
@@ -1,9 +1,8 @@
import zlib
-from gzip import GzipFile
-from cStringIO import StringIO
+from scrapy.utils.gz import gunzip
from scrapy.http import Response, TextResponse
-from scrapy.core.downloader.responsetypes import responsetypes
+from scrapy.responsetypes import responsetypes
class HttpCompressionMiddleware(object):
@@ -11,7 +10,7 @@ class HttpCompressionMiddleware(object):
sent/received from web sites"""
def process_request(self, request, spider):
- request.headers.setdefault('Accept-Encoding', 'gzip,deflate')
+ request.headers.setdefault('Accept-Encoding', 'x-gzip,gzip,deflate')
def process_response(self, request, response, spider):
if isinstance(response, Response):
@@ -33,8 +32,8 @@ class HttpCompressionMiddleware(object):
return response
def _decode(self, body, encoding):
- if encoding == 'gzip':
- body = GzipFile(fileobj=StringIO(body)).read()
+ if encoding == 'gzip' or encoding == 'x-gzip':
+ body = gunzip(body)
if encoding == 'deflate':
try:
diff --git a/scrapy/contrib/downloadermiddleware/redirect.py b/scrapy/contrib/downloadermiddleware/redirect.py
index cbeb41050..c8a401d0f 100644
--- a/scrapy/contrib/downloadermiddleware/redirect.py
+++ b/scrapy/contrib/downloadermiddleware/redirect.py
@@ -1,8 +1,9 @@
+from w3lib.url import urljoin_rfc
+
from scrapy import log
from scrapy.http import HtmlResponse
-from scrapy.utils.url import urljoin_rfc
from scrapy.utils.response import get_meta_refresh
-from scrapy.exceptions import IgnoreRequest
+from scrapy.exceptions import IgnoreRequest, NotConfigured
from scrapy.conf import settings
@@ -10,6 +11,8 @@ class RedirectMiddleware(object):
"""Handle redirection of requests based on response status and meta-refresh html tag"""
def __init__(self):
+ if not settings.getbool('REDIRECT_ENABLED'):
+ raise NotConfigured
self.max_metarefresh_delay = settings.getint('REDIRECT_MAX_METAREFRESH_DELAY')
self.max_redirect_times = settings.getint('REDIRECT_MAX_TIMES')
self.priority_adjust = settings.getint('REDIRECT_PRIORITY_ADJUST')
diff --git a/scrapy/contrib/downloadermiddleware/retry.py b/scrapy/contrib/downloadermiddleware/retry.py
index c8d44dffe..71fb3a94f 100644
--- a/scrapy/contrib/downloadermiddleware/retry.py
+++ b/scrapy/contrib/downloadermiddleware/retry.py
@@ -20,23 +20,29 @@ About HTTP errors to consider:
from twisted.internet.error import TimeoutError as ServerTimeoutError, DNSLookupError, \
ConnectionRefusedError, ConnectionDone, ConnectError, \
- ConnectionLost
+ ConnectionLost, TCPTimedOutError
from twisted.internet.defer import TimeoutError as UserTimeoutError
from twisted.web.client import PartialDownloadError
from scrapy import log
+from scrapy.exceptions import NotConfigured
from scrapy.utils.response import response_status_message
from scrapy.conf import settings
class RetryMiddleware(object):
+ # IOError is raised by the HttpCompression middleware when trying to
+ # decompress an empty response
EXCEPTIONS_TO_RETRY = (ServerTimeoutError, UserTimeoutError, DNSLookupError,
ConnectionRefusedError, ConnectionDone, ConnectError,
- ConnectionLost, PartialDownloadError)
+ ConnectionLost, PartialDownloadError, TCPTimedOutError,
+ IOError)
def __init__(self):
+ if not settings.getbool('RETRY_ENABLED'):
+ raise NotConfigured
self.max_retry_times = settings.getint('RETRY_TIMES')
- self.retry_http_codes = map(int, settings.getlist('RETRY_HTTP_CODES'))
+ self.retry_http_codes = set(int(x) for x in settings.getlist('RETRY_HTTP_CODES'))
self.priority_adjust = settings.getint('RETRY_PRIORITY_ADJUST')
def process_response(self, request, response, spider):
@@ -64,6 +70,6 @@ class RetryMiddleware(object):
retryreq.priority = request.priority + self.priority_adjust
return retryreq
else:
- log.msg("Discarding %s (failed %d times): %s" % (request, retries, reason),
+ log.msg("Gave up retrying %s (failed %d times): %s" % (request, retries, reason),
spider=spider, level=log.DEBUG)
diff --git a/scrapy/contrib/downloadermiddleware/robotstxt.py b/scrapy/contrib/downloadermiddleware/robotstxt.py
index 220b5926a..bf64677f8 100644
--- a/scrapy/contrib/downloadermiddleware/robotstxt.py
+++ b/scrapy/contrib/downloadermiddleware/robotstxt.py
@@ -9,25 +9,28 @@ import robotparser
from scrapy.xlib.pydispatch import dispatcher
from scrapy import signals, log
-from scrapy.project import crawler
from scrapy.exceptions import NotConfigured, IgnoreRequest
from scrapy.http import Request
from scrapy.utils.httpobj import urlparse_cached
-from scrapy.conf import settings
class RobotsTxtMiddleware(object):
DOWNLOAD_PRIORITY = 1000
- def __init__(self):
- if not settings.getbool('ROBOTSTXT_OBEY'):
+ def __init__(self, crawler):
+ if not crawler.settings.getbool('ROBOTSTXT_OBEY'):
raise NotConfigured
+ self.crawler = crawler
self._parsers = {}
self._spider_netlocs = {}
self._useragents = {}
dispatcher.connect(self.spider_opened, signals.spider_opened)
dispatcher.connect(self.spider_closed, signals.spider_closed)
+ @classmethod
+ def from_crawler(cls, crawler):
+ return cls(crawler)
+
def process_request(self, request, spider):
useragent = self._useragents[spider]
rp = self.robot_parser(request, spider)
@@ -42,7 +45,7 @@ class RobotsTxtMiddleware(object):
self._parsers[netloc] = None
robotsurl = "%s://%s/robots.txt" % (url.scheme, url.netloc)
robotsreq = Request(robotsurl, priority=self.DOWNLOAD_PRIORITY)
- dfd = crawler.engine.download(robotsreq, spider)
+ dfd = self.crawler.engine.download(robotsreq, spider)
dfd.addCallback(self._parse_robots)
self._spider_netlocs[spider].add(netloc)
return self._parsers[netloc]
diff --git a/scrapy/contrib/downloadermiddleware/stats.py b/scrapy/contrib/downloadermiddleware/stats.py
index 2f9c61336..0b8062d60 100644
--- a/scrapy/contrib/downloadermiddleware/stats.py
+++ b/scrapy/contrib/downloadermiddleware/stats.py
@@ -11,24 +11,19 @@ class DownloaderStats(object):
raise NotConfigured
def process_request(self, request, spider):
- stats.inc_value('downloader/request_count')
stats.inc_value('downloader/request_count', spider=spider)
stats.inc_value('downloader/request_method_count/%s' % request.method, spider=spider)
reqlen = len(request_httprepr(request))
stats.inc_value('downloader/request_bytes', reqlen, spider=spider)
- stats.inc_value('downloader/request_bytes', reqlen)
def process_response(self, request, response, spider):
- stats.inc_value('downloader/response_count')
stats.inc_value('downloader/response_count', spider=spider)
stats.inc_value('downloader/response_status_count/%s' % response.status, spider=spider)
reslen = len(response_httprepr(response))
stats.inc_value('downloader/response_bytes', reslen, spider=spider)
- stats.inc_value('downloader/response_bytes', reslen)
return response
def process_exception(self, request, exception, spider):
ex_class = "%s.%s" % (exception.__class__.__module__, exception.__class__.__name__)
- stats.inc_value('downloader/exception_count')
stats.inc_value('downloader/exception_count', spider=spider)
stats.inc_value('downloader/exception_type_count/%s' % ex_class, spider=spider)
diff --git a/scrapy/contrib/dupefilter.py b/scrapy/contrib/dupefilter.py
deleted file mode 100644
index c6b9d185a..000000000
--- a/scrapy/contrib/dupefilter.py
+++ /dev/null
@@ -1,49 +0,0 @@
-"""
-Dupe Filter classes implement a mechanism for filtering duplicate requests.
-They must implement the following methods:
-
-* open_spider(spider)
- open a spider for tracking duplicates (typically used to reserve resources)
-
-* close_spider(spider)
- close a spider (typically used for freeing resources)
-
-* request_seen(spider, request, dont_record=False)
- return ``True`` if the request was seen before, or ``False`` otherwise. If
- ``dont_record`` is ``True`` the request must not be recorded as seen.
-
-"""
-
-from scrapy.utils.request import request_fingerprint
-
-
-class NullDupeFilter(dict):
- def open_spider(self, spider):
- pass
-
- def close_spider(self, spider):
- pass
-
- def request_seen(self, spider, request, dont_record=False):
- return False
-
-
-class RequestFingerprintDupeFilter(object):
- """Duplicate filter using scrapy.utils.request.request_fingerprint"""
-
- def __init__(self):
- self.fingerprints = {}
-
- def open_spider(self, spider):
- self.fingerprints[spider] = set()
-
- def close_spider(self, spider):
- del self.fingerprints[spider]
-
- def request_seen(self, spider, request, dont_record=False):
- fp = request_fingerprint(request)
- if fp in self.fingerprints[spider]:
- return True
- if not dont_record:
- self.fingerprints[spider].add(fp)
- return False
diff --git a/scrapy/contrib/exporter/__init__.py b/scrapy/contrib/exporter/__init__.py
index b77c747cc..820bf06e2 100644
--- a/scrapy/contrib/exporter/__init__.py
+++ b/scrapy/contrib/exporter/__init__.py
@@ -4,6 +4,7 @@ Item Exporters are used to export/serialize items into different formats.
import csv
import pprint
+import marshal
from cPickle import Pickler
from xml.sax.saxutils import XMLGenerator
@@ -12,7 +13,7 @@ from scrapy.utils.py26 import json
__all__ = ['BaseItemExporter', 'PprintItemExporter', 'PickleItemExporter', \
'CsvItemExporter', 'XmlItemExporter', 'JsonLinesItemExporter', \
- 'JsonItemExporter']
+ 'JsonItemExporter', 'MarshalItemExporter']
class BaseItemExporter(object):
@@ -143,11 +144,20 @@ class XmlItemExporter(BaseItemExporter):
class CsvItemExporter(BaseItemExporter):
- def __init__(self, file, include_headers_line=True, **kwargs):
+ def __init__(self, file, include_headers_line=True, join_multivalued=',', **kwargs):
self._configure(kwargs, dont_fail=True)
self.include_headers_line = include_headers_line
self.csv_writer = csv.writer(file, **kwargs)
self._headers_not_written = True
+ self._join_multivalued = join_multivalued
+
+ def _to_str_if_unicode(self, value):
+ if isinstance(value, (list, tuple)):
+ try:
+ value = self._join_multivalued.join(value)
+ except TypeError: # list in value may not contain strings
+ pass
+ return super(CsvItemExporter, self)._to_str_if_unicode(value)
def export_item(self, item):
if self._headers_not_written:
@@ -176,6 +186,16 @@ class PickleItemExporter(BaseItemExporter):
self.pickler.dump(dict(self._get_serialized_fields(item)))
+class MarshalItemExporter(BaseItemExporter):
+
+ def __init__(self, file, **kwargs):
+ self._configure(kwargs)
+ self.file = file
+
+ def export_item(self, item):
+ marshal.dump(dict(self._get_serialized_fields(item)), self.file)
+
+
class PprintItemExporter(BaseItemExporter):
def __init__(self, file, **kwargs):
diff --git a/scrapy/contrib/exporter/jsonlines.py b/scrapy/contrib/exporter/jsonlines.py
index eb2dbcafe..fbab65735 100644
--- a/scrapy/contrib/exporter/jsonlines.py
+++ b/scrapy/contrib/exporter/jsonlines.py
@@ -1,5 +1,6 @@
from scrapy.contrib.exporter import JsonLinesItemExporter
+from scrapy.exceptions import ScrapyDeprecationWarning
import warnings
warnings.warn("Module `scrapy.contrib.exporter.jsonlines` is deprecated - use `scrapy.contrib.exporter` instead",
- DeprecationWarning, stacklevel=2)
+ ScrapyDeprecationWarning, stacklevel=2)
diff --git a/scrapy/contrib/feedexport.py b/scrapy/contrib/feedexport.py
index 8ab028c9e..a1e215367 100644
--- a/scrapy/contrib/feedexport.py
+++ b/scrapy/contrib/feedexport.py
@@ -12,14 +12,14 @@ from ftplib import FTP
from shutil import copyfileobj
from zope.interface import Interface, implements
-
from twisted.internet import defer, threads
+from w3lib.url import file_uri_to_path
+
from scrapy import log, signals
from scrapy.xlib.pydispatch import dispatcher
from scrapy.utils.ftp import ftp_makedirs_cwd
from scrapy.exceptions import NotConfigured
from scrapy.utils.misc import load_object
-from scrapy.utils.url import file_uri_to_path
from scrapy.conf import settings
@@ -136,7 +136,7 @@ class FeedExporter(object):
self.slots = {}
dispatcher.connect(self.open_spider, signals.spider_opened)
dispatcher.connect(self.close_spider, signals.spider_closed)
- dispatcher.connect(self.item_passed, signals.item_passed)
+ dispatcher.connect(self.item_scraped, signals.item_scraped)
def open_spider(self, spider):
file = TemporaryFile(prefix='feed-')
@@ -163,7 +163,7 @@ class FeedExporter(object):
d.addBoth(lambda _: slot.file.close())
return d
- def item_passed(self, item, spider):
+ def item_scraped(self, item, spider):
slot = self.slots[spider]
slot.exporter.export_item(item)
slot.itemcount += 1
diff --git a/scrapy/contrib/httpcache.py b/scrapy/contrib/httpcache.py
new file mode 100644
index 000000000..8eed8b943
--- /dev/null
+++ b/scrapy/contrib/httpcache.py
@@ -0,0 +1,64 @@
+from __future__ import with_statement
+
+import os
+from time import time
+import cPickle as pickle
+
+from scrapy.http import Headers
+from scrapy.responsetypes import responsetypes
+from scrapy.utils.request import request_fingerprint
+from scrapy.utils.project import data_path
+from scrapy import conf
+
+
+class DbmCacheStorage(object):
+
+ def __init__(self, settings=conf.settings):
+ self.cachedir = data_path(settings['HTTPCACHE_DIR'])
+ self.expiration_secs = settings.getint('HTTPCACHE_EXPIRATION_SECS')
+ self.dbmodule = __import__(settings['HTTPCACHE_DBM_MODULE'])
+ self.dbs = {}
+
+ def open_spider(self, spider):
+ dbpath = os.path.join(self.cachedir, '%s.db' % spider.name)
+ self.dbs[spider] = self.dbmodule.open(dbpath, 'c')
+
+ def close_spider(self, spider):
+ self.dbs[spider].close()
+
+ def retrieve_response(self, spider, request):
+ data = self._read_data(spider, request)
+ if data is None:
+ return # not cached
+ url = data['url']
+ status = data['status']
+ headers = Headers(data['headers'])
+ body = data['body']
+ respcls = responsetypes.from_args(headers=headers, url=url)
+ response = respcls(url=url, headers=headers, status=status, body=body)
+ return response
+
+ def store_response(self, spider, request, response):
+ key = self._request_key(request)
+ data = {
+ 'status': response.status,
+ 'url': response.url,
+ 'headers': dict(response.headers),
+ 'body': response.body,
+ }
+ self.dbs[spider]['%s_data' % key] = pickle.dumps(data, protocol=2)
+ self.dbs[spider]['%s_time' % key] = str(time())
+
+ def _read_data(self, spider, request):
+ key = self._request_key(request)
+ db = self.dbs[spider]
+ tkey = '%s_time' % key
+ if not db.has_key(tkey):
+ return # not found
+ ts = db[tkey]
+ if 0 < self.expiration_secs < time() - float(ts):
+ return # expired
+ return pickle.loads(db['%s_data' % key])
+
+ def _request_key(self, request):
+ return request_fingerprint(request)
diff --git a/scrapy/contrib/ibl/__init__.py b/scrapy/contrib/ibl/__init__.py
deleted file mode 100644
index fbb1c895e..000000000
--- a/scrapy/contrib/ibl/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-"""
-This contrib implements an automatic extraction library based on an Instance
-Based Learning (IBL) algorithm, as described in the following papers:
-
- A hierarchical approach to wrapper induction
- http://portal.acm.org/citation.cfm?id=301191
-
- Extracting web data using instance based learning
- http://portal.acm.org/citation.cfm?id=1265174
-
-This code requires the numpy library.
-"""
diff --git a/scrapy/contrib/ibl/descriptor.py b/scrapy/contrib/ibl/descriptor.py
deleted file mode 100644
index 5b4ae99ce..000000000
--- a/scrapy/contrib/ibl/descriptor.py
+++ /dev/null
@@ -1,62 +0,0 @@
-"""
-Extended types for IBL extraction
-"""
-from itertools import chain
-
-from scrapy.contrib.ibl.extractors import text
-
-class FieldDescriptor(object):
- """description of a scraped attribute"""
- __slots__ = ('name', 'description', 'extractor', 'required', 'allow_markup')
-
- def __init__(self, name, description, extractor=text, required=False,
- allow_markup=False):
- self.name = name
- self.description = description
- self.extractor = extractor
- self.required = required
- self.allow_markup = allow_markup
-
- @classmethod
- def from_field(cls, name, field):
- return cls(name, field.get('description'), \
- field.get('ibl_extractor', text), field.get('required', False), \
- field.get('allow_markup', False))
-
- def __str__(self):
- return "FieldDescriptor(%s)" % self.name
-
-class ItemDescriptor(object):
- """Simple auto scraping item descriptor.
-
- This used to describe type-specific operations and may be overridden where
- necessary.
- """
-
- def __init__(self, name, description, attribute_descriptors):
- self.name = name
- self.attribute_map = dict((d.name, d) for d in attribute_descriptors)
- self._required_attributes = [d.name for d in attribute_descriptors \
- if d.required]
-
- @classmethod
- def from_item(cls, name, description, item):
- a = [FieldDescriptor.from_field(n, f) for n, f in item.fields.items()]
- return cls(name, description, a)
-
- def validated(self, data):
- """Only return the items in the data that are valid"""
- return [d for d in data if self._item_validates(d)]
-
- def _item_validates(self, item):
- """simply checks that all mandatory attributes are present"""
- variant_attrs = set(chain(*
- [v.keys() for v in item.get('variants', [])]))
- return all([(name in item or name in variant_attrs) \
- for name in self._required_attributes])
-
- def get_required_attributes(self):
- return self._required_attributes
-
- def __str__(self):
- return "ItemDescriptor(%s)" % self.name
diff --git a/scrapy/contrib/ibl/extraction/__init__.py b/scrapy/contrib/ibl/extraction/__init__.py
deleted file mode 100644
index 299fa31ae..000000000
--- a/scrapy/contrib/ibl/extraction/__init__.py
+++ /dev/null
@@ -1,96 +0,0 @@
-"""
-IBL module
-
-This contains an extraction algorithm based on the paper Extracting Web Data
-Using Instance-Based Learning by Yanhong Zhai and Bing Liu.
-
-It defines the InstanceBasedLearningExtractor class, which implements this
-extraction algorithm.
-
-Main departures from the original algorithm:
- * there is no limit in prefix or suffix size
- * we have "attribute adaptors" that allow generic post processing and may
- affect the extraction process. For example, a price field may require a
- numeric value to be present.
- * tags can be inserted to extract regions not wrapped by html tags. These
- regions are then identified using the longest unique character prefix and
- suffix.
-"""
-from operator import itemgetter
-from .regionextract import build_extraction_tree
-from .pageparsing import parse_template, parse_extraction_page
-from .pageobjects import TokenDict
-
-class InstanceBasedLearningExtractor(object):
- """Implementation of the instance based learning algorithm to
- extract data from web pages.
- """
-
- def __init__(self, templates, type_descriptor=None, trace=False):
- """Initialise this extractor
-
- templates should contain a sequence of strings, each containing
- annotated html that will be used as templates for extraction.
-
- Tags surrounding areas to be extracted must contain a
- 'data-scrapy-annotate' attribute and the value must be the name
- of the attribute. If the tag was inserted and was not present in the
- original page, the data-scrapy-generated attribute must be present.
-
- type_descriptor may contain a type descriptor describing the item
- to be extracted.
-
- if trace is true, the returned extracted data will have a 'trace'
- property that contains a trace of the extraction execution.
- """
- self.token_dict = TokenDict()
- parsed_plus_templates = [(parse_template(self.token_dict, t), t) for t in templates]
- parsed_plus_epages = [(p, parse_extraction_page(self.token_dict, t)) for p, t \
- in parsed_plus_templates if _annotation_count(p)]
- parsed_templates = map(itemgetter(0), parsed_plus_epages)
-
- # templates with more attributes are considered first
- sorted_templates = sorted(parsed_templates, key=_annotation_count, reverse=True)
- self.extraction_trees = [build_extraction_tree(t, type_descriptor,
- trace) for t in sorted_templates]
- self.validated = type_descriptor.validated if type_descriptor else \
- self._filter_not_none
-
- def extract(self, html, pref_template_id=None, useone=False):
- """extract data from an html page
-
- If pref_template_url is specified, the template with that url will be
- used first.
- if useone is True and no data was extracted, no additional template will
- be tried. If False and no data was extracted, try with rest of item templates
- """
- extraction_page = parse_extraction_page(self.token_dict, html)
- if pref_template_id is not None:
- if useone:
- extraction_trees = [x for x in self.extraction_trees if x.template.id == pref_template_id]
- else:
- extraction_trees = sorted(self.extraction_trees,
- key=lambda x: x.template.id != pref_template_id)
- else:
- extraction_trees = self.extraction_trees
-
- for extraction_tree in extraction_trees:
- extracted = extraction_tree.extract(extraction_page)
- correctly_extracted = self.validated(extracted)
- extra_required = extraction_tree.template.extra_required_attrs
- correctly_extracted = [c for c in correctly_extracted if \
- extra_required.intersection(c.keys()) == extra_required ]
- if len(correctly_extracted) > 0:
- return correctly_extracted, extraction_tree.template
- return None, None
-
- def __str__(self):
- return "InstanceBasedLearningExtractor[\n%s\n]" % \
- (',\n'.join(map(str, self.extraction_trees)))
-
- @staticmethod
- def _filter_not_none(items):
- return [d for d in items if d is not None]
-
-def _annotation_count(template):
- return len(template.annotations)
diff --git a/scrapy/contrib/ibl/extraction/pageobjects.py b/scrapy/contrib/ibl/extraction/pageobjects.py
deleted file mode 100644
index fa290d3c7..000000000
--- a/scrapy/contrib/ibl/extraction/pageobjects.py
+++ /dev/null
@@ -1,228 +0,0 @@
-"""
-Page objects
-
-This module contains objects representing pages and parts of pages (e.g. tokens
-and annotations) used in the instance based learning algorithm.
-"""
-from numpy import array, ndarray
-
-from scrapy.contrib.ibl.htmlpage import HtmlTagType
-
-class TokenType(object):
- """constants for token types"""
- WORD = 0
- OPEN_TAG = HtmlTagType.OPEN_TAG
- CLOSE_TAG = HtmlTagType.CLOSE_TAG
- NON_PAIRED_TAG = HtmlTagType.UNPAIRED_TAG
-
-class TokenDict(object):
- """Mapping from parse tokens to integers
-
- >>> d = TokenDict()
- >>> d.tokenid('i')
- 0
- >>> d.tokenid('b')
- 1
- >>> d.tokenid('i')
- 0
-
- Tokens can be searched for by id
- >>> d.find_token(1)
- 'b'
-
- The lower 24 bits store the token reference and the higher bits the type.
- """
-
- def __init__(self):
- self.token_ids = {}
-
- def tokenid(self, token, token_type=TokenType.WORD):
- """create an integer id from the token and token type passed"""
- tid = self.token_ids.setdefault(token, len(self.token_ids))
- return tid | (token_type << 24)
-
- @staticmethod
- def token_type(token):
- """extract the token type from the token id passed"""
- return token >> 24
-
- def find_token(self, tid):
- """Search for a tag with the given ID
-
- This is O(N) and is only intended for debugging
- """
- tid &= 0xFFFFFF
- if tid >= len(self.token_ids) or tid < 0:
- raise ValueError("tag id %s out of range" % tid)
-
- for (token, token_id) in self.token_ids.items():
- if token_id == tid:
- return token
- assert False, "token dictionary is corrupt"
-
- def token_string(self, tid):
- """create a string representation of a token
-
- This is O(N).
- """
- templates = ["%s", "<%s>", "%s>", "<%s/>"]
- return templates[tid >> 24] % self.find_token(tid)
-
-class Page(object):
- """Basic representation of a page. This consists of a reference to a
- dictionary of tokens and an array of raw token ids
- """
-
- __slots__ = ('token_dict', 'page_tokens')
-
- def __init__(self, token_dict, page_tokens):
- self.token_dict = token_dict
- # use a numpy array becuase we can index/slice easily and efficiently
- if not isinstance(page_tokens, ndarray):
- page_tokens = array(page_tokens)
- self.page_tokens = page_tokens
-
-class TemplatePage(Page):
- __slots__ = ('annotations', 'id', 'ignored_regions', 'extra_required_attrs')
-
- def __init__(self, token_dict, page_tokens, annotations, template_id=None, \
- ignored_regions=None, extra_required=None):
- Page.__init__(self, token_dict, page_tokens)
- # ensure order is the same as start tag order in the original page
- annotations = sorted(annotations, key=lambda x: x.end_index, reverse=True)
- self.annotations = sorted(annotations, key=lambda x: x.start_index)
- self.id = template_id
- self.ignored_regions = ignored_regions or []
- self.extra_required_attrs = set(extra_required or [])
-
- def __str__(self):
- summary = []
- for index, token in enumerate(self.page_tokens):
- text = "%s: %s" % (index, self.token_dict.find_token(token))
- summary.append(text)
- return "TemplatePage\n============\nTokens: (index, token)\n%s\nAnnotations: %s\n" % \
- ('\n'.join(summary), '\n'.join(map(str, self.annotations)))
-
-class ExtractionPage(Page):
- """Parsed data belonging to a web page upon which we wish to perform
- extraction.
- """
- __slots__ = ('text',
- 'token_start_indexes', # index in text of the start of a token
- 'token_follow_indexes', # index in text of data following token
- 'tag_attributes' # a map from token index to tag attributes
- )
-
- def __init__(self, text, token_dict, page_tokens, token_start_indexes,
- token_follow_indexes, tag_attributes):
- Page.__init__(self, token_dict, page_tokens)
- self.text = text
- self.token_start_indexes = token_start_indexes
- self.token_follow_indexes = token_follow_indexes
- self.tag_attributes = tag_attributes
-
- def token_html(self, token_index):
- """The raw html for a page token at the given index in the page_tokens
- list
- """
- text_start = self.token_start_indexes[token_index]
- text_end = self.token_follow_indexes[token_index]
- return self.text[text_start:text_end]
-
- def html_between_tokens(self, start_token_index, end_token_index):
- """The raw html between the tokens at the specified indexes in the
- page_tokens list
-
- This assumes start_token_index <= end_token_index
- """
- text_start = self.token_follow_indexes[start_token_index]
- text_end = self.token_start_indexes[end_token_index]
- return self.text[text_start:text_end]
-
- def text_between_tokens(self, start_token_index, end_token_index,
- tag_replacement=u' '):
- """The text between the the tokens at the specified indexes in the
- page_tokens list. Tags are replaced by tag_replacement (default one space
- character)
- """
- return tag_replacement.join([self.text[
- self.token_follow_indexes[i]:self.token_start_indexes[i+1]] \
- for i in xrange(start_token_index, end_token_index)])
-
- def tag_attribute(self, token_index, attribute):
- """The value of a tag attribute. The tag is identified by its
- corresponding token index.
-
- If the tag or attribute is not present, None is returned
- """
- return self.tag_attributes.get(token_index, {}).get(attribute)
-
- def __str__(self):
- summary = []
- for (token, start, follow) in zip(self.page_tokens, self.token_start_indexes,
- self.token_follow_indexes):
- text = "%s %s-%s (%s)" % (self.token_dict.find_token(token), start, follow,
- self.text[start:follow])
- summary.append(text)
- return "ExtractionPage\n==============\nTokens: %s\n\nRaw text: %s\n\n" \
- "Tag attributes: %s\n" % ('\n'.join(summary), self.text,
- self.tag_attributes)
-
-class AnnotationText(object):
- __slots__ = ('start_text', 'follow_text')
-
- def __init__(self, start_text=None, follow_text=None):
- self.start_text = start_text
- self.follow_text = follow_text
-
- def __str__(self):
- return "AnnotationText(%s..%s)" % \
- (repr(self.start_text), repr(self.follow_text))
-
-class AnnotationTag(object):
- """A tag that annotates part of the document
-
- It has the following properties:
- start_index - index of the token for the opening tag
- end_index - index of the token for the closing tag
- surrounds_attribute - the attribute name surrounded by this tag
- tag_attributes - list of (tag attribute, extracted attribute) tuples
- for each item to be extracted from a tag attribute
- annotation_text - text prefix and suffix for the attribute to be extracted
- metadata - dict with annotation data not used by IBL extractor
- """
- __slots__ = ('surrounds_attribute', 'start_index', 'end_index',
- 'tag_attributes', 'annotation_text', 'variant_id',
- 'metadata')
-
- def __init__(self, start_index, end_index, surrounds_attribute=None,
- annotation_text=None, tag_attributes=None, variant_id=None):
- self.start_index = start_index
- self.end_index = end_index
- self.surrounds_attribute = surrounds_attribute
- self.annotation_text = annotation_text
- self.tag_attributes = tag_attributes or []
- self.variant_id = variant_id
- self.metadata = {}
-
- def __str__(self):
- return "AnnotationTag(%s)" % ", ".join(
- ["%s=%s" % (s, getattr(self, s)) \
- for s in self.__slots__ if getattr(self, s)])
-
- def __repr__(self):
- return str(self)
-
-class LabelledRegion(object):
- __slots__ = ('start_index', 'end_index')
-
- def __init__(self, start, end):
- self.start_index = start
- self.end_index = end
-
- def __str__(self):
- return "LabelledRegion (%s, %s)" % (self.start_index, self.end_index)
-
- def __repr__(self):
- return str(self)
-
diff --git a/scrapy/contrib/ibl/extraction/pageparsing.py b/scrapy/contrib/ibl/extraction/pageparsing.py
deleted file mode 100644
index 2df63267f..000000000
--- a/scrapy/contrib/ibl/extraction/pageparsing.py
+++ /dev/null
@@ -1,319 +0,0 @@
-"""
-Page parsing
-
-Parsing of web pages for extraction task.
-"""
-from collections import defaultdict
-from numpy import array
-
-from scrapy.utils.py26 import json
-
-from scrapy.contrib.ibl.htmlpage import HtmlTagType, HtmlTag, HtmlPage
-from scrapy.contrib.ibl.extraction.pageobjects import (AnnotationTag,
- TemplatePage, ExtractionPage, AnnotationText, TokenDict)
-
-def parse_strings(template_html, extraction_html):
- """Create a template and extraction page from raw strings
-
- this is useful for testing purposes
- """
- t = TokenDict()
- template_page = HtmlPage(body=template_html)
- extraction_page = HtmlPage(body=extraction_html)
- return (parse_template(t, template_page),
- parse_extraction_page(t, extraction_page))
-
-def parse_template(token_dict, template_html):
- """Create an TemplatePage object by parsing the annotated html"""
- parser = TemplatePageParser(token_dict)
- parser.feed(template_html)
- return parser.to_template()
-
-def parse_extraction_page(token_dict, page_html):
- """Create an ExtractionPage object by parsing the html"""
- parser = ExtractionPageParser(token_dict)
- parser.feed(page_html)
- return parser.to_extraction_page()
-
-class InstanceLearningParser(object):
- """Base parser for instance based learning algorithm
-
- This does not require correct HTML and the parsing method should not alter
- the original tag order. It is important that parsing results do not vary.
- """
- def __init__(self, token_dict):
- self.token_dict = token_dict
- self.token_list = []
-
- def _add_token(self, token, token_type, start, end):
- tid = self.token_dict.tokenid(token, token_type)
- self.token_list.append(tid)
-
- def feed(self, html_page):
- self.html_page = html_page
- self.previous_element_class = None
- for data in html_page.parsed_body:
- if isinstance(data, HtmlTag):
- self._add_token(data.tag, data.tag_type, data.start, data.end)
- self.handle_tag(data)
- else:
- self.handle_data(data)
- self.previous_element_class = data.__class__
-
- def handle_data(self, html_data_fragment):
- pass
-
- def handle_tag(self, html_tag):
- pass
-
-_END_UNPAIREDTAG_TAGS = ["form", "div", "p", "table", "tr", "td"]
-
-class TemplatePageParser(InstanceLearningParser):
- """Template parsing for instance based learning algorithm"""
-
- def __init__(self, token_dict):
- InstanceLearningParser.__init__(self, token_dict)
- self.annotations = []
- self.ignored_regions = []
- self.extra_required_attrs = []
- self.ignored_tag_stacks = defaultdict(list)
- # tag names that have not been completed
- self.labelled_tag_stacks = defaultdict(list)
- self.replacement_stacks = defaultdict(list)
- self.unpairedtag_stack = []
- self.variant_stack = []
- self.prev_data = None
- self.last_text_region = None
- self.next_tag_index = 0
-
- def handle_tag(self, html_tag):
- if self.last_text_region:
- self._process_text('')
-
- if html_tag.tag_type == HtmlTagType.OPEN_TAG:
- self._handle_open_tag(html_tag)
- elif html_tag.tag_type == HtmlTagType.CLOSE_TAG:
- self._handle_close_tag(html_tag)
- else:
- # the tag is not paired, it can contain only attribute annotations
- self._handle_unpaired_tag(html_tag)
-
- @staticmethod
- def _read_template_annotation(html_tag):
- template_attr = html_tag.attributes.get('data-scrapy-annotate')
- if template_attr is None:
- return None
- unescaped = template_attr.replace('"', '"')
- return json.loads(unescaped)
-
- @staticmethod
- def _read_bool_template_attribute(html_tag, attribute):
- return html_tag.attributes.get("data-scrapy-" + attribute) == "true"
-
- def _close_unpaired_tag(self):
- self.unpairedtag_stack[0].end_index = self.next_tag_index
- self.unpairedtag_stack = []
-
- def _handle_unpaired_tag(self, html_tag):
- if self._read_bool_template_attribute(html_tag, "ignore") and html_tag.tag == "img":
- self.ignored_regions.append((self.next_tag_index, self.next_tag_index + 1))
- elif self._read_bool_template_attribute(html_tag, "ignore-beneath"):
- self.ignored_regions.append((self.next_tag_index, None))
- jannotation = self._read_template_annotation(html_tag)
- if jannotation:
- if self.unpairedtag_stack:
- self._close_unpaired_tag()
-
- annotation = AnnotationTag(self.next_tag_index, self.next_tag_index + 1)
- attribute_annotations = jannotation.pop('annotations', {}).items()
- for extract_attribute, tag_value in attribute_annotations:
- if extract_attribute == 'content':
- annotation.surrounds_attribute = tag_value
- self.unpairedtag_stack.append(annotation)
- else:
- annotation.tag_attributes.append((extract_attribute, tag_value))
- self.annotations.append(annotation)
-
- self.extra_required_attrs.extend(jannotation.pop('required', []))
- annotation.metadata = jannotation
-
- self.next_tag_index += 1
-
- def _handle_open_tag(self, html_tag):
- if self._read_bool_template_attribute(html_tag, "ignore"):
- if html_tag.tag == "img":
- self.ignored_regions.append((self.next_tag_index, self.next_tag_index + 1))
- else:
- self.ignored_regions.append((self.next_tag_index, None))
- self.ignored_tag_stacks[html_tag.tag].append(html_tag)
-
- elif self.ignored_tag_stacks.get(html_tag.tag):
- self.ignored_tag_stacks[html_tag.tag].append(None)
- if self._read_bool_template_attribute(html_tag, "ignore-beneath"):
- self.ignored_regions.append((self.next_tag_index, None))
-
- replacement = html_tag.attributes.pop("data-scrapy-replacement", None)
- if replacement:
- self.token_list.pop()
- self._add_token(replacement, html_tag.tag_type, html_tag.start, html_tag.end)
- self.replacement_stacks[html_tag.tag].append(replacement)
- elif html_tag.tag in self.replacement_stacks:
- self.replacement_stacks[html_tag.tag].append(None)
-
- if self.unpairedtag_stack:
- if html_tag.tag in _END_UNPAIREDTAG_TAGS:
- self._close_unpaired_tag()
- else:
- self.unpairedtag_stack.append(html_tag.tag)
-
- # can't be a p inside another p. Also, an open p element closes
- # a previous open p element.
- if html_tag.tag == "p" and html_tag.tag in self.labelled_tag_stacks:
- annotation = self.labelled_tag_stacks.pop(html_tag.tag)[0]
- annotation.end_index = self.next_tag_index
- self.annotations.append(annotation)
-
- jannotation = self._read_template_annotation(html_tag)
- if not jannotation:
- if html_tag.tag in self.labelled_tag_stacks:
- # add this tag to the stack to match correct end tag
- self.labelled_tag_stacks[html_tag.tag].append(None)
- self.next_tag_index += 1
- return
-
- annotation = AnnotationTag(self.next_tag_index, None)
- if jannotation.pop('generated', False):
- self.token_list.pop()
- annotation.start_index -= 1
- if self.previous_element_class == HtmlTag:
- annotation.annotation_text = AnnotationText('')
- else:
- annotation.annotation_text = AnnotationText(self.prev_data)
- if self._read_bool_template_attribute(html_tag, "ignore") \
- or self._read_bool_template_attribute(html_tag, "ignore-beneath"):
- ignored = self.ignored_regions.pop()
- self.ignored_regions.append((ignored[0]-1, ignored[1]))
-
- self.extra_required_attrs.extend(jannotation.pop('required', []))
-
- attribute_annotations = jannotation.pop('annotations', {}).items()
- for extract_attribute, tag_value in attribute_annotations:
- if extract_attribute == 'content':
- annotation.surrounds_attribute = tag_value
- else:
- annotation.tag_attributes.append((extract_attribute, tag_value))
-
- variant_id = jannotation.pop('variant', 0)
- if variant_id > 0:
- if annotation.surrounds_attribute is not None:
- self.variant_stack.append(variant_id)
- else:
- annotation.variant_id = variant_id
-
- annotation.metadata = jannotation
-
- if annotation.annotation_text is None:
- self.next_tag_index += 1
- if self.variant_stack and annotation.variant_id is None:
- variant_id = self.variant_stack[-1]
- if variant_id == '0':
- variant_id = None
- annotation.variant_id = variant_id
-
- # look for a closing tag if the content is important
- if annotation.surrounds_attribute:
- self.labelled_tag_stacks[html_tag.tag].append(annotation)
- else:
- annotation.end_index = annotation.start_index + 1
- self.annotations.append(annotation)
-
- def _handle_close_tag(self, html_tag):
-
- if self.unpairedtag_stack:
- if html_tag.tag == self.unpairedtag_stack[-1]:
- self.unpairedtag_stack.pop()
- else:
- self._close_unpaired_tag()
- ignored_tags = self.ignored_tag_stacks.get(html_tag.tag)
- if ignored_tags is not None:
- tag = ignored_tags.pop()
- if isinstance(tag, HtmlTag):
- for i in range(-1, -len(self.ignored_regions) - 1, -1):
- if self.ignored_regions[i][1] is None:
- self.ignored_regions[i] = (self.ignored_regions[i][0], self.next_tag_index)
- break
- if len(ignored_tags) == 0:
- del self.ignored_tag_stacks[html_tag.tag]
-
- if html_tag.tag in self.replacement_stacks:
- replacement = self.replacement_stacks[html_tag.tag].pop()
- if replacement:
- self.token_list.pop()
- self._add_token(replacement, html_tag.tag_type, html_tag.start, html_tag.end)
- if len(self.replacement_stacks[html_tag.tag]) == 0:
- del self.replacement_stacks[html_tag.tag]
-
- labelled_tags = self.labelled_tag_stacks.get(html_tag.tag)
- if labelled_tags is None:
- self.next_tag_index += 1
- return
- annotation = labelled_tags.pop()
- if annotation is None:
- self.next_tag_index += 1
- else:
- annotation.end_index = self.next_tag_index
- self.annotations.append(annotation)
- if annotation.annotation_text is not None:
- self.token_list.pop()
- self.last_text_region = annotation
- else:
- self.next_tag_index += 1
- if len(labelled_tags) == 0:
- del self.labelled_tag_stacks[html_tag.tag]
- if annotation.variant_id and self.variant_stack:
- prev = self.variant_stack.pop()
- if prev != annotation.variant_id:
- raise ValueError("unbalanced variant annotation tags")
-
- def handle_data(self, html_data_fragment):
- fragment_text = self.html_page.fragment_data(html_data_fragment)
- self._process_text(fragment_text)
-
- def _process_text(self, text):
- if self.last_text_region is not None:
- self.last_text_region.annotation_text.follow_text = text
- self.last_text_region = None
- self.prev_data = text
-
- def to_template(self):
- """create a TemplatePage from the data fed to this parser"""
- return TemplatePage(self.token_dict, self.token_list, self.annotations,
- self.html_page.page_id, self.ignored_regions, self.extra_required_attrs)
-
-class ExtractionPageParser(InstanceLearningParser):
- """Parse an HTML page for extraction using the instance based learning
- algorithm
-
- This needs to extract the tokens in a similar way to LabelledPageParser,
- it needs to also maintain a mapping from token index to the original content
- so that once regions are identified, the original content can be extracted.
- """
- def __init__(self, token_dict):
- InstanceLearningParser.__init__(self, token_dict)
- self.page_data = []
- self.token_start_index = []
- self.token_follow_index = []
- self.tag_attrs = {}
-
- def _add_token(self, token, token_type, start, end):
- InstanceLearningParser._add_token(self, token, token_type, start, end)
- self.token_start_index.append(start)
- self.token_follow_index.append(end)
-
- def handle_tag(self, html_tag):
- if html_tag.attributes:
- self.tag_attrs[len(self.token_list) - 1] = html_tag.attributes
-
- def to_extraction_page(self):
- return ExtractionPage(self.html_page.body, self.token_dict, array(self.token_list),
- self.token_start_index, self.token_follow_index, self.tag_attrs)
diff --git a/scrapy/contrib/ibl/extraction/regionextract.py b/scrapy/contrib/ibl/extraction/regionextract.py
deleted file mode 100644
index db5eb2a38..000000000
--- a/scrapy/contrib/ibl/extraction/regionextract.py
+++ /dev/null
@@ -1,627 +0,0 @@
-"""
-Region Extract
-
-Custom extraction for regions in a document
-"""
-import re
-import operator
-import copy
-import pprint
-import cStringIO
-from itertools import groupby
-
-from numpy import array
-
-from scrapy.contrib.ibl.descriptor import FieldDescriptor
-from scrapy.contrib.ibl.extraction.similarity import (similar_region,
- longest_unique_subsequence, common_prefix)
-from scrapy.contrib.ibl.extraction.pageobjects import AnnotationTag, LabelledRegion
-
-def build_extraction_tree(template, type_descriptor, trace=True):
- """Build a tree of region extractors corresponding to the
- template
- """
- attribute_map = type_descriptor.attribute_map if type_descriptor else None
- extractors = BasicTypeExtractor.create(template.annotations, attribute_map)
- if trace:
- extractors = TraceExtractor.apply(template, extractors)
- for cls in (AdjacentVariantExtractor, RepeatedDataExtractor, AdjacentVariantExtractor, RepeatedDataExtractor,
- RecordExtractor):
- extractors = cls.apply(template, extractors)
- if trace:
- extractors = TraceExtractor.apply(template, extractors)
-
- return TemplatePageExtractor(template, extractors)
-
-_ID = lambda x: x
-_DEFAULT_DESCRIPTOR = FieldDescriptor('none', None)
-
-def _labelled(obj):
- """
- Returns labelled element of the object (extractor or labelled region)
- """
- if hasattr(obj, "annotation"):
- return obj.annotation
- return obj
-
-def _compose(f, g):
- """given unary functions f and g, return a function that computes f(g(x))
- """
- def _exec(x):
- ret = g(x)
- return f(ret) if ret is not None else None
- return _exec
-
-class BasicTypeExtractor(object):
- """The BasicTypeExtractor extracts single attributes corresponding to
- annotations.
-
- For example:
- >>> from scrapy.contrib.ibl.extraction.pageparsing import parse_strings
- >>> template, page = parse_strings( \
- u'x ', u' a name ')
- >>> ex = BasicTypeExtractor(template.annotations[0])
- >>> ex.extract(page, 0, 1, None)
- [(u'name', u' a name')]
-
- It supports attribute descriptors
- >>> descriptor = FieldDescriptor('name', None, lambda x: x.strip())
- >>> ex = BasicTypeExtractor(template.annotations[0], {'name': descriptor})
- >>> ex.extract(page, 0, 1, None)
- [(u'name', u'a name')]
-
- It supports ignoring regions
- >>> template, page = parse_strings(\
- u'x xx
',\
- u'a name id-9
')
- >>> ex = BasicTypeExtractor(template.annotations[0])
- >>> ex.extract(page, 0, 3, [LabelledRegion(*(1,2))])
- [(u'name', u'a name')]
- """
-
- def __init__(self, annotation, attribute_descriptors=None):
- self.annotation = annotation
- if attribute_descriptors is None:
- attribute_descriptors = {}
-
- if annotation.surrounds_attribute:
- descriptor = attribute_descriptors.get(annotation.surrounds_attribute)
- if descriptor:
- self.content_validate = descriptor.extractor
- self.allow_markup = descriptor.allow_markup
- else:
- self.content_validate = _ID
- self.allow_markup = False
- self.extract = self._extract_content
-
- if annotation.tag_attributes:
- self.tag_data = []
- for (tag_attr, extraction_attr) in annotation.tag_attributes:
- descriptor = attribute_descriptors.get(extraction_attr)
- extractf = descriptor.extractor if descriptor else _ID
- self.tag_data.append((extractf, tag_attr, extraction_attr))
-
- self.extract = self._extract_both if \
- annotation.surrounds_attribute else self._extract_attribute
-
- def _extract_both(self, page, start_index, end_index, ignored_regions=None):
- return self._extract_content(page, start_index, end_index, ignored_regions) + \
- self._extract_attribute(page, start_index, end_index, ignored_regions)
-
- def _extract_content(self, extraction_page, start_index, end_index, ignored_regions=None):
- # we might want to add opening/closing ul/ol/table if we have the
- # middle of a region. This would require support in the scrapy
- # cleansing.
- complete_data = ""
- start = start_index
- end = ignored_regions[0].start_index if ignored_regions else end_index
- while start is not None:
- if self.allow_markup:
- data = extraction_page.html_between_tokens(start, end)
- else:
- data = extraction_page.text_between_tokens(start, end)
- complete_data += data
- if ignored_regions:
- start = ignored_regions[0].end_index
- ignored_regions.pop(0)
- end = ignored_regions[0].start_index if ignored_regions else end_index
- else:
- start = None
- complete_data = self.content_validate(complete_data)
- return [(self.annotation.surrounds_attribute, complete_data)] if complete_data else []
-
- def _extract_attribute(self, extraction_page, start_index, end_index, ignored_regions=None):
- data = []
- for (f, ta, ea) in self.tag_data:
- tag_value = extraction_page.tag_attribute(start_index, ta)
- if tag_value:
- extracted = f(tag_value)
- if extracted is not None:
- data.append((ea, extracted))
- return data
-
- @classmethod
- def create(cls, annotations, attribute_descriptors=None):
- """Create a list of basic extractors from the given annotations
- and attribute descriptors
- """
- if attribute_descriptors is None:
- attribute_descriptors = {}
- return [cls._create_basic_extractor(annotation, attribute_descriptors) \
- for annotation in annotations \
- if annotation.surrounds_attribute or annotation.tag_attributes]
-
- @staticmethod
- def _create_basic_extractor(annotation, attribute_descriptors):
- """Create a basic type extractor for the annotation"""
- text_region = annotation.annotation_text
- if text_region is not None:
- region_extract = TextRegionDataExtractor(text_region.start_text,
- text_region.follow_text).extract
- # copy attribute_descriptors and add the text extractor
- descriptor_copy = dict(attribute_descriptors)
- attr_descr = descriptor_copy.get(annotation.surrounds_attribute,
- _DEFAULT_DESCRIPTOR)
- attr_descr = copy.copy(attr_descr)
- attr_descr.extractor = _compose(attr_descr.extractor, region_extract)
- descriptor_copy[annotation.surrounds_attribute] = attr_descr
- attribute_descriptors = descriptor_copy
- return BasicTypeExtractor(annotation, attribute_descriptors)
-
- def extracted_item(self):
- """key used to identify the item extracted"""
- return (self.annotation.surrounds_attribute, self.annotation.tag_attributes)
-
- def __repr__(self):
- return str(self)
-
- def __str__(self):
- messages = ['BasicTypeExtractor(']
- if self.annotation.surrounds_attribute:
- messages += [self.annotation.surrounds_attribute, ': ',
- 'html content' if self.allow_markup else 'text content',
- ]
- if self.content_validate != _ID:
- messages += [', extracted with \'',
- self.content_validate.__name__, '\'']
-
- if self.annotation.tag_attributes:
- if self.annotation.surrounds_attribute:
- messages.append(';')
- for (f, ta, ea) in self.tag_data:
- messages += [ea, ': tag attribute "', ta, '"']
- if f != _ID:
- messages += [', validated by ', str(f)]
- messages.append(", template[%s:%s])" % \
- (self.annotation.start_index, self.annotation.end_index))
- return ''.join(messages)
-
-class RepeatedDataExtractor(object):
- """Data extractor for handling repeated data"""
-
- def __init__(self, prefix, suffix, extractors):
- self.prefix = array(prefix)
- self.suffix = array(suffix)
- self.extractor = copy.copy(extractors[0])
- self.annotation = copy.copy(self.extractor.annotation)
- self.annotation.end_index = extractors[-1].annotation.end_index
-
- def extract(self, page, start_index, end_index, ignored_regions):
- """repeatedly find regions bounded by the repeated
- prefix and suffix and extract them
- """
- prefixlen = len(self.prefix)
- suffixlen = len(self.suffix)
- index = max(0, start_index - prefixlen)
- max_index = min(len(page.page_tokens) - suffixlen, end_index + len(self.suffix))
- max_start_index = max_index - prefixlen
- extracted = []
- while index <= max_start_index:
- prefix_end = index + prefixlen
- if (page.page_tokens[index:prefix_end] == self.prefix).all():
- for peek in xrange(prefix_end, max_index):
- if (page.page_tokens[peek:peek + suffixlen] \
- == self.suffix).all():
- extracted += self.extractor.extract(page,
- prefix_end - 1, peek, ignored_regions)
- index = max(peek, index + 1)
- break
- else:
- break
- else:
- index += 1
- return extracted
-
- @staticmethod
- def apply(template, extractors):
- tokens = template.page_tokens
- output_extractors = []
- group_key = lambda x: x.extracted_item()
- for extr_key, extraction_group in groupby(extractors, group_key):
- extraction_group = list(extraction_group)
- if extr_key is None or len(extraction_group) == 1:
- output_extractors += extraction_group
- continue
-
- separating_tokens = [ \
- tokens[x.annotation.end_index:y.annotation.start_index+1] \
- for (x, y) in zip(extraction_group[:-1], extraction_group[1:])]
-
- # calculate the common prefix
- group_start = extraction_group[0].annotation.start_index
- prefix_start = max(0, group_start - len(separating_tokens[0]))
- first_prefix = tokens[prefix_start:group_start+1]
- prefixes = [first_prefix] + separating_tokens
- prefix_pattern = list(reversed(
- common_prefix(*map(reversed, prefixes))))
-
- # calculate the common suffix
- group_end = extraction_group[-1].annotation.end_index
- last_suffix = tokens[group_end:group_end + \
- len(separating_tokens[-1])]
- suffixes = separating_tokens + [last_suffix]
- suffix_pattern = common_prefix(*suffixes)
-
- # create a repeated data extractor, if there is a suitable
- # prefix and suffix. (TODO: tune this heuristic)
- matchlen = len(prefix_pattern) + len(suffix_pattern)
- if matchlen >= len(separating_tokens):
- group_extractor = RepeatedDataExtractor(prefix_pattern,
- suffix_pattern, extraction_group)
- output_extractors.append(group_extractor)
- else:
- output_extractors += extraction_group
- return output_extractors
-
- def extracted_item(self):
- """key used to identify the item extracted"""
- return self.extractor.extracted_item()
-
- def __repr__(self):
- return "Repeat(%r)" % self.extractor
-
- def __str__(self):
- return "Repeat(%s)" % self.extractor
-
-class TransposedDataExtractor(object):
- """ """
- pass
-
-_namef = operator.itemgetter(0)
-_valuef = operator.itemgetter(1)
-def _attrs2dict(attributes):
- """convert a list of attributes (name, value) tuples
- into a dict of lists.
-
- For example:
- >>> l = [('name', 'sofa'), ('colour', 'red'), ('colour', 'green')]
- >>> _attrs2dict(l) == {'name': ['sofa'], 'colour': ['red', 'green']}
- True
- """
- grouped_data = groupby(sorted(attributes, key=_namef), _namef)
- return dict((name, map(_valuef, data)) for (name, data) in grouped_data)
-
-class RecordExtractor(object):
- """The RecordExtractor will extract records given annotations.
-
- It looks for a similar region in the target document, using the ibl
- similarity algorithm. The annotations are partitioned by the first similar
- region found and searched recursively.
-
- Records are represented as dicts mapping attribute names to lists
- containing their values.
-
- For example:
- >>> from scrapy.contrib.ibl.extraction.pageparsing import parse_strings
- >>> template, page = parse_strings( \
- u'x ' + \
- u'y
', \
- u'name description
')
- >>> basic_extractors = map(BasicTypeExtractor, template.annotations)
- >>> ex = RecordExtractor.apply(template, basic_extractors)[0]
- >>> ex.extract(page)
- [{u'description': [u'description'], u'name': [u'name']}]
- """
-
- def __init__(self, extractors, template_tokens):
- """Construct a RecordExtractor for the given annotations and their
- corresponding region extractors
- """
- self.extractors = extractors
- self.template_tokens = template_tokens
- self.template_ignored_regions = []
- start_index = min(e.annotation.start_index for e in extractors)
- end_index = max(e.annotation.end_index for e in extractors)
- self.annotation = AnnotationTag(start_index, end_index)
-
- def extract(self, page, start_index=0, end_index=None, ignored_regions=None):
- """extract data from an extraction page
-
- The region in the page to be extracted from may be specified using
- start_index and end_index
- """
- ignored_regions = [i if isinstance(i, LabelledRegion) else LabelledRegion(*i) for i in (ignored_regions or [])]
- region_elements = sorted(self.extractors + ignored_regions, key=lambda x: _labelled(x).start_index)
- _, _, attributes = self._doextract(page, region_elements, start_index,
- end_index)
- # collect variant data, maintaining the order of variants
- variant_ids = []; variants = {}; items = []
- for k, v in attributes:
- if isinstance(k, int):
- if k in variants:
- variants[k] += v
- else:
- variant_ids.append(k)
- variants[k] = v
- else:
- items.append((k, v))
-
- variant_records = [('variants', _attrs2dict(variants[vid])) \
- for vid in variant_ids]
- items += variant_records
- return [_attrs2dict(items)]
-
- def _doextract(self, page, region_elements, start_index, end_index, nested_regions=None, ignored_regions=None):
- """Carry out extraction of records using the given annotations
- in the page tokens bounded by start_index and end_index
- """
- # reorder extractors leaving nested ones for the end and separating
- # ignore regions
- nested_regions = nested_regions or []
- ignored_regions = ignored_regions or []
- first_region, following_regions = region_elements[0], region_elements[1:]
- while following_regions and _labelled(following_regions[0]).start_index \
- < _labelled(first_region).end_index:
- region = following_regions.pop(0)
- labelled = _labelled(region)
- if isinstance(labelled, AnnotationTag) or (nested_regions and \
- _labelled(nested_regions[-1]).start_index < labelled.start_index \
- < _labelled(nested_regions[-1]).end_index):
- nested_regions.append(region)
- else:
- ignored_regions.append(region)
- extracted_data = []
- # end_index is inclusive, but similar_region treats it as exclusive
- end_region = None if end_index is None else end_index + 1
- labelled = _labelled(first_region)
- score, pindex, sindex = \
- similar_region(page.page_tokens, self.template_tokens,
- labelled, start_index, end_region)
- if score > 0:
- if isinstance(labelled, AnnotationTag):
- similar_ignored_regions = []
- start = pindex
- for i in ignored_regions:
- s, p, e = similar_region(page.page_tokens, self.template_tokens, \
- i, start, sindex)
- if s > 0:
- similar_ignored_regions.append(LabelledRegion(*(p, e)))
- start = e or start
- extracted_data = first_region.extract(page, pindex, sindex, similar_ignored_regions)
- if extracted_data:
- if first_region.annotation.variant_id:
- extracted_data = [(first_region.annotation.variant_id, extracted_data)]
-
- if nested_regions:
- _, _, nested_data = self._doextract(page, nested_regions, pindex, sindex)
- extracted_data += nested_data
- if following_regions:
- _, _, following_data = self._doextract(page, following_regions, sindex or start_index, end_index)
- extracted_data += following_data
-
- elif following_regions:
- end_index, _, following_data = self._doextract(page, following_regions, start_index, end_index)
- if end_index is not None:
- pindex, sindex, extracted_data = self._doextract(page, [first_region], start_index, end_index - 1, nested_regions, ignored_regions)
- extracted_data += following_data
- elif nested_regions:
- _, _, nested_data = self._doextract(page, nested_regions, start_index, end_index)
- extracted_data += nested_data
- return pindex, sindex, extracted_data
-
- @classmethod
- def apply(cls, template, extractors):
- return [cls(extractors, template.page_tokens)]
-
- def extracted_item(self):
- return [self.__class__.__name__] + \
- sorted(e.extracted_item() for e in self.extractors)
-
- def __repr__(self):
- return str(self)
-
- def __str__(self):
- stream = cStringIO.StringIO()
- pprint.pprint(self.extractors, stream)
- stream.seek(0)
- template_data = stream.read()
- if template_data:
- return "%s[\n%s\n]" % (self.__class__.__name__, template_data)
- return "%s[none]" % (self.__class__.__name__)
-
-class AdjacentVariantExtractor(RecordExtractor):
- """Extractor for variants
-
- This simply extends the RecordExtractor to output data in a "variants"
- attribute.
-
- The "apply" method will only apply to variants whose items are all adjacent and
- it will appear as one record so that it can be handled by the RepeatedDataExtractor.
- """
-
- def extract(self, page, start_index=0, end_index=None, ignored_regions=None):
- records = RecordExtractor.extract(self, page, start_index, end_index, ignored_regions)
- return [('variants', r['variants'][0]) for r in records if r]
-
- @classmethod
- def apply(cls, template, extractors):
- adjacent_variants = set([])
- variantf = lambda x: x.annotation.variant_id
- for vid, egroup in groupby(extractors, variantf):
- if not vid:
- continue
- if vid in adjacent_variants:
- adjacent_variants.remove(vid)
- else:
- adjacent_variants.add(vid)
- new_extractors = []
- for variant, group_seq in groupby(extractors, variantf):
- group_seq = list(group_seq)
- if variant in adjacent_variants:
- record_extractor = AdjacentVariantExtractor(group_seq, template.page_tokens)
- new_extractors.append(record_extractor)
- else:
- new_extractors += group_seq
- return new_extractors
-
- def __repr__(self):
- return str(self)
-
-class TraceExtractor(object):
- """Extractor that wraps other extractors and prints an execution
- trace of the extraction process to aid debugging
- """
-
- def __init__(self, traced, template):
- self.traced = traced
- self.annotation = traced.annotation
- tstart = traced.annotation.start_index
- tend = traced.annotation.end_index
- self.tprefix = " ".join([template.token_dict.token_string(t)
- for t in template.page_tokens[tstart-4:tstart+1]])
- self.tsuffix = " ".join([template.token_dict.token_string(t)
- for t in template.page_tokens[tend:tend+5]])
-
- def summarize_trace(self, page, start, end, ret):
- text_start = page.token_follow_indexes[start]
- text_end = page.token_start_indexes[end or -1]
- page_snippet = "(...%s)%s(%s...)" % (
- page.text[text_start-50:text_start].replace('\n', ' '),
- page.text[text_start:text_end],
- page.text[text_end:text_end+50].replace('\n', ' '))
- pre_summary = "\nstart %s page[%s:%s]\n" % (self.traced.__class__.__name__, start, end)
- post_summary = """
-%s page[%s:%s]
-
-html
-%s
-
-annotation
-...%s
-%s
-%s...
-
-extracted
-%s
- """ % (self.traced.__class__.__name__, start, end, page_snippet,
- self.tprefix, self.annotation, self.tsuffix, [r for r in ret if 'trace' not in r])
- return pre_summary, post_summary
-
- def extract(self, page, start, end, ignored_regions):
- ret = self.traced.extract(page, start, end, ignored_regions)
- if not ret:
- return []
-
- # handle records by inserting a trace and combining with variant traces
- if len(ret) == 1 and isinstance(ret[0], dict):
- item = ret[0]
- trace = item.pop('trace', [])
- variants = item.get('variants', ())
- for variant in variants:
- trace += variant.pop('trace', [])
- pre_summary, post_summary = self.summarize_trace(page, start, end, ret)
- item['trace'] = [pre_summary] + trace + [post_summary]
- return ret
-
- pre_summary, post_summary = self.summarize_trace(page, start, end, ret)
- return [('trace', pre_summary)] + ret + [('trace', post_summary)]
-
- @staticmethod
- def apply(template, extractors):
- output = []
- for extractor in extractors:
- if not isinstance(extractor, TraceExtractor):
- extractor = TraceExtractor(extractor, template)
- output.append(extractor)
- return output
-
- def extracted_item(self):
- return self.traced.extracted_item()
-
- def __repr__(self):
- return "Trace(%s)" % repr(self.traced)
-
-class TemplatePageExtractor(object):
- """Top level extractor for a template page"""
-
- def __init__(self, template, extractors):
- # fixme: handle multiple items per page
- self.extractor = extractors[0]
- self.template = template
-
- def extract(self, page, start_index=0, end_index=None):
- return self.extractor.extract(page, start_index, end_index, self.template.ignored_regions)
-
- def __repr__(self):
- return repr(self.extractor)
-
- def __str__(self):
- return str(self.extractor)
-
-# Based on nltk's WordPunctTokenizer
-_tokenize = re.compile(r'\w+|[^\w\s]+', re.UNICODE | re.MULTILINE | re.DOTALL).findall
-
-class TextRegionDataExtractor(object):
- """Data Extractor for extracting text fragments from within a larger
- body of text. It extracts based on the longest unique prefix and suffix.
-
- for example:
- >>> extractor = TextRegionDataExtractor('designed by ', '.')
- >>> extractor.extract("by Marc Newson.")
- 'Marc Newson'
-
- Both prefix and suffix are optional:
- >>> extractor = TextRegionDataExtractor('designed by ')
- >>> extractor.extract("by Marc Newson.")
- 'Marc Newson.'
- >>> extractor = TextRegionDataExtractor(suffix='.')
- >>> extractor.extract("by Marc Newson.")
- 'by Marc Newson'
-
- It requires a minimum match of at least one word or punctuation character:
- >>> extractor = TextRegionDataExtractor('designed by')
- >>> extractor.extract("y Marc Newson.") is None
- True
- """
- def __init__(self, prefix=None, suffix=None):
- self.prefix = (prefix or '')[::-1]
- self.suffix = suffix or ''
- self.minprefix = self.minmatch(self.prefix)
- self.minsuffix = self.minmatch(self.suffix)
-
- @staticmethod
- def minmatch(matchstring):
- """the minimum number of characters that should match in order
- to consider it a match for that string.
-
- This uses the last word of punctuation character
- """
- tokens = _tokenize(matchstring or '')
- return len(tokens[0]) if tokens else 0
-
- def extract(self, text):
- """attempt to extract a substring from the text"""
- pref_index = 0
- if self.minprefix > 0:
- rev_idx, plen = longest_unique_subsequence(text[::-1], self.prefix)
- if plen < self.minprefix:
- return None
- pref_index = -rev_idx
- if self.minsuffix == 0:
- return text[pref_index:]
- sidx, slen = longest_unique_subsequence(text[pref_index:], self.suffix)
- if slen < self.minsuffix:
- return None
- return text[pref_index:pref_index + sidx]
-
-
diff --git a/scrapy/contrib/ibl/extraction/similarity.py b/scrapy/contrib/ibl/extraction/similarity.py
deleted file mode 100644
index 9bb8e24c3..000000000
--- a/scrapy/contrib/ibl/extraction/similarity.py
+++ /dev/null
@@ -1,136 +0,0 @@
-"""
-Similarity calculation for Instance based extraction algorithm.
-"""
-from itertools import izip, count
-from operator import itemgetter
-from heapq import nlargest
-
-def common_prefix_length(a, b):
- """Calculate the length of the common prefix in both sequences passed.
-
- For example, the common prefix in this example is [1, 3]
- >>> common_prefix_length([1, 3, 4], [1, 3, 5, 1])
- 2
-
- If there is no common prefix, 0 is returned
- >>> common_prefix_length([1], [])
- 0
- """
- i = -1
- for i, x, y in izip(count(), a, b):
- if x != y:
- return i
- return i + 1
-
-def common_prefix(*sequences):
- """determine the common prefix of all sequences passed
-
- For example:
- >>> common_prefix('abcdef', 'abc', 'abac')
- ['a', 'b']
- """
- prefix = []
- for sample in izip(*sequences):
- first = sample[0]
- if all(x == first for x in sample[1:]):
- prefix.append(first)
- else:
- break
- return prefix
-
-def longest_unique_subsequence(to_search, subsequence, range_start=0,
- range_end=None):
- """Find the longest unique subsequence of items in a list or array. This
- searches the to_search list or array looking for the longest overlapping
- match with subsequence. If the largest match is unique (there is no other
- match of equivalent length), the index and length of match is returned. If
- there is no match, (None, None) is returned.
-
- Please see section 3.2 of Extracting Web Data Using Instance-Based
- Learning by Yanhong Zhai and Bing Liu
-
- For example, the longest match occurs at index 2 and has length 3
- >>> to_search = [6, 3, 2, 4, 3, 2, 5]
- >>> longest_unique_subsequence(to_search, [2, 4, 3])
- (2, 3)
-
- When there are two equally long subsequences, it does not generate a match
- >>> longest_unique_subsequence(to_search, [3, 2])
- (None, None)
-
- range_start and range_end specify a range in which the match must begin
- >>> longest_unique_subsequence(to_search, [3, 2], 3)
- (4, 2)
- >>> longest_unique_subsequence(to_search, [3, 2], 0, 2)
- (1, 2)
- """
- startval = subsequence[0]
- if range_end is None:
- range_end = len(to_search)
-
- # the comparison to startval ensures only matches of length >= 1 and
- # reduces the number of calls to the common_length function
- matches = ((i, common_prefix_length(to_search[i:], subsequence)) \
- for i in xrange(range_start, range_end) if startval == to_search[i])
- best2 = nlargest(2, matches, key=itemgetter(1))
- # if there is a single unique best match, return that
- if len(best2) == 1 or len(best2) == 2 and best2[0][1] != best2[1][1]:
- return best2[0]
- return None, None
-
-def similar_region(extracted_tokens, template_tokens, labelled_region,
- range_start=0, range_end=None):
- """Given a labelled section in a template, identify a similar region
- in the extracted tokens.
-
- The start and end index of the similar region in the extracted tokens
- is returned.
-
- This will return a tuple containing:
- (match score, start index, end index)
- where match score is the sum of the length of the matching prefix and
- suffix. If there is no unique match, (0, None, None) will be returned.
-
- start_index and end_index specify a range in which the match must begin
- """
- data_length = len(extracted_tokens)
- if range_end is None:
- range_end = data_length
- # calculate the prefix score by finding a longest subsequence in
- # reverse order
- reverse_prefix = template_tokens[labelled_region.start_index::-1]
- reverse_tokens = extracted_tokens[::-1]
- (rpi, pscore) = longest_unique_subsequence(reverse_tokens, reverse_prefix,
- data_length - range_end, data_length - range_start)
-
- # None means nothing exracted. Index 0 means there cannot be a suffix.
- if not rpi:
- return 0, None, None
-
- # convert to an index from the start instead of in reverse
- prefix_index = len(extracted_tokens) - rpi - 1
-
- if labelled_region.end_index is None:
- return pscore, prefix_index, None
-
- suffix = template_tokens[labelled_region.end_index:]
-
- # if it's not a paired tag, use the best match between prefix & suffix
- if labelled_region.start_index == labelled_region.end_index:
- (match_index, sscore) = longest_unique_subsequence(extracted_tokens,
- suffix, prefix_index, range_end)
- if match_index == prefix_index:
- return (pscore + sscore, prefix_index, match_index)
- elif pscore > sscore:
- return pscore, prefix_index, prefix_index
- elif sscore > pscore:
- return sscore, match_index, match_index
- return 0, None, None
-
- # calculate the suffix match on the tokens following the prefix. We could
- # consider the whole page and require a good match.
- (match_index, sscore) = longest_unique_subsequence(extracted_tokens,
- suffix, prefix_index + 1, range_end)
- if match_index is None:
- return 0, None, None
- return (pscore + sscore, prefix_index, match_index)
diff --git a/scrapy/contrib/ibl/extractors.py b/scrapy/contrib/ibl/extractors.py
deleted file mode 100644
index 9c460df10..000000000
--- a/scrapy/contrib/ibl/extractors.py
+++ /dev/null
@@ -1,156 +0,0 @@
-"""
-Extractors for attributes
-"""
-import re
-import urlparse
-
-from scrapy.utils.markup import remove_entities
-from scrapy.utils.url import safe_url_string
-
-#FIXME: the use of "." needs to be localized
-_NUMERIC_ENTITIES = re.compile("([0-9]+)(?:;|\s)", re.U)
-_PRICE_NUMBER_RE = re.compile('(?:^|[^a-zA-Z0-9])(\d+(?:\.\d+)?)(?:$|[^a-zA-Z0-9])')
-_NUMBER_RE = re.compile('(\d+(?:\.\d+)?)')
-
-_IMAGES = (
- 'mng', 'pct', 'bmp', 'gif', 'jpg', 'jpeg', 'png', 'pst', 'psp', 'tif',
- 'tiff', 'ai', 'drw', 'dxf', 'eps', 'ps', 'svg',
-)
-
-_IMAGES_TYPES = '|'.join(_IMAGES)
-_CSS_IMAGERE = re.compile("background(?:-image)?\s*:\s*url\((.*?)\)", re.I)
-_BASE_PATH_RE = "/?(?:[^/]+/)*(?:.+%s)"
-_IMAGE_PATH_RE = re.compile(_BASE_PATH_RE % '\.(?:%s)' % _IMAGES_TYPES, re.I)
-_GENERIC_PATH_RE = re.compile(_BASE_PATH_RE % '', re.I)
-
-def text(txt):
- stripped = txt.strip() if txt else None
- if stripped:
- return stripped
-
-def contains_any_numbers(txt):
- """text that must contain at least one number
- >>> contains_any_numbers('foo')
- >>> contains_any_numbers('$67 at 15% discount')
- '$67 at 15% discount'
- """
- if _NUMBER_RE.search(txt) is not None:
- return txt
-
-def contains_prices(txt):
- """text must contain a number that is not joined to text"""
- if _PRICE_NUMBER_RE.findall(txt) is not None:
- return txt
-
-def contains_numbers(txt, count=1):
- """Must contain a certain amount of numbers
-
- >>> contains_numbers('foo', 2)
- >>> contains_numbers('this 1 has 2 numbers', 2)
- 'this 1 has 2 numbers'
- """
- numbers = _NUMBER_RE.findall(txt)
- if len(numbers) == count:
- return txt
-
-def extract_number(txt):
- """Extract a numeric value.
-
- This will fail if more than one numeric value is present.
-
- >>> extract_number(' 45.3')
- '45.3'
- >>> extract_number(' 45.3, 7')
-
- It will handle unescaped entities:
- >>> extract_number(u'£129.99')
- u'129.99'
- """
- txt = _NUMERIC_ENTITIES.sub(lambda m: unichr(int(m.groups()[0])), txt)
- numbers = _NUMBER_RE.findall(txt)
- if len(numbers) == 1:
- return numbers[0]
-
-def url(txt):
- """convert text to a url
-
- this is quite conservative, since relative urls are supported
- """
- txt = txt.strip("\t\r\n '\"")
- if txt:
- return txt
-
-def image_url(txt):
- """convert text to a url
-
- this is quite conservative, since relative urls are supported
- Example:
-
- >>> image_url('')
-
- >>> image_url(' ')
-
- >>> image_url(' \\n\\n ')
-
- >>> image_url('foo-bar.jpg')
- ['foo-bar.jpg']
- >>> image_url('/images/main_logo12.gif')
- ['/images/main_logo12.gif']
- >>> image_url("http://www.image.com/image.jpg")
- ['http://www.image.com/image.jpg']
- >>> image_url("http://www.domain.com/path1/path2/path3/image.jpg")
- ['http://www.domain.com/path1/path2/path3/image.jpg']
- >>> image_url("/path1/path2/path3/image.jpg")
- ['/path1/path2/path3/image.jpg']
- >>> image_url("path1/path2/image.jpg")
- ['path1/path2/image.jpg']
- >>> image_url("background-image : url(http://www.site.com/path1/path2/image.jpg)")
- ['http://www.site.com/path1/path2/image.jpg']
- >>> image_url("background-image : url('http://www.site.com/path1/path2/image.jpg')")
- ['http://www.site.com/path1/path2/image.jpg']
- >>> image_url('background-image : url("http://www.site.com/path1/path2/image.jpg")')
- ['http://www.site.com/path1/path2/image.jpg']
- >>> image_url("background : url(http://www.site.com/path1/path2/image.jpg)")
- ['http://www.site.com/path1/path2/image.jpg']
- >>> image_url("background : url('http://www.site.com/path1/path2/image.jpg')")
- ['http://www.site.com/path1/path2/image.jpg']
- >>> image_url('background : url("http://www.site.com/path1/path2/image.jpg")')
- ['http://www.site.com/path1/path2/image.jpg']
- >>> image_url('/getimage.php?image=totalgardens/outbbq2_400.jpg&type=prod&resizeto=350')
- ['/getimage.php?image=totalgardens/outbbq2_400.jpg&type=prod&resizeto=350']
- >>> image_url('http://www.site.com/getimage.php?image=totalgardens/outbbq2_400.jpg&type=prod&resizeto=350')
- ['http://www.site.com/getimage.php?image=totalgardens/outbbq2_400.jpg&type=prod&resizeto=350']
- >>> image_url('http://s7d4.scene7.com/is/image/Kohler/jaa03267?hei=425&wid=457&op_usm=2,1,2,1&qlt=80')
- ['http://s7d4.scene7.com/is/image/Kohler/jaa03267?hei=425&wid=457&op_usm=2,1,2,1&qlt=80']
- >>> image_url('../image.aspx?thumb=true&boxSize=175&img=Unknoportrait[1].jpg')
- ['../image.aspx?thumb=true&boxSize=175&img=Unknoportrait%5B1%5D.jpg']
- >>> image_url('http://www.sundancecatalog.com/mgen/catalog/test.ms?args=%2245932|MERIDIAN+PENDANT|.jpg%22&is=336,336,0xffffff')
- ['http://www.sundancecatalog.com/mgen/catalog/test.ms?args=%2245932|MERIDIAN+PENDANT|.jpg%22&is=336,336,0xffffff']
- >>> image_url('http://www.site.com/image.php')
- ['http://www.site.com/image.php']
- >>> image_url('background-image:URL(http://s7d5.scene7.com/is/image/wasserstrom/165133?wid=227&hei=227&defaultImage=noimage_wasserstrom)')
- ['http://s7d5.scene7.com/is/image/wasserstrom/165133?wid=227&hei=227&defaultImage=noimage_wasserstrom']
-
- """
- txt = url(txt)
- imgurl = None
- if txt:
- # check if the text is style content
- m = _CSS_IMAGERE.search(txt)
- txt = m.groups()[0] if m else txt
- parsed = urlparse.urlparse(txt)
- path = None
- m = _IMAGE_PATH_RE.search(parsed.path)
- if m:
- path = m.group()
- elif parsed.query:
- m = _GENERIC_PATH_RE.search(parsed.path)
- if m:
- path = m.group()
- if path is not None:
- parsed = list(parsed)
- parsed[2] = path
- imgurl = urlparse.urlunparse(parsed)
- if not imgurl:
- imgurl = txt
- return [safe_url_string(remove_entities(url(imgurl)))] if imgurl else None
diff --git a/scrapy/contrib/ibl/htmlpage.py b/scrapy/contrib/ibl/htmlpage.py
deleted file mode 100644
index 023030bdc..000000000
--- a/scrapy/contrib/ibl/htmlpage.py
+++ /dev/null
@@ -1,167 +0,0 @@
-"""
-htmlpage
-
-Container object for representing html pages in the IBL system. This
-encapsulates page related information and prevents parsing multiple times.
-"""
-import re
-import hashlib
-
-from scrapy.utils.python import str_to_unicode
-
-def create_page_from_jsonpage(jsonpage, body_key):
- """Create an HtmlPage object from a dict object conforming to the schema
- for a page
-
- `body_key` is the key where the body is stored and can be either 'body'
- (original page with annotations - if any) or 'original_body' (original
- page, always). Classification typically uses 'original_body' to avoid
- confusing the classifier with annotated pages, while extraction uses 'body'
- to pass the annotated pages.
- """
- url = jsonpage['url']
- headers = jsonpage.get('headers')
- body = str_to_unicode(jsonpage[body_key])
- page_id = jsonpage.get('page_id')
- return HtmlPage(url, headers, body, page_id)
-
-class HtmlPage(object):
- def __init__(self, url=None, headers=None, body=None, page_id=None):
- assert isinstance(body, unicode), "unicode expected, got: %s" % type(body).__name__
- self.headers = headers or {}
- self.body = body
- self.url = url or u''
- if page_id is None and url:
- self.page_id = hashlib.sha1(url).hexdigest()
- else:
- self.page_id = page_id
-
-
- def _set_body(self, body):
- self._body = body
- self.parsed_body = list(parse_html(body))
-
- body = property(lambda x: x._body, _set_body)
-
- def fragment_data(self, data_fragment):
- return self.body[data_fragment.start:data_fragment.end]
-
-class HtmlTagType(object):
- OPEN_TAG = 1
- CLOSE_TAG = 2
- UNPAIRED_TAG = 3
-
-class HtmlDataFragment(object):
- __slots__ = ('start', 'end')
-
- def __init__(self, start, end):
- self.start = start
- self.end = end
-
- def __str__(self):
- return "" % (self.start, self.end)
-
- def __repr__(self):
- return str(self)
-
-class HtmlTag(HtmlDataFragment):
- __slots__ = ('tag_type', 'tag', 'attributes')
-
- def __init__(self, tag_type, tag, attributes, start, end):
- HtmlDataFragment.__init__(self, start, end)
- self.tag_type = tag_type
- self.tag = tag
- self.attributes = attributes
-
- def __str__(self):
- return "" % (self.tag, ', '.join(sorted\
- (["%s: %s" % (k, repr(v)) for k, v in self.attributes.items()])), self.start, self.end)
-
- def __repr__(self):
- return str(self)
-
-_ATTR = "((?:[^=/>\s]|/(?!>))+)(?:\s*=(?:\s*\"(.*?)\"|\s*'(.*?)'|([^>\s]+))?)?"
-_TAG = "<(\/?)(\w+(?::\w+)?)((?:\s+" + _ATTR + ")+\s*|\s*)(\/?)>"
-_DOCTYPE = r""
-_SCRIPT = "()(.*?)( )"
-_COMMENT = "()"
-
-_ATTR_REGEXP = re.compile(_ATTR, re.I | re.DOTALL)
-_HTML_REGEXP = re.compile("%s|%s|%s" % (_COMMENT, _SCRIPT, _TAG), re.I | re.DOTALL)
-_DOCTYPE_REGEXP = re.compile("(?:%s)" % _DOCTYPE)
-_COMMENT_REGEXP = re.compile(_COMMENT, re.DOTALL)
-
-def parse_html(text):
- """Higher level html parser. Calls lower level parsers and joins sucesive
- HtmlDataFragment elements in a single one.
- """
- # If have doctype remove it.
- start_pos = 0
- match = _DOCTYPE_REGEXP.match(text)
- if match:
- start_pos = match.end()
- prev_end = start_pos
- for match in _HTML_REGEXP.finditer(text, start_pos):
- start = match.start()
- end = match.end()
-
- if start > prev_end:
- yield HtmlDataFragment(prev_end, start)
-
- if match.groups()[0] is not None: # comment
- yield HtmlDataFragment(start, end)
- elif match.groups()[1] is not None: #
- for e in _parse_script(match):
- yield e
- else: # tag
- yield _parse_tag(match)
- prev_end = end
- textlen = len(text)
- if prev_end < textlen:
- yield HtmlDataFragment(prev_end, textlen)
-
-def _parse_script(match):
- """parse a region matched by _HTML_REGEXP"""
- open_text, content, close_text = match.groups()[1:4]
-
- open_tag = _parse_tag(_HTML_REGEXP.match(open_text))
- open_tag.start = match.start()
- open_tag.end = match.start() + len(open_text)
-
- close_tag = _parse_tag(_HTML_REGEXP.match(close_text))
- close_tag.start = match.end() - len(close_text)
- close_tag.end = match.end()
-
- yield open_tag
- if open_tag.end < close_tag.start:
- start_pos = 0
- for m in _COMMENT_REGEXP.finditer(content):
- if m.start() > start_pos:
- yield HtmlDataFragment(open_tag.end + start_pos, open_tag.end + m.start())
- yield HtmlDataFragment(open_tag.end + m.start(), open_tag.end + m.end())
- start_pos = m.end()
- if open_tag.end + start_pos < close_tag.start:
- yield HtmlDataFragment(open_tag.end + start_pos, close_tag.start)
- yield close_tag
-
-def _parse_tag(match):
- """
- parse a tag matched by _HTML_REGEXP
- """
- data = match.groups()
- closing, tag, attr_text = data[4:7]
- # if tag is None then the match is a comment
- if tag is not None:
- unpaired = data[-1]
- if closing:
- tag_type = HtmlTagType.CLOSE_TAG
- elif unpaired:
- tag_type = HtmlTagType.UNPAIRED_TAG
- else:
- tag_type = HtmlTagType.OPEN_TAG
- attributes = []
- for attr_match in _ATTR_REGEXP.findall(attr_text):
- name = attr_match[0].lower()
- values = [v for v in attr_match[1:] if v]
- attributes.append((name, values[0] if values else None))
- return HtmlTag(tag_type, tag.lower(), dict(attributes), match.start(), match.end())
diff --git a/scrapy/contrib/linkextractors/htmlparser.py b/scrapy/contrib/linkextractors/htmlparser.py
index fb3fd661b..0f979d3c1 100644
--- a/scrapy/contrib/linkextractors/htmlparser.py
+++ b/scrapy/contrib/linkextractors/htmlparser.py
@@ -4,9 +4,10 @@ HTMLParser-based link extractor
from HTMLParser import HTMLParser
+from w3lib.url import safe_url_string, urljoin_rfc
+
from scrapy.link import Link
from scrapy.utils.python import unique as unique_list
-from scrapy.utils.url import safe_url_string, urljoin_rfc
class HtmlParserLinkExtractor(HTMLParser):
diff --git a/scrapy/contrib/linkextractors/image.py b/scrapy/contrib/linkextractors/image.py
index 1f29a6797..cac87ec1d 100644
--- a/scrapy/contrib/linkextractors/image.py
+++ b/scrapy/contrib/linkextractors/image.py
@@ -3,9 +3,9 @@ This module implements the HtmlImageLinkExtractor for extracting
image links only.
"""
-
+from w3lib.url import urljoin_rfc
from scrapy.link import Link
-from scrapy.utils.url import canonicalize_url, urljoin_rfc
+from scrapy.utils.url import canonicalize_url
from scrapy.utils.python import unicode_to_str, flatten
from scrapy.selector.libxml2sel import XPathSelectorList, HtmlXPathSelector
diff --git a/scrapy/contrib/linkextractors/lxmlhtml.py b/scrapy/contrib/linkextractors/lxmlhtml.py
new file mode 100644
index 000000000..826c76227
--- /dev/null
+++ b/scrapy/contrib/linkextractors/lxmlhtml.py
@@ -0,0 +1,36 @@
+"""
+Link extractor based on lxml.html
+"""
+
+import lxml.html
+
+from scrapy.link import Link
+from scrapy.utils.python import unique as unique_list
+
+class LxmlParserLinkExtractor(object):
+ def __init__(self, tag="a", attr="href", process=None, unique=False):
+ self.scan_tag = tag if callable(tag) else lambda t: t == tag
+ self.scan_attr = attr if callable(attr) else lambda a: a == attr
+ self.process_attr = process if callable(process) else lambda v: v
+ self.unique = unique
+
+ self.links = []
+
+ def _extract_links(self, response_text, response_url):
+ html = lxml.html.fromstring(response_text)
+ html.make_links_absolute(response_url)
+ for e, a, l, p in html.iterlinks():
+ if self.scan_tag(e.tag):
+ if self.scan_attr(a):
+ link = Link(self.process_attr(l), text=e.text)
+ self.links.append(link)
+
+ links = unique_list(self.links, key=lambda link: link.url) \
+ if self.unique else self.links
+
+ return links
+
+ def extract_links(self, response):
+ return self._extract_links(response.body, response.url)
+
+
diff --git a/scrapy/contrib/linkextractors/lxmlparser.py b/scrapy/contrib/linkextractors/lxmlparser.py
deleted file mode 100644
index 1bf35501d..000000000
--- a/scrapy/contrib/linkextractors/lxmlparser.py
+++ /dev/null
@@ -1,111 +0,0 @@
-"""
-lxml-based link extractors (experimental)
-
-NOTE: The ideal name for this module would be `lxml`, but that's not possible
-because it collides with the lxml library module.
-"""
-
-from lxml import etree
-import lxml.html
-
-from scrapy.link import Link
-from scrapy.utils.python import unique as unique_list, str_to_unicode
-from scrapy.utils.url import safe_url_string, urljoin_rfc
-
-class LxmlLinkExtractor(object):
- def __init__(self, tag="a", attr="href", process=None, unique=False):
- scan_tag = tag if callable(tag) else lambda t: t == tag
- scan_attr = attr if callable(attr) else lambda a: a == attr
- process_attr = process if callable(process) else lambda v: v
-
- self.unique = unique
-
- target = LinkTarget(scan_tag, scan_attr, process_attr)
- self.parser = etree.HTMLParser(target=target)
-
- def _extract_links(self, response_text, response_url, response_encoding):
- self.base_url, self.links = etree.HTML(response_text, self.parser)
-
- links = unique_list(self.links, key=lambda link: link.url) if self.unique else self.links
-
- ret = []
- base_url = urljoin_rfc(response_url, self.base_url) if self.base_url else response_url
- for link in links:
- link.url = urljoin_rfc(base_url, link.url, response_encoding)
- link.url = safe_url_string(link.url, response_encoding)
- link.text = str_to_unicode(link.text, response_encoding, errors='replace')
- ret.append(link)
-
- return ret
-
- def extract_links(self, response):
- # wrapper needed to allow to work directly with text
- return self._extract_links(response.body, response.url,
- response.encoding)
-
- def matches(self, url):
- """This extractor matches with any url, since it doesn't contain any patterns"""
- return True
-
-
-class LinkTarget(object):
- def __init__(self, scan_tag, scan_attr, process_attr):
- self.scan_tag = scan_tag
- self.scan_attr = scan_attr
- self.process_attr = process_attr
-
- self.base_url = None
- self.links = []
-
- self.current_link = None
-
- def start(self, tag, attrs):
- if tag == 'base':
- self.base_url = dict(attrs).get('href')
- if self.scan_tag(tag):
- for attr, value in attrs.iteritems():
- if self.scan_attr(attr):
- url = self.process_attr(value)
- link = Link(url=url)
- self.links.append(link)
- self.current_link = link
-
- def end(self, tag):
- self.current_link = None
-
- def data(self, data):
- if self.current_link and not self.current_link.text:
- self.current_link.text = data.strip()
-
- def close(self):
- return self.base_url, self.links
-
-
-class LxmlParserLinkExtractor(object):
- def __init__(self, tag="a", attr="href", process=None, unique=False):
- self.scan_tag = tag if callable(tag) else lambda t: t == tag
- self.scan_attr = attr if callable(attr) else lambda a: a == attr
- self.process_attr = process if callable(process) else lambda v: v
- self.unique = unique
-
- self.links = []
-
- def _extract_links(self, response_text, response_url):
- html = lxml.html.fromstring(response_text)
- html.make_links_absolute(response_url)
- for e, a, l, p in html.iterlinks():
- if self.scan_tag(e.tag):
- if self.scan_attr(a):
- link = Link(self.process_attr(l), text=e.text)
- self.links.append(link)
-
- links = unique_list(self.links, key=lambda link: link.url) \
- if self.unique else self.links
-
- return links
-
- def extract_links(self, response):
- # wrapper needed to allow to work directly with text
- return self._extract_links(response.body, response.url)
-
-
diff --git a/scrapy/contrib/linkextractors/regex.py b/scrapy/contrib/linkextractors/regex.py
index 1de044df3..9c349ad3a 100644
--- a/scrapy/contrib/linkextractors/regex.py
+++ b/scrapy/contrib/linkextractors/regex.py
@@ -1,7 +1,7 @@
import re
-from scrapy.utils.url import urljoin_rfc
-from scrapy.utils.markup import remove_tags, remove_entities, replace_escape_chars
+from w3lib.url import urljoin_rfc
+from w3lib.html import remove_tags, remove_entities, replace_escape_chars
from scrapy.link import Link
from .sgml import SgmlLinkExtractor
diff --git a/scrapy/contrib/linkextractors/sgml.py b/scrapy/contrib/linkextractors/sgml.py
index 8fbcb35e7..4412ef75e 100644
--- a/scrapy/contrib/linkextractors/sgml.py
+++ b/scrapy/contrib/linkextractors/sgml.py
@@ -3,12 +3,16 @@ SGMLParser-based Link extractors
"""
import re
+from urlparse import urlparse
+
+from w3lib.url import safe_url_string, urljoin_rfc
from scrapy.selector import HtmlXPathSelector
from scrapy.link import Link
+from scrapy.linkextractor import IGNORED_EXTENSIONS
from scrapy.utils.misc import arg_to_iter
from scrapy.utils.python import FixedSGMLParser, unique as unique_list, str_to_unicode
-from scrapy.utils.url import safe_url_string, urljoin_rfc, canonicalize_url, url_is_from_any_domain
+from scrapy.utils.url import canonicalize_url, url_is_from_any_domain, url_has_any_extension
from scrapy.utils.response import get_base_url
class BaseSgmlLinkExtractor(FixedSGMLParser):
@@ -89,13 +93,17 @@ _is_valid_url = lambda url: url.split('://', 1)[0] in set(['http', 'https', 'fil
class SgmlLinkExtractor(BaseSgmlLinkExtractor):
def __init__(self, allow=(), deny=(), allow_domains=(), deny_domains=(), restrict_xpaths=(),
- tags=('a', 'area'), attrs=('href'), canonicalize=True, unique=True, process_value=None):
+ tags=('a', 'area'), attrs=('href'), canonicalize=True, unique=True, process_value=None,
+ deny_extensions=None):
self.allow_res = [x if isinstance(x, _re_type) else re.compile(x) for x in arg_to_iter(allow)]
self.deny_res = [x if isinstance(x, _re_type) else re.compile(x) for x in arg_to_iter(deny)]
self.allow_domains = set(arg_to_iter(allow_domains))
self.deny_domains = set(arg_to_iter(deny_domains))
self.restrict_xpaths = tuple(arg_to_iter(restrict_xpaths))
self.canonicalize = canonicalize
+ if deny_extensions is None:
+ deny_extensions = IGNORED_EXTENSIONS
+ self.deny_extensions = set(['.' + e for e in deny_extensions])
tag_func = lambda x: x in tags
attr_func = lambda x: x in attrs
BaseSgmlLinkExtractor.__init__(self, tag=tag_func, attr=attr_func,
@@ -116,24 +124,27 @@ class SgmlLinkExtractor(BaseSgmlLinkExtractor):
return links
def _process_links(self, links):
- links = [link for link in links if _is_valid_url(link.url)]
-
- if self.allow_res:
- links = [link for link in links if _matches(link.url, self.allow_res)]
- if self.deny_res:
- links = [link for link in links if not _matches(link.url, self.deny_res)]
- if self.allow_domains:
- links = [link for link in links if url_is_from_any_domain(link.url, self.allow_domains)]
- if self.deny_domains:
- links = [link for link in links if not url_is_from_any_domain(link.url, self.deny_domains)]
-
- if self.canonicalize:
- for link in links:
- link.url = canonicalize_url(link.url)
-
+ links = [x for x in links if self._link_allowed(x)]
links = BaseSgmlLinkExtractor._process_links(self, links)
return links
+ def _link_allowed(self, link):
+ parsed_url = urlparse(link.url)
+ allowed = _is_valid_url(link.url)
+ if self.allow_res:
+ allowed &= _matches(link.url, self.allow_res)
+ if self.deny_res:
+ allowed &= not _matches(link.url, self.deny_res)
+ if self.allow_domains:
+ allowed &= url_is_from_any_domain(parsed_url, self.allow_domains)
+ if self.deny_domains:
+ allowed &= not url_is_from_any_domain(parsed_url, self.deny_domains)
+ if self.deny_extensions:
+ allowed &= not url_has_any_extension(parsed_url, self.deny_extensions)
+ if allowed and self.canonicalize:
+ link.url = canonicalize_url(parsed_url)
+ return allowed
+
def matches(self, url):
if self.allow_domains and not url_is_from_any_domain(url, self.allow_domains):
return False
diff --git a/scrapy/contrib/loader/__init__.py b/scrapy/contrib/loader/__init__.py
index a9fc8f011..fa8387eaa 100644
--- a/scrapy/contrib/loader/__init__.py
+++ b/scrapy/contrib/loader/__init__.py
@@ -79,7 +79,11 @@ class ItemLoader(object):
def get_output_value(self, field_name):
proc = self.get_output_processor(field_name)
proc = wrap_loader_context(proc, self.context)
- return proc(self._values[field_name])
+ try:
+ return proc(self._values[field_name])
+ except Exception, e:
+ raise ValueError("Error with output processor: field=%r value=%r error='%s: %s'" % \
+ (field_name, self._values[field_name], type(e).__name__, str(e)))
def get_collected_values(self, field_name):
return self._values[field_name]
diff --git a/scrapy/contrib/logstats.py b/scrapy/contrib/logstats.py
new file mode 100644
index 000000000..9ce599bff
--- /dev/null
+++ b/scrapy/contrib/logstats.py
@@ -0,0 +1,59 @@
+from twisted.internet import task
+
+from scrapy.xlib.pydispatch import dispatcher
+from scrapy.exceptions import NotConfigured
+from scrapy.conf import settings
+from scrapy import log, signals
+
+class Slot(object):
+
+ def __init__(self):
+ self.items = 0
+ self.itemsprev = 0
+ self.pages = 0
+ self.pagesprev = 0
+
+class LogStats(object):
+ """Log basic scraping stats periodically"""
+
+ def __init__(self):
+ self.interval = settings.getfloat('LOGSTATS_INTERVAL')
+ if not self.interval:
+ raise NotConfigured
+ self.slots = {}
+ self.multiplier = 60.0 / self.interval
+ dispatcher.connect(self.item_scraped, signal=signals.item_scraped)
+ dispatcher.connect(self.response_received, signal=signals.response_received)
+ dispatcher.connect(self.spider_opened, signal=signals.spider_opened)
+ dispatcher.connect(self.spider_closed, signal=signals.spider_closed)
+ dispatcher.connect(self.engine_started, signal=signals.engine_started)
+ dispatcher.connect(self.engine_stopped, signal=signals.engine_stopped)
+
+ def item_scraped(self, spider):
+ self.slots[spider].items += 1
+
+ def response_received(self, spider):
+ self.slots[spider].pages += 1
+
+ def spider_opened(self, spider):
+ self.slots[spider] = Slot()
+
+ def spider_closed(self, spider):
+ del self.slots[spider]
+
+ def engine_started(self):
+ self.tsk = task.LoopingCall(self.log)
+ self.tsk.start(self.interval)
+
+ def log(self):
+ for spider, slot in self.slots.items():
+ irate = (slot.items - slot.itemsprev) * self.multiplier
+ prate = (slot.pages - slot.pagesprev) * self.multiplier
+ slot.pagesprev, slot.itemsprev = slot.pages, slot.items
+ msg = "Crawled %d pages (at %d pages/min), scraped %d items (at %d items/min)" \
+ % (slot.pages, prate, slot.items, irate)
+ log.msg(msg, spider=spider)
+
+ def engine_stopped(self):
+ if self.tsk.running:
+ self.tsk.stop()
diff --git a/scrapy/contrib/memdebug.py b/scrapy/contrib/memdebug.py
index 2d79d0b80..a28aad2ef 100644
--- a/scrapy/contrib/memdebug.py
+++ b/scrapy/contrib/memdebug.py
@@ -4,18 +4,15 @@ MemoryDebugger extension
See documentation in docs/topics/extensions.rst
"""
-import os
import gc
-import socket
from scrapy.xlib.pydispatch import dispatcher
from scrapy import signals
from scrapy.exceptions import NotConfigured
-from scrapy.mail import MailSender
-from scrapy.utils.trackref import format_live_refs
from scrapy.conf import settings
-from scrapy import log
+from scrapy.stats import stats
+from scrapy.utils.trackref import live_refs
class MemoryDebugger(object):
@@ -28,9 +25,6 @@ class MemoryDebugger(object):
if not settings.getbool('MEMDEBUG_ENABLED'):
raise NotConfigured
- self.mail = MailSender()
- self.rcpts = settings.getlist('MEMDEBUG_NOTIFY')
-
dispatcher.connect(self.engine_started, signals.engine_started)
dispatcher.connect(self.engine_stopped, signals.engine_stopped)
@@ -39,32 +33,13 @@ class MemoryDebugger(object):
self.libxml2.debugMemory(1)
def engine_stopped(self):
- figures = self.collect_figures()
- report = self.create_report(figures)
- self.log_or_send_report(report)
-
- def collect_figures(self):
- gc.collect()
-
- figures = []
- figures.append(("Objects in gc.garbage", len(gc.garbage), ""))
if self.libxml2:
self.libxml2.cleanupParser()
- figures.append(("libxml2 memory leak", self.libxml2.debugMemory(1), "bytes"))
- return figures
-
- def create_report(self, figures):
- s = ""
- s += "SCRAPY MEMORY DEBUGGER RESULTS\n\n"
- for f in figures:
- s += "%-30s : %d %s\n" % f
+ stats.set_value('memdebug/libxml2_leaked_bytes', self.libxml2.debugMemory(1))
+ gc.collect()
+ stats.set_value('memdebug/gc_garbage_count', len(gc.garbage))
if settings.getbool('TRACK_REFS'):
- s += os.linesep
- s += format_live_refs()
- return s
-
- def log_or_send_report(self, report):
- if self.rcpts:
- self.mail.send(self.rcpts, "Scrapy Memory Debugger results at %s" % \
- socket.gethostname(), report)
- log.msg(report)
+ for cls, wdict in live_refs.iteritems():
+ if not wdict:
+ continue
+ stats.set_value('memdebug/live_refs/%s' % cls.__name__, len(wdict))
diff --git a/scrapy/contrib/memusage.py b/scrapy/contrib/memusage.py
index e3e051ab5..95de44997 100644
--- a/scrapy/contrib/memusage.py
+++ b/scrapy/contrib/memusage.py
@@ -12,31 +12,34 @@ from twisted.internet import task
from scrapy.xlib.pydispatch import dispatcher
from scrapy import signals
from scrapy import log
-from scrapy.project import crawler
from scrapy.exceptions import NotConfigured
from scrapy.mail import MailSender
-from scrapy.conf import settings
from scrapy.stats import stats
from scrapy.utils.memory import get_vmvalue_from_procfs, procfs_supported
from scrapy.utils.engine import get_engine_status
class MemoryUsage(object):
- def __init__(self):
- if not settings.getbool('MEMUSAGE_ENABLED'):
+ def __init__(self, crawler):
+ if not crawler.settings.getbool('MEMUSAGE_ENABLED'):
raise NotConfigured
if not procfs_supported():
raise NotConfigured
+ self.crawler = crawler
self.warned = False
- self.notify_mails = settings.getlist('MEMUSAGE_NOTIFY')
- self.limit = settings.getint('MEMUSAGE_LIMIT_MB')*1024*1024
- self.warning = settings.getint('MEMUSAGE_WARNING_MB')*1024*1024
- self.report = settings.getbool('MEMUSAGE_REPORT')
+ self.notify_mails = crawler.settings.getlist('MEMUSAGE_NOTIFY')
+ self.limit = crawler.settings.getint('MEMUSAGE_LIMIT_MB')*1024*1024
+ self.warning = crawler.settings.getint('MEMUSAGE_WARNING_MB')*1024*1024
+ self.report = crawler.settings.getbool('MEMUSAGE_REPORT')
self.mail = MailSender()
dispatcher.connect(self.engine_started, signal=signals.engine_started)
dispatcher.connect(self.engine_stopped, signal=signals.engine_stopped)
+ @classmethod
+ def from_crawler(cls, crawler):
+ return cls(crawler)
+
def get_virtual_size(self):
return get_vmvalue_from_procfs('VmSize')
@@ -70,10 +73,10 @@ class MemoryUsage(object):
log.msg("Memory usage exceeded %dM. Shutting down Scrapy..." % mem, level=log.ERROR)
if self.notify_mails:
subj = "%s terminated: memory usage exceeded %dM at %s" % \
- (settings['BOT_NAME'], mem, socket.gethostname())
+ (self.crawler.settings['BOT_NAME'], mem, socket.gethostname())
self._send_report(self.notify_mails, subj)
stats.set_value('memusage/limit_notified', 1)
- crawler.stop()
+ self.crawler.stop()
def _check_warning(self):
if self.warned: # warn only once
@@ -84,7 +87,7 @@ class MemoryUsage(object):
log.msg("Memory usage reached %dM" % mem, level=log.WARNING)
if self.notify_mails:
subj = "%s warning: memory usage reached %dM at %s" % \
- (settings['BOT_NAME'], mem, socket.gethostname())
+ (self.crawler.settings['BOT_NAME'], mem, socket.gethostname())
self._send_report(self.notify_mails, subj)
stats.set_value('memusage/warning_notified', 1)
self.warned = True
diff --git a/scrapy/contrib/pipeline/__init__.py b/scrapy/contrib/pipeline/__init__.py
index 2e6cc8626..c1c7e5a22 100644
--- a/scrapy/contrib/pipeline/__init__.py
+++ b/scrapy/contrib/pipeline/__init__.py
@@ -4,9 +4,7 @@ Item pipeline
See documentation in docs/item-pipeline.rst
"""
-from scrapy import log
from scrapy.middleware import MiddlewareManager
-from scrapy.utils.python import get_func_args
class ItemPipelineManager(MiddlewareManager):
@@ -16,22 +14,10 @@ class ItemPipelineManager(MiddlewareManager):
def _get_mwlist_from_settings(cls, settings):
return settings.getlist('ITEM_PIPELINES')
- # FIXME: remove in Scrapy 0.11
- def _wrap_old_process_item(self, old):
- def new(item, spider):
- return old(spider, item)
- return new
-
def _add_middleware(self, pipe):
super(ItemPipelineManager, self)._add_middleware(pipe)
- func = getattr(pipe, 'process_item', None)
- if func:
- # FIXME: remove in Scrapy 0.11
- fargs = get_func_args(func.im_func)
- if fargs and fargs[1] == 'spider':
- log.msg("Update %s.process_item() method to receive (item, spider) instead of (spider, item) or they will stop working on Scrapy 0.11" % pipe.__class__.__name__, log.WARNING)
- func = self._wrap_old_process_item(func)
- self.methods['process_item'].append(func)
+ if hasattr(pipe, 'process_item'):
+ self.methods['process_item'].append(pipe.process_item)
def process_item(self, item, spider):
return self._process_chain('process_item', item, spider)
diff --git a/scrapy/contrib/pipeline/fileexport.py b/scrapy/contrib/pipeline/fileexport.py
deleted file mode 100644
index c591f547b..000000000
--- a/scrapy/contrib/pipeline/fileexport.py
+++ /dev/null
@@ -1,54 +0,0 @@
-import warnings
-warnings.warn("File export pipeline is deprecated and will be removed in Scrapy 0.11, use Feed exports instead", \
- DeprecationWarning, stacklevel=2)
-
-from scrapy.xlib.pydispatch import dispatcher
-from scrapy import signals
-from scrapy.exceptions import NotConfigured
-from scrapy.contrib import exporter
-from scrapy.conf import settings
-
-class FileExportPipeline(object):
-
- def __init__(self):
- self.exporter, self.file = self.get_exporter_and_file()
- self.exporter.start_exporting()
- dispatcher.connect(self.engine_stopped, signals.engine_stopped)
-
- def process_item(self, item, spider):
- self.exporter.export_item(item)
- return item
-
- def engine_stopped(self):
- self.exporter.finish_exporting()
- self.file.close()
-
- def get_exporter_and_file(self):
- format = settings['EXPORT_FORMAT']
- filename = settings['EXPORT_FILE']
- if not format or not filename:
- raise NotConfigured
- exp_kwargs = {
- 'fields_to_export': settings.getlist('EXPORT_FIELDS') or None,
- 'export_empty_fields': settings.getbool('EXPORT_EMPTY', False),
- 'encoding': settings.get('EXPORT_ENCODING', 'utf-8'),
- }
- file = open(filename, 'wb')
- if format == 'xml':
- exp = exporter.XmlItemExporter(file, **exp_kwargs)
- elif format == 'csv':
- exp = exporter.CsvItemExporter(file, **exp_kwargs)
- elif format == 'csv_headers':
- exp = exporter.CsvItemExporter(file, include_headers_line=True, \
- **exp_kwargs)
- elif format == 'pprint':
- exp = exporter.PprintItemExporter(file, **exp_kwargs)
- elif format == 'pickle':
- exp = exporter.PickleItemExporter(file, **exp_kwargs)
- elif format == 'json':
- exp = exporter.JsonLinesItemExporter(file, **exp_kwargs)
- elif format == 'jsonlines':
- exp = exporter.JsonItemExporter(file, **exp_kwargs)
- else:
- raise NotConfigured("Unsupported export format: %s" % format)
- return exp, file
diff --git a/scrapy/contrib/pipeline/images.py b/scrapy/contrib/pipeline/images.py
index 427222d47..c7333a542 100644
--- a/scrapy/contrib/pipeline/images.py
+++ b/scrapy/contrib/pipeline/images.py
@@ -154,6 +154,8 @@ class ImagesPipeline(MediaPipeline):
}
def __init__(self, store_uri, download_func=None):
+ if not store_uri:
+ raise NotConfigured
self.store = self._get_store(store_uri)
super(ImagesPipeline, self).__init__(download_func=download_func)
@@ -167,8 +169,6 @@ class ImagesPipeline(MediaPipeline):
s3store.AWS_ACCESS_KEY_ID = settings['AWS_ACCESS_KEY_ID']
s3store.AWS_SECRET_ACCESS_KEY = settings['AWS_SECRET_ACCESS_KEY']
store_uri = settings['IMAGES_STORE']
- if not store_uri:
- raise NotConfigured
return cls(store_uri)
def _get_store(self, uri):
diff --git a/scrapy/contrib/pipeline/media.py b/scrapy/contrib/pipeline/media.py
index baaa22fd5..ee0320c36 100644
--- a/scrapy/contrib/pipeline/media.py
+++ b/scrapy/contrib/pipeline/media.py
@@ -6,7 +6,6 @@ from scrapy import log
from scrapy.utils.request import request_fingerprint
from scrapy.utils.misc import arg_to_iter
-
class MediaPipeline(object):
LOG_FAILED_RESULTS = True
@@ -20,17 +19,16 @@ class MediaPipeline(object):
def __init__(self, download_func=None):
self.spiderinfo = {}
- self._cached_download_func = download_func
+ self.download_func = download_func
- @property
- def _download_func(self):
- if self._cached_download_func is None:
- self._cached_download_func = self._default_download_func()
- return self._cached_download_func
-
- def _default_download_func(self):
- from scrapy.project import crawler
- return crawler.engine.download
+ @classmethod
+ def from_crawler(cls, crawler):
+ try:
+ pipe = cls.from_settings(crawler.settings)
+ except AttributeError:
+ pipe = cls()
+ pipe.crawler = crawler
+ return pipe
def open_spider(self, spider):
self.spiderinfo[spider] = self.SpiderInfo(spider)
@@ -49,6 +47,8 @@ class MediaPipeline(object):
fp = request_fingerprint(request)
cb = request.callback or (lambda _: _)
eb = request.errback
+ request.callback = None
+ request.errback = None
# Return cached result if request was already seen
if fp in info.downloaded:
@@ -73,10 +73,19 @@ class MediaPipeline(object):
def _check_media_to_download(self, result, request, info):
if result is not None:
return result
- # Download request and process its response
- return mustbe_deferred(self.download, request, info).addCallbacks(
+ if self.download_func:
+ # this ugly code was left only to support tests. TODO: remove
+ dfd = mustbe_deferred(self.download_func, request, info.spider)
+ dfd.addCallbacks(
callback=self.media_downloaded, callbackArgs=(request, info),
errback=self.media_failed, errbackArgs=(request, info))
+ else:
+ request.meta['handle_httpstatus_all'] = True
+ dfd = self.crawler.engine.download(request, info.spider)
+ dfd.addCallbacks(
+ callback=self.media_downloaded, callbackArgs=(request, info),
+ errback=self.media_failed, errbackArgs=(request, info))
+ return dfd
def _cache_result_and_execute_waiters(self, result, fp, info):
info.downloading.remove(fp)
@@ -85,10 +94,6 @@ class MediaPipeline(object):
defer_result(result).chainDeferred(wad)
### Overradiable Interface
- def download(self, request, info):
- """Defines how to download the media request"""
- return self._download_func(request, info.spider)
-
def media_to_download(self, request, info):
"""Check request before starting download"""
pass
diff --git a/scrapy/contrib/resolver.py b/scrapy/contrib/resolver.py
deleted file mode 100644
index 8bf04c25f..000000000
--- a/scrapy/contrib/resolver.py
+++ /dev/null
@@ -1,46 +0,0 @@
-from collections import defaultdict
-
-from twisted.internet import reactor, defer
-from twisted.internet.base import ThreadedResolver
-
-from scrapy.xlib.pydispatch import dispatcher
-from scrapy.utils.httpobj import urlparse_cached
-from scrapy import signals
-
-
-class CachingResolver(object):
- """Scrapy extension to use a caching resolver, instead of default one"""
-
- def __init__(self):
- self.spider_hostnames = defaultdict(set)
- self.resolver = _CachingThreadedResolver(reactor)
- reactor.installResolver(self.resolver)
- dispatcher.connect(self.request_received, signals.request_received)
- dispatcher.connect(self.spider_closed, signal=signals.spider_closed)
-
- def request_received(self, request, spider):
- url_hostname = urlparse_cached(request).hostname
- self.spider_hostnames[spider].add(url_hostname)
-
- def spider_closed(self, spider):
- for hostname in self.spider_hostnames[spider]:
- self.resolver._cache.pop(hostname, None)
- self.spider_hostnames.pop(spider, None)
-
-
-class _CachingThreadedResolver(ThreadedResolver):
-
- def __init__(self, *args, **kwargs):
- ThreadedResolver.__init__(self, *args, **kwargs)
- self._cache = {}
-
- def getHostByName(self, name, timeout = (1, 3, 11, 45)):
- if name in self._cache:
- return defer.succeed(self._cache[name])
- dfd = ThreadedResolver.getHostByName(self, name, timeout)
- dfd.addCallback(self._cache_result, name)
- return dfd
-
- def _cache_result(self, result, name):
- self._cache[name] = result
- return result
diff --git a/scrapy/contrib/schedulermiddleware/__init__.py b/scrapy/contrib/schedulermiddleware/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/scrapy/contrib/schedulermiddleware/duplicatesfilter.py b/scrapy/contrib/schedulermiddleware/duplicatesfilter.py
deleted file mode 100644
index 2ba329146..000000000
--- a/scrapy/contrib/schedulermiddleware/duplicatesfilter.py
+++ /dev/null
@@ -1,29 +0,0 @@
-"""
-DuplicatesFilterMiddleware: Filter out already visited urls
-
-See documentation in docs/topics/scheduler-middleware.rst
-"""
-
-from scrapy.exceptions import IgnoreRequest, NotConfigured
-from scrapy.utils.misc import load_object
-from scrapy.conf import settings
-
-class DuplicatesFilterMiddleware(object):
-
- def __init__(self):
- clspath = settings.get('DUPEFILTER_CLASS')
- if not clspath:
- raise NotConfigured
-
- self.dupefilter = load_object(clspath)()
-
- def enqueue_request(self, spider, request):
- seen = self.dupefilter.request_seen(spider, request)
- if seen and not request.dont_filter:
- raise IgnoreRequest('Skipped (request already seen)')
-
- def open_spider(self, spider):
- self.dupefilter.open_spider(spider)
-
- def close_spider(self, spider):
- self.dupefilter.close_spider(spider)
diff --git a/scrapy/contrib/spiderclosedelay.py b/scrapy/contrib/spiderclosedelay.py
deleted file mode 100644
index 203c4de62..000000000
--- a/scrapy/contrib/spiderclosedelay.py
+++ /dev/null
@@ -1,39 +0,0 @@
-"""
-SpiderCloseDelay is an extension that keeps a idle spiders open until a
-configurable amount of idle time has elapsed
-"""
-
-from time import time
-
-from scrapy.xlib.pydispatch import dispatcher
-from collections import defaultdict
-
-from scrapy import signals
-from scrapy.project import crawler
-from scrapy.exceptions import NotConfigured, DontCloseSpider
-from scrapy.conf import settings
-
-
-class SpiderCloseDelay(object):
- def __init__(self):
- self.delay = settings.getint('SPIDER_CLOSE_DELAY')
- if not self.delay:
- raise NotConfigured
-
- self.opened_at = defaultdict(time)
- dispatcher.connect(self.spider_idle, signal=signals.spider_idle)
- dispatcher.connect(self.spider_closed, signal=signals.spider_closed)
-
- def spider_idle(self, spider):
- try:
- lastseen = crawler.engine.downloader.sites[spider].lastseen
- except KeyError:
- lastseen = None
- if not lastseen:
- lastseen = self.opened_at[spider]
-
- if time() < lastseen + self.delay:
- raise DontCloseSpider
-
- def spider_closed(self, spider):
- self.opened_at.pop(spider, None)
diff --git a/scrapy/contrib/spidermiddleware/depth.py b/scrapy/contrib/spidermiddleware/depth.py
index 786dd9797..978e7baef 100644
--- a/scrapy/contrib/spidermiddleware/depth.py
+++ b/scrapy/contrib/spidermiddleware/depth.py
@@ -4,45 +4,64 @@ Depth Spider Middleware
See documentation in docs/topics/spider-middleware.rst
"""
+import warnings
+
from scrapy import log
from scrapy.http import Request
+from scrapy.exceptions import ScrapyDeprecationWarning
class DepthMiddleware(object):
- def __init__(self, maxdepth, stats=None):
+ def __init__(self, maxdepth, stats=None, verbose_stats=False, prio=1):
self.maxdepth = maxdepth
self.stats = stats
- if self.stats and self.maxdepth:
- stats.set_value('envinfo/request_depth_limit', maxdepth)
+ self.verbose_stats = verbose_stats
+ self.prio = prio
@classmethod
def from_settings(cls, settings):
maxdepth = settings.getint('DEPTH_LIMIT')
usestats = settings.getbool('DEPTH_STATS')
+ verbose = settings.getbool('DEPTH_STATS_VERBOSE')
+ sorder = settings['SCHEDULER_ORDER']
+ if sorder:
+ # XXX: backwards compatibility with old SCHEDULER_ORDER setting
+ # will be removed on Scrapy 0.15
+ warnings.warn("SCHEDULER_ORDER setting is deprecated, " \
+ "use DEPTH_PRIORITY instead", ScrapyDeprecationWarning)
+ if sorder == 'BFO':
+ prio = 1
+ elif sorder == 'DFO':
+ prio = -1
+ else:
+ prio = settings.getint('DEPTH_PRIORITY')
if usestats:
from scrapy.stats import stats
else:
stats = None
- return cls(maxdepth, stats)
+ return cls(maxdepth, stats, verbose, prio)
def process_spider_output(self, response, result, spider):
def _filter(request):
if isinstance(request, Request):
depth = response.request.meta['depth'] + 1
request.meta['depth'] = depth
+ if self.prio:
+ request.priority += depth * self.prio
if self.maxdepth and depth > self.maxdepth:
log.msg("Ignoring link (depth > %d): %s " % (self.maxdepth, request.url), \
level=log.DEBUG, spider=spider)
return False
elif self.stats:
- self.stats.inc_value('request_depth_count/%s' % depth, spider=spider)
- if depth > self.stats.get_value('request_depth_max', 0, spider=spider):
- self.stats.set_value('request_depth_max', depth, spider=spider)
+ if self.verbose_stats:
+ self.stats.inc_value('request_depth_count/%s' % depth, spider=spider)
+ self.stats.max_value('request_depth_max', depth, spider=spider)
return True
# base case (depth=0)
if self.stats and 'depth' not in response.request.meta:
response.request.meta['depth'] = 0
- self.stats.inc_value('request_depth_count/0', spider=spider)
+ if self.verbose_stats:
+ self.stats.inc_value('request_depth_count/0', spider=spider)
return (r for r in result or () if _filter(r))
diff --git a/scrapy/contrib/spidermiddleware/httperror.py b/scrapy/contrib/spidermiddleware/httperror.py
index 86913c02d..59d37a2f4 100644
--- a/scrapy/contrib/spidermiddleware/httperror.py
+++ b/scrapy/contrib/spidermiddleware/httperror.py
@@ -19,8 +19,11 @@ class HttpErrorMiddleware(object):
def process_spider_input(self, response, spider):
if 200 <= response.status < 300: # common case
return
- if 'handle_httpstatus_list' in response.request.meta:
- allowed_statuses = response.request.meta['handle_httpstatus_list']
+ meta = response.request.meta
+ if 'handle_httpstatus_all' in meta:
+ return
+ if 'handle_httpstatus_list' in meta:
+ allowed_statuses = meta['handle_httpstatus_list']
else:
allowed_statuses = getattr(spider, 'handle_httpstatus_list', ())
if response.status in allowed_statuses:
diff --git a/scrapy/contrib/spiderqueue.py b/scrapy/contrib/spiderqueue.py
deleted file mode 100644
index 82d77402f..000000000
--- a/scrapy/contrib/spiderqueue.py
+++ /dev/null
@@ -1,81 +0,0 @@
-from zope.interface import implements
-
-from twisted.internet import threads
-from boto.sqs.connection import SQSConnection
-from boto.sqs.message import Message
-from boto.sqs import regions
-
-from scrapy.interfaces import ISpiderQueue
-from scrapy.utils.py26 import json
-
-class SQSSpiderQueue(object):
-
- implements(ISpiderQueue)
-
- def __init__(self, *a, **kw):
- self.queue_name = kw.pop('queue_name', 'scrapy')
- self.region_name = kw.pop('region_name', 'us-east-1')
- self.visibility_timeout = kw.pop('visibility_timeout', 7200)
- self.aws_access_key_id = kw.pop('aws_access_key_id', None)
- self.aws_secret_access_key = kw.pop('aws_secret_access_key', None)
- self.region = self._get_region(self.region_name)
- self.conn.create_queue(self.queue_name)
- super(SQSSpiderQueue, self).__init__(*a, **kw)
-
- @classmethod
- def from_settings(cls, settings):
- return cls(
- queue_name=settings['SQS_QUEUE'],
- region_name=settings['SQS_REGION'],
- visibility_timeout=settings.getint('SQS_VISIBILITY_TIMEOUT'),
- aws_access_key_id=settings['AWS_ACCESS_KEY_ID'],
- aws_secret_access_key=settings['AWS_SECRET_ACCESS_KEY']
- )
-
- def _get_region(self, name):
- return [r for r in regions() if r.name == name][0]
-
- @property
- def conn(self):
- return SQSConnection(self.aws_access_key_id, self.aws_secret_access_key, \
- region=self.region)
-
- @property
- def queue(self):
- return self.conn.get_queue(self.queue_name)
-
- def _queue_method(self, method, *a, **kw):
- return getattr(self.queue, method)(*a, **kw)
-
- def pop(self):
- return threads.deferToThread(self._pop)
-
- def _pop(self):
- msgs = self.queue.get_messages(1, visibility_timeout=self.visibility_timeout)
- if msgs:
- msg = msgs[0]
- msg.delete()
- return json.loads(msg.get_body())
-
- def add(self, name, **spider_args):
- d = spider_args.copy()
- d['name'] = name
- msg = Message(body=json.dumps(d))
- return threads.deferToThread(self._queue_method, 'write', msg)
-
- def count(self):
- return threads.deferToThread(self._queue_method, 'count')
-
- def list(self):
- return threads.deferToThread(self._list)
-
- def _list(self):
- msgs = []
- m = self.queue.read(visibility_timeout=100)
- while m:
- msgs.append(json.loads(m.get_body()))
- m = self.queue.read(visibility_timeout=100)
- return msgs
-
- def clear(self):
- return threads.deferToThread(self._queue_method, 'clear')
diff --git a/scrapy/contrib/spiders/__init__.py b/scrapy/contrib/spiders/__init__.py
index 6a310dd44..c16bb6c0a 100644
--- a/scrapy/contrib/spiders/__init__.py
+++ b/scrapy/contrib/spiders/__init__.py
@@ -1,2 +1,3 @@
from scrapy.contrib.spiders.crawl import CrawlSpider, Rule
from scrapy.contrib.spiders.feed import XMLFeedSpider, CSVFeedSpider
+from scrapy.contrib.spiders.sitemap import SitemapSpider
diff --git a/scrapy/contrib/spiders/crawl.py b/scrapy/contrib/spiders/crawl.py
index 4ca606d8a..e6a2d66c4 100644
--- a/scrapy/contrib/spiders/crawl.py
+++ b/scrapy/contrib/spiders/crawl.py
@@ -6,11 +6,10 @@ See documentation in docs/topics/spiders.rst
"""
import copy
-from functools import partial
from scrapy.http import Request
from scrapy.utils.spider import iterate_spider_output
-from scrapy.contrib.spiders.init import InitSpider
+from scrapy.spider import BaseSpider
from scrapy.conf import settings
def identity(x):
@@ -29,7 +28,7 @@ class Rule(object):
else:
self.follow = follow
-class CrawlSpider(InitSpider):
+class CrawlSpider(BaseSpider):
rules = ()
@@ -38,7 +37,7 @@ class CrawlSpider(InitSpider):
self._compile_rules()
def parse(self, response):
- return self._response_downloaded(response, self.parse_start_url, cb_kwargs={}, follow=True)
+ return self._parse_response(response, self.parse_start_url, cb_kwargs={}, follow=True)
def parse_start_url(self, response):
return []
@@ -48,19 +47,21 @@ class CrawlSpider(InitSpider):
def _requests_to_follow(self, response):
seen = set()
- for rule in self._rules:
+ for n, rule in enumerate(self._rules):
links = [l for l in rule.link_extractor.extract_links(response) if l not in seen]
if links and rule.process_links:
links = rule.process_links(links)
seen = seen.union(links)
for link in links:
- callback = partial(self._response_downloaded, callback=rule.callback, \
- cb_kwargs=rule.cb_kwargs, follow=rule.follow)
- r = Request(url=link.url, callback=callback)
- r.meta['link_text'] = link.text
+ r = Request(url=link.url, callback=self._response_downloaded)
+ r.meta.update(rule=n, link_text=link.text)
yield rule.process_request(r)
- def _response_downloaded(self, response, callback, cb_kwargs, follow):
+ def _response_downloaded(self, response):
+ rule = self._rules[response.meta['rule']]
+ return self._parse_response(response, rule.callback, rule.cb_kwargs, rule.follow)
+
+ def _parse_response(self, response, callback, cb_kwargs, follow=True):
if callback:
cb_res = callback(response, **cb_kwargs) or ()
cb_res = self.process_results(response, cb_res)
diff --git a/scrapy/contrib/spiders/feed.py b/scrapy/contrib/spiders/feed.py
index b449be977..10b837353 100644
--- a/scrapy/contrib/spiders/feed.py
+++ b/scrapy/contrib/spiders/feed.py
@@ -5,14 +5,14 @@ for scraping from an XML feed.
See documentation in docs/topics/spiders.rst
"""
-from scrapy.contrib.spiders.init import InitSpider
+from scrapy.spider import BaseSpider
from scrapy.item import BaseItem
from scrapy.http import Request
from scrapy.utils.iterators import xmliter, csviter
from scrapy.selector import XmlXPathSelector, HtmlXPathSelector
from scrapy.exceptions import NotConfigured, NotSupported
-class XMLFeedSpider(InitSpider):
+class XMLFeedSpider(BaseSpider):
"""
This class intends to be the base class for spiders that scrape
from XML feeds.
@@ -47,7 +47,7 @@ class XMLFeedSpider(InitSpider):
"""This method must be overriden with your custom spider functionality"""
if hasattr(self, 'parse_item'): # backward compatibility
return self.parse_item(response, selector)
- raise NotImplemented
+ raise NotImplementedError
def parse_nodes(self, response, nodes):
"""This method is called for the nodes matching the provided tag name
@@ -90,7 +90,7 @@ class XMLFeedSpider(InitSpider):
for (prefix, uri) in self.namespaces:
selector.register_namespace(prefix, uri)
-class CSVFeedSpider(InitSpider):
+class CSVFeedSpider(BaseSpider):
"""Spider for parsing CSV feeds.
It receives a CSV file in a response; iterates through each of its rows,
and calls parse_row with a dict containing each field's data.
@@ -110,9 +110,9 @@ class CSVFeedSpider(InitSpider):
"""This method has the same purpose as the one in XMLFeedSpider"""
return response
- def parse_row(self, row):
+ def parse_row(self, response, row):
"""This method must be overriden with your custom spider functionality"""
- raise NotImplemented
+ raise NotImplementedError
def parse_rows(self, response):
"""Receives a response and a dict (representing each row) with a key for
diff --git a/scrapy/contrib/spiders/sitemap.py b/scrapy/contrib/spiders/sitemap.py
new file mode 100644
index 000000000..698e7c389
--- /dev/null
+++ b/scrapy/contrib/spiders/sitemap.py
@@ -0,0 +1,63 @@
+import re
+
+from scrapy.spider import BaseSpider
+from scrapy.http import Request, XmlResponse
+from scrapy.utils.sitemap import Sitemap, sitemap_urls_from_robots
+from scrapy.utils.gz import gunzip
+from scrapy import log
+
+class SitemapSpider(BaseSpider):
+
+ sitemap_urls = ()
+ sitemap_rules = [('', 'parse')]
+ sitemap_follow = ['']
+
+ def __init__(self, *a, **kw):
+ super(SitemapSpider, self).__init__(*a, **kw)
+ self._cbs = []
+ for r, c in self.sitemap_rules:
+ if isinstance(c, basestring):
+ c = getattr(self, c)
+ self._cbs.append((regex(r), c))
+ self._follow = [regex(x) for x in self.sitemap_follow]
+
+ def start_requests(self):
+ return [Request(x, callback=self._parse_sitemap) for x in self.sitemap_urls]
+
+ def _parse_sitemap(self, response):
+ if response.url.endswith('/robots.txt'):
+ for url in sitemap_urls_from_robots(response.body):
+ yield Request(url, callback=self._parse_sitemap)
+ else:
+ if isinstance(response, XmlResponse):
+ body = response.body
+ elif is_gzipped(response):
+ body = gunzip(response.body)
+ else:
+ log.msg("Ignoring non-XML sitemap: %s" % response, log.WARNING)
+ return
+
+ s = Sitemap(body)
+ if s.type == 'sitemapindex':
+ for loc in iterloc(s):
+ if any(x.search(loc) for x in self._follow):
+ yield Request(loc, callback=self._parse_sitemap)
+ elif s.type == 'urlset':
+ for loc in iterloc(s):
+ for r, c in self._cbs:
+ if r.search(loc):
+ yield Request(loc, callback=c)
+ break
+
+def is_gzipped(response):
+ ctype = response.headers.get('Content-Type', '')
+ return ctype in ('application/x-gzip', 'application/gzip')
+
+def regex(x):
+ if isinstance(x, basestring):
+ return re.compile(x)
+ return x
+
+def iterloc(it):
+ for d in it:
+ yield d['loc']
diff --git a/scrapy/contrib/statscol.py b/scrapy/contrib/statscol.py
deleted file mode 100644
index ff52f0b41..000000000
--- a/scrapy/contrib/statscol.py
+++ /dev/null
@@ -1,57 +0,0 @@
-"""
-A Stats collector for persisting stats to Amazon SimpleDB.
-
-Requires the boto library: http://code.google.com/p/boto/
-"""
-
-from datetime import datetime
-
-from twisted.internet import threads
-
-from scrapy.utils.simpledb import to_sdb_value
-from scrapy.statscol import StatsCollector
-from scrapy import log
-from scrapy.conf import settings
-
-class SimpledbStatsCollector(StatsCollector):
-
- def __init__(self):
- super(SimpledbStatsCollector, self).__init__()
- self._sdbdomain = settings['STATS_SDB_DOMAIN']
- self._access_key = settings['AWS_ACCESS_KEY_ID']
- self._secret_key = settings['AWS_SECRET_ACCESS_KEY']
-
- self._async = settings.getbool('STATS_SDB_ASYNC')
- import boto
- self.connect_sdb = boto.connect_sdb
- self.connect_sdb(aws_access_key_id=self._access_key, aws_secret_access_key=self._secret_key).create_domain(self._sdbdomain)
-
- def _persist_stats(self, stats, spider=None):
- if spider is None: # only store spider-specific stats
- return
- if not self._sdbdomain:
- return
- if self._async:
- dfd = threads.deferToThread(self._persist_to_sdb, spider, stats.copy())
- dfd.addErrback(log.err, 'Error uploading stats to SimpleDB', \
- spider=spider)
- else:
- self._persist_to_sdb(spider, stats)
-
- def _persist_to_sdb(self, spider, stats):
- ts = self._get_timestamp(spider).isoformat()
- sdb_item_id = "%s_%s" % (spider.name, ts)
- sdb_item = dict((k, self._to_sdb_value(v, k)) for k, v in stats.iteritems())
- sdb_item['spider'] = spider.name
- sdb_item['timestamp'] = self._to_sdb_value(ts)
- self.connect_sdb(aws_access_key_id=self._access_key, aws_secret_access_key=self._secret_key).put_attributes(self._sdbdomain, sdb_item_id, sdb_item)
-
- def _get_timestamp(self, spider):
- return datetime.utcnow()
-
- def _to_sdb_value(self, obj, key=None):
- try:
- return to_sdb_value(obj)
- except TypeError:
- raise TypeError("%s unsupported type %r used in key %r" % \
- (type(self).__name__, type(obj).__name__, key))
diff --git a/scrapy/contrib/throttle.py b/scrapy/contrib/throttle.py
new file mode 100644
index 000000000..228af2021
--- /dev/null
+++ b/scrapy/contrib/throttle.py
@@ -0,0 +1,120 @@
+# TODO: this extension is currently broken and needs to be ported after the
+# downloader refactoring introduced in r2732
+
+from scrapy.xlib.pydispatch import dispatcher
+from scrapy.utils.python import setattr_default
+from scrapy.conf import settings
+from scrapy.exceptions import NotConfigured
+from scrapy import signals
+
+class AutoThrottle(object):
+ """
+ ============
+ AutoThrottle
+ ============
+
+ This is an extension for automatically throttling crawling speed based on
+ load.
+
+ 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
+ doesn't have to tune the download delays and concurrent requests to find
+ the optimum one. the user only needs to specify the maximum concurrent
+ requests it allows, and the extension does the rest.
+
+ Download latencies
+ ==================
+
+ In Scrapy, the download latency is the (real) time elapsed between
+ establishing the TCP connection and receiving the HTTP headers.
+
+ Note that these latencies are very hard to measure accurately in a
+ cooperative multitasking environment because Scrapy may be busy processing
+ a spider callback, for example, and unable to attend downloads. However,
+ the latencies should give a reasonable estimate of how busy Scrapy (and
+ ultimately, the server) is. This extension builds on that premise.
+
+ Throttling rules
+ ================
+
+ This adjusts download delays and concurrency based on the following rules:
+
+ 1. spiders always start with one concurrent request and a download delay of
+ START_DELAY
+
+ 2. when a response is received, the download delay is adjusted to the
+ average of previous download delay and the latency of the response.
+
+ 3. after CONCURRENCY_CHECK_PERIOD responses have passed, the average
+ latency of this period is checked against the previous one and:
+
+ 3.1. if the latency remained constant (within standard deviation limits)
+ and the concurrency is lower than MAX_CONCURRENCY, the concurrency is
+ increased
+
+ 3.2. if the latency has increased (beyond standard deviation limits) and
+ the concurrency is higher than 1, the concurrency is decreased
+
+ """
+
+ # TODO: convert these to settings
+ START_DELAY = 5.0
+ MAX_CONCURRENCY = 8
+ CONCURRENCY_CHECK_PERIOD = 10
+
+ DEBUG = 0
+
+ def __init__(self):
+ if not settings.getbool('AUTOTHROTTLE_ENABLED'):
+ raise NotConfigured
+ dispatcher.connect(self.spider_opened, signal=signals.spider_opened)
+ dispatcher.connect(self.spider_closed, signal=signals.spider_closed)
+ dispatcher.connect(self.response_received, signal=signals.response_received)
+ self.last_latencies = {}
+ self.last_lat = {}
+
+ def spider_opened(self, spider):
+ spider.download_delay = self.START_DELAY
+ spider.max_concurrent_requests = 1
+ self.last_latencies[spider] = [self.START_DELAY]
+ self.last_lat[spider] = self.START_DELAY, 0.0
+
+ def spider_closed(self, spider):
+ del self.last_latencies[spider]
+ del self.last_lat[spider]
+
+ def response_received(self, response, spider):
+ latency = response.meta.get('download_latency')
+ if not latency:
+ return
+ spider.download_delay = (spider.download_delay + latency) / 2.0
+ self._check_concurrency(spider, latency)
+ if self.DEBUG:
+ print "conc:%2d | delay:%5d ms | latency:%5d ms | size:%6d bytes" % \
+ (spider.max_concurrent_requests, spider.download_delay*1000, \
+ latency*1000, len(response.body))
+
+ def _check_concurrency(self, spider, latency):
+ latencies = self.last_latencies[spider]
+ latencies.append(latency)
+ if len(latencies) == self.CONCURRENCY_CHECK_PERIOD:
+ curavg, curdev = avg_stdev(latencies)
+ preavg, predev = self.last_lat[spider]
+ self.last_lat[spider] = curavg, curdev
+ del latencies[:]
+ if curavg > preavg + predev:
+ if spider.max_concurrent_requests > 1:
+ spider.max_concurrent_requests -= 1
+ elif spider.max_concurrent_requests < self.MAX_CONCURRENCY:
+ spider.max_concurrent_requests += 1
+
+def avg_stdev(lst):
+ """Return average and standard deviation of the given list"""
+ avg = sum(lst)/len(lst)
+ sdsq = sum((x-avg) ** 2 for x in lst)
+ stdev = (sdsq / (len(lst) -1)) ** 0.5
+ return avg, stdev
diff --git a/scrapy/contrib/webservice/crawler.py b/scrapy/contrib/webservice/crawler.py
index 04c38ce02..f25d90474 100644
--- a/scrapy/contrib/webservice/crawler.py
+++ b/scrapy/contrib/webservice/crawler.py
@@ -1,10 +1,8 @@
from scrapy.webservice import JsonRpcResource
-from scrapy.project import crawler
class CrawlerResource(JsonRpcResource):
ws_name = 'crawler'
- def __init__(self, _crawler=crawler):
- JsonRpcResource.__init__(self)
- self._target = _crawler
+ def __init__(self, crawler):
+ JsonRpcResource.__init__(self, crawler, crawler)
diff --git a/scrapy/contrib/webservice/enginestatus.py b/scrapy/contrib/webservice/enginestatus.py
index 2e2469c01..20e806423 100644
--- a/scrapy/contrib/webservice/enginestatus.py
+++ b/scrapy/contrib/webservice/enginestatus.py
@@ -1,19 +1,17 @@
from scrapy.webservice import JsonResource
-from scrapy.project import crawler
from scrapy.utils.engine import get_engine_status
class EngineStatusResource(JsonResource):
ws_name = 'enginestatus'
- def __init__(self, spider_name=None, _crawler=crawler):
- JsonResource.__init__(self)
+ def __init__(self, crawler, spider_name=None):
+ JsonResource.__init__(self, crawler)
self._spider_name = spider_name
self.isLeaf = spider_name is not None
- self._crawler = _crawler
def render_GET(self, txrequest):
- status = get_engine_status(self._crawler.engine)
+ status = get_engine_status(self.crawler.engine)
if self._spider_name is None:
return status
for sp, st in status['spiders'].items():
@@ -21,4 +19,4 @@ class EngineStatusResource(JsonResource):
return st
def getChild(self, name, txrequest):
- return EngineStatusResource(name, self._crawler)
+ return EngineStatusResource(name, self.crawler)
diff --git a/scrapy/contrib/webservice/stats.py b/scrapy/contrib/webservice/stats.py
index 3ab2efce3..623758c20 100644
--- a/scrapy/contrib/webservice/stats.py
+++ b/scrapy/contrib/webservice/stats.py
@@ -5,6 +5,5 @@ class StatsResource(JsonRpcResource):
ws_name = 'stats'
- def __init__(self, _stats=stats):
- JsonRpcResource.__init__(self)
- self._target = _stats
+ def __init__(self, crawler):
+ JsonRpcResource.__init__(self, crawler, stats)
diff --git a/scrapy/contrib_exp/crawlspider/__init__.py b/scrapy/contrib_exp/crawlspider/__init__.py
deleted file mode 100644
index 03173eb38..000000000
--- a/scrapy/contrib_exp/crawlspider/__init__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-"""CrawlSpider v2"""
-
-from .rules import Rule
-from .spider import CrawlSpider
diff --git a/scrapy/contrib_exp/crawlspider/matchers.py b/scrapy/contrib_exp/crawlspider/matchers.py
deleted file mode 100644
index 3ef259c67..000000000
--- a/scrapy/contrib_exp/crawlspider/matchers.py
+++ /dev/null
@@ -1,61 +0,0 @@
-"""
-Request/Response Matchers
-
-Perform evaluation to Request or Response attributes
-"""
-
-import re
-
-class BaseMatcher(object):
- """Base matcher. Returns True by default."""
-
- def matches_request(self, request):
- """Performs Request Matching"""
- return True
-
- def matches_response(self, response):
- """Performs Response Matching"""
- return True
-
-
-class UrlMatcher(BaseMatcher):
- """Matches URL attribute"""
-
- def __init__(self, url):
- """Initialize url attribute"""
- self._url = url
-
- def matches_url(self, url):
- """Returns True if given url is equal to matcher's url"""
- return self._url == url
-
- def matches_request(self, request):
- """Returns True if Request's url matches initial url"""
- return self.matches_url(request.url)
-
- def matches_response(self, response):
- """Returns True if Response's url matches initial url"""
- return self.matches_url(response.url)
-
-
-class UrlRegexMatcher(UrlMatcher):
- """Matches URL using regular expression"""
-
- def __init__(self, regex, flags=0):
- """Initialize regular expression"""
- self._regex = re.compile(regex, flags)
-
- def matches_url(self, url):
- """Returns True if url matches regular expression"""
- return self._regex.search(url) is not None
-
-
-class UrlListMatcher(UrlMatcher):
- """Matches if URL is in List"""
-
- def __init__(self, urls):
- self._urls = urls
-
- def matches_url(self, url):
- """Returns True if url is in urls list"""
- return url in self._urls
diff --git a/scrapy/contrib_exp/crawlspider/reqext.py b/scrapy/contrib_exp/crawlspider/reqext.py
deleted file mode 100644
index 98210fa11..000000000
--- a/scrapy/contrib_exp/crawlspider/reqext.py
+++ /dev/null
@@ -1,112 +0,0 @@
-"""Request Extractors"""
-from scrapy.http import Request
-from scrapy.selector import HtmlXPathSelector
-from scrapy.utils.misc import arg_to_iter
-from scrapy.utils.python import FixedSGMLParser, str_to_unicode
-from scrapy.utils.url import safe_url_string, urljoin_rfc
-
-from itertools import ifilter
-
-
-class BaseSgmlRequestExtractor(FixedSGMLParser):
- """Base SGML Request Extractor"""
-
- def __init__(self, tag='a', attr='href'):
- """Initialize attributes"""
- FixedSGMLParser.__init__(self)
-
- self.scan_tag = tag if callable(tag) else lambda t: t == tag
- self.scan_attr = attr if callable(attr) else lambda a: a == attr
- self.current_request = None
-
- def extract_requests(self, response):
- """Returns list of requests extracted from response"""
- return self._extract_requests(response.body, response.url,
- response.encoding)
-
- def _extract_requests(self, response_text, response_url, response_encoding):
- """Extract requests with absolute urls"""
- self.reset()
- self.feed(response_text)
- self.close()
-
- base_url = urljoin_rfc(response_url, self.base_url) if self.base_url else response_url
- self._make_absolute_urls(base_url, response_encoding)
- self._fix_link_text_encoding(response_encoding)
-
- return self.requests
-
- def _make_absolute_urls(self, base_url, encoding):
- """Makes all request's urls absolute"""
- self.requests = [x.replace(url=safe_url_string(urljoin_rfc(base_url, \
- x.url, encoding), encoding)) for x in self.requests]
-
- def _fix_link_text_encoding(self, encoding):
- """Convert link_text to unicode for each request"""
- for req in self.requests:
- req.meta.setdefault('link_text', '')
- req.meta['link_text'] = str_to_unicode(req.meta['link_text'],
- encoding)
-
- def reset(self):
- """Reset state"""
- FixedSGMLParser.reset(self)
- self.requests = []
- self.base_url = None
-
- def unknown_starttag(self, tag, attrs):
- """Process unknown start tag"""
- if 'base' == tag:
- self.base_url = dict(attrs).get('href')
-
- _matches = lambda (attr, value): self.scan_attr(attr) \
- and value is not None
- if self.scan_tag(tag):
- for attr, value in ifilter(_matches, attrs):
- req = Request(url=value)
- self.requests.append(req)
- self.current_request = req
-
- def unknown_endtag(self, tag):
- """Process unknown end tag"""
- self.current_request = None
-
- def handle_data(self, data):
- """Process data"""
- current = self.current_request
- if current and not 'link_text' in current.meta:
- current.meta['link_text'] = data.strip()
-
-
-class SgmlRequestExtractor(BaseSgmlRequestExtractor):
- """SGML Request Extractor"""
-
- def __init__(self, tags=None, attrs=None):
- """Initialize with custom tag & attribute function checkers"""
- # defaults
- tags = tuple(tags) if tags else ('a', 'area')
- attrs = tuple(attrs) if attrs else ('href', )
-
- tag_func = lambda x: x in tags
- attr_func = lambda x: x in attrs
- BaseSgmlRequestExtractor.__init__(self, tag=tag_func, attr=attr_func)
-
-# TODO: move to own file
-class XPathRequestExtractor(SgmlRequestExtractor):
- """SGML Request Extractor with XPath restriction"""
-
- def __init__(self, restrict_xpaths, tags=None, attrs=None):
- """Initialize XPath restrictions"""
- self.restrict_xpaths = tuple(arg_to_iter(restrict_xpaths))
- SgmlRequestExtractor.__init__(self, tags, attrs)
-
- def extract_requests(self, response):
- """Restrict to XPath regions"""
- hxs = HtmlXPathSelector(response)
- fragments = (''.join(
- html_frag for html_frag in hxs.select(xpath).extract()
- ) for xpath in self.restrict_xpaths)
- html_slice = ''.join(html_frag for html_frag in fragments)
- return self._extract_requests(html_slice, response.url,
- response.encoding)
-
diff --git a/scrapy/contrib_exp/crawlspider/reqgen.py b/scrapy/contrib_exp/crawlspider/reqgen.py
deleted file mode 100644
index 3858fbcf7..000000000
--- a/scrapy/contrib_exp/crawlspider/reqgen.py
+++ /dev/null
@@ -1,27 +0,0 @@
-"""Request Generator"""
-from itertools import imap
-
-class RequestGenerator(object):
- """Extracto and process requests from response"""
-
- def __init__(self, req_extractors, req_processors, callback, spider=None):
- """Initialize attributes"""
- self._request_extractors = req_extractors
- self._request_processors = req_processors
- #TODO: resolve callback?
- self._callback = callback
-
- def generate_requests(self, response):
- """Extract and process new requests from response.
- Attach callback to each request as default callback."""
- requests = []
- for ext in self._request_extractors:
- requests.extend(ext.extract_requests(response))
-
- for proc in self._request_processors:
- requests = proc(requests)
-
- # return iterator
- # @@@ creates new Request object with callback
- return imap(lambda r: r.replace(callback=self._callback), requests)
-
diff --git a/scrapy/contrib_exp/crawlspider/reqproc.py b/scrapy/contrib_exp/crawlspider/reqproc.py
deleted file mode 100644
index adc07005a..000000000
--- a/scrapy/contrib_exp/crawlspider/reqproc.py
+++ /dev/null
@@ -1,107 +0,0 @@
-"""Request Processors"""
-from scrapy.utils.misc import arg_to_iter
-from scrapy.utils.url import canonicalize_url, url_is_from_any_domain
-
-from itertools import ifilter
-
-import re
-
-class Canonicalize(object):
- """Canonicalize Request Processor"""
-
- def __call__(self, requests):
- """Canonicalize all requests' urls"""
- return (x.replace(url=canonicalize_url(x.url)) for x in requests)
-
-
-class FilterDupes(object):
- """Filter duplicate Requests"""
-
- def __init__(self, *attributes):
- """Initialize comparison attributes"""
- self._attributes = tuple(attributes) if attributes \
- else tuple(['url'])
-
- def _equal_attr(self, obj1, obj2, attr):
- return getattr(obj1, attr) == getattr(obj2, attr)
-
- def _requests_equal(self, req1, req2):
- """Attribute comparison helper"""
- # look for not equal attribute
- _not_equal = lambda attr: not self._equal_attr(req1, req2, attr)
- for attr in ifilter(_not_equal, self._attributes):
- return False
- # all attributes equal
- return True
-
- def _request_in(self, request, requests_seen):
- """Check if request is in given requests seen list"""
- _req_seen = lambda r: self._requests_equal(r, request)
- for seen in ifilter(_req_seen, requests_seen):
- return True
- # request not seen
- return False
-
- def __call__(self, requests):
- """Filter seen requests"""
- # per-call duplicates filter
- self.requests_seen = set()
- _not_seen = lambda r: not self._request_in(r, self.requests_seen)
- for req in ifilter(_not_seen, requests):
- yield req
- # registry seen request
- self.requests_seen.add(req)
-
-
-class FilterDomain(object):
- """Filter request's domain"""
-
- def __init__(self, allow=(), deny=()):
- """Initialize allow/deny attributes"""
- self.allow = tuple(arg_to_iter(allow))
- self.deny = tuple(arg_to_iter(deny))
-
- def __call__(self, requests):
- """Filter domains"""
- processed = (req for req in requests)
-
- if self.allow:
- processed = (req for req in requests
- if url_is_from_any_domain(req.url, self.allow))
- if self.deny:
- processed = (req for req in requests
- if not url_is_from_any_domain(req.url, self.deny))
-
- return processed
-
-
-class FilterUrl(object):
- """Filter request's url"""
-
- def __init__(self, allow=(), deny=()):
- """Initialize allow/deny attributes"""
- _re_type = type(re.compile('', 0))
-
- self.allow_res = [x if isinstance(x, _re_type) else re.compile(x)
- for x in arg_to_iter(allow)]
- self.deny_res = [x if isinstance(x, _re_type) else re.compile(x)
- for x in arg_to_iter(deny)]
-
- def __call__(self, requests):
- """Filter request's url based on allow/deny rules"""
- #TODO: filter valid urls here?
- processed = (req for req in requests)
-
- if self.allow_res:
- processed = (req for req in requests
- if self._matches(req.url, self.allow_res))
- if self.deny_res:
- processed = (req for req in requests
- if not self._matches(req.url, self.deny_res))
-
- return processed
-
- def _matches(self, url, regexs):
- """Returns True if url matches any regex in given list"""
- return any(r.search(url) for r in regexs)
-
diff --git a/scrapy/contrib_exp/crawlspider/rules.py b/scrapy/contrib_exp/crawlspider/rules.py
deleted file mode 100644
index ff1691ad0..000000000
--- a/scrapy/contrib_exp/crawlspider/rules.py
+++ /dev/null
@@ -1,100 +0,0 @@
-"""Crawler Rules"""
-from scrapy.http import Request
-from scrapy.http import Response
-
-from functools import partial
-from itertools import ifilter
-
-from .matchers import BaseMatcher
-# default strint-to-matcher class
-from .matchers import UrlRegexMatcher
-
-class CompiledRule(object):
- """Compiled version of Rule"""
- def __init__(self, matcher, callback=None, follow=False):
- """Initialize attributes checking type"""
- assert isinstance(matcher, BaseMatcher)
- assert callback is None or callable(callback)
- assert isinstance(follow, bool)
-
- self.matcher = matcher
- self.callback = callback
- self.follow = follow
-
-
-class Rule(object):
- """Crawler Rule"""
- def __init__(self, matcher=None, callback=None, follow=False, **kwargs):
- """Store attributes"""
- self.matcher = matcher
- self.callback = callback
- self.cb_kwargs = kwargs if kwargs else {}
- self.follow = True if follow else False
-
- if self.callback is None and self.follow is False:
- raise ValueError("Rule must either have a callback or "
- "follow=True: %r" % self)
-
- def __repr__(self):
- return "Rule(matcher=%r, callback=%r, follow=%r, **%r)" \
- % (self.matcher, self.callback, self.follow, self.cb_kwargs)
-
-
-class RulesManager(object):
- """Rules Manager"""
- def __init__(self, rules, spider, default_matcher=UrlRegexMatcher):
- """Initialize rules using spider and default matcher"""
- self._rules = tuple()
-
- # compile absolute/relative-to-spider callbacks"""
- for rule in rules:
- # prepare matcher
- if rule.matcher is None:
- # instance BaseMatcher by default
- matcher = BaseMatcher()
- elif isinstance(rule.matcher, BaseMatcher):
- matcher = rule.matcher
- else:
- # matcher not BaseMatcher, check for string
- if isinstance(rule.matcher, basestring):
- # instance default matcher
- matcher = default_matcher(rule.matcher)
- else:
- raise ValueError('Not valid matcher given %r in %r' \
- % (rule.matcher, rule))
-
- # prepare callback
- if callable(rule.callback):
- callback = rule.callback
- elif not rule.callback is None:
- # callback from spider
- callback = getattr(spider, rule.callback)
-
- if not callable(callback):
- raise AttributeError('Invalid callback %r can not be resolved' \
- % callback)
- else:
- callback = None
-
- if rule.cb_kwargs:
- # build partial callback
- callback = partial(callback, **rule.cb_kwargs)
-
- # append compiled rule to rules list
- crule = CompiledRule(matcher, callback, follow=rule.follow)
- self._rules += (crule, )
-
- def get_rule_from_request(self, request):
- """Returns first rule that matches given Request"""
- _matches = lambda r: r.matcher.matches_request(request)
- for rule in ifilter(_matches, self._rules):
- # return first match of iterator
- return rule
-
- def get_rule_from_response(self, response):
- """Returns first rule that matches given Response"""
- _matches = lambda r: r.matcher.matches_response(response)
- for rule in ifilter(_matches, self._rules):
- # return first match of iterator
- return rule
-
diff --git a/scrapy/contrib_exp/crawlspider/spider.py b/scrapy/contrib_exp/crawlspider/spider.py
deleted file mode 100644
index e2bf1a34b..000000000
--- a/scrapy/contrib_exp/crawlspider/spider.py
+++ /dev/null
@@ -1,69 +0,0 @@
-"""CrawlSpider v2"""
-from scrapy.spider import BaseSpider
-from scrapy.utils.spider import iterate_spider_output
-
-from .matchers import UrlListMatcher
-from .rules import Rule, RulesManager
-from .reqext import SgmlRequestExtractor
-from .reqgen import RequestGenerator
-from .reqproc import Canonicalize, FilterDupes
-
-class CrawlSpider(BaseSpider):
- """CrawlSpider v2"""
-
- request_extractors = None
- request_processors = None
- rules = []
-
- def __init__(self, *a, **kw):
- """Initialize dispatcher"""
- super(CrawlSpider, self).__init__(*a, **kw)
-
- # auto follow start urls
- if self.start_urls:
- _matcher = UrlListMatcher(self.start_urls)
- # append new rule using type from current self.rules
- rules = self.rules + type(self.rules)([
- Rule(_matcher, follow=True)
- ])
- else:
- rules = self.rules
-
- # set defaults if not set
- if self.request_extractors is None:
- # default link extractor. Extracts all links from response
- self.request_extractors = [ SgmlRequestExtractor() ]
-
- if self.request_processors is None:
- # default proccessor. Filter duplicates requests
- self.request_processors = [ FilterDupes() ]
-
-
- # wrap rules
- self._rulesman = RulesManager(rules, spider=self)
- # generates new requests with given callback
- self._reqgen = RequestGenerator(self.request_extractors,
- self.request_processors,
- callback=self.parse)
-
- def parse(self, response):
- """Dispatch callback and generate requests"""
- # get rule for response
- rule = self._rulesman.get_rule_from_response(response)
-
- if rule:
- # dispatch callback if set
- if rule.callback:
- output = iterate_spider_output(rule.callback(response))
- for req_or_item in output:
- yield req_or_item
-
- if rule.follow:
- for req in self._reqgen.generate_requests(response):
- # only dispatch request if has matching rule
- if self._rulesman.get_rule_from_request(req):
- yield req
- else:
- self.log("No rule for response %s" % response, level=log.WARNING)
-
-
diff --git a/scrapy/contrib_exp/djangoitem.py b/scrapy/contrib_exp/djangoitem.py
index dfef58dac..1abe98bfd 100644
--- a/scrapy/contrib_exp/djangoitem.py
+++ b/scrapy/contrib_exp/djangoitem.py
@@ -11,8 +11,7 @@ class DjangoItemMeta(ItemMeta):
cls._model_fields = []
cls._model_meta = cls.django_model._meta
for model_field in cls._model_meta.fields:
- # XXX: for now we're treating each PK as autogenerated field
- if model_field != cls._model_meta.pk:
+ if model_field.auto_created == False:
if model_field.name not in cls.fields:
cls.fields[model_field.name] = Field()
cls._model_fields.append(model_field.name)
@@ -31,4 +30,3 @@ class DjangoItem(Item):
if commit:
model.save()
return model
-
diff --git a/scrapy/contrib_exp/downloadermiddleware/decompression.py b/scrapy/contrib_exp/downloadermiddleware/decompression.py
index 83bc2bb97..397c9e093 100644
--- a/scrapy/contrib_exp/downloadermiddleware/decompression.py
+++ b/scrapy/contrib_exp/downloadermiddleware/decompression.py
@@ -11,7 +11,7 @@ from tempfile import mktemp
from scrapy import log
from scrapy.http import Response
-from scrapy.core.downloader.responsetypes import responsetypes
+from scrapy.responsetypes import responsetypes
class DecompressionMiddleware(object):
diff --git a/scrapy/contrib_exp/iterators.py b/scrapy/contrib_exp/iterators.py
index 0fc73e194..0f3a8c694 100644
--- a/scrapy/contrib_exp/iterators.py
+++ b/scrapy/contrib_exp/iterators.py
@@ -2,14 +2,19 @@ from scrapy.http import Response
from scrapy.selector import XmlXPathSelector
-def xmliter_lxml(obj, nodename):
+def xmliter_lxml(obj, nodename, namespace=None):
from lxml import etree
reader = _StreamReader(obj)
- iterable = etree.iterparse(reader, tag=nodename, encoding=reader.encoding)
+ tag = '{%s}%s' % (namespace, nodename) if namespace else nodename
+ iterable = etree.iterparse(reader, tag=tag, encoding=reader.encoding)
+ selxpath = '//' + ('x:%s' % nodename if namespace else nodename)
for _, node in iterable:
nodetext = etree.tostring(node)
node.clear()
- yield XmlXPathSelector(text=nodetext).select('//' + nodename)[0]
+ xs = XmlXPathSelector(text=nodetext)
+ if namespace:
+ xs.register_namespace('x', namespace)
+ yield xs.select(selxpath)[0]
class _StreamReader(object):
diff --git a/scrapy/core/downloader/__init__.py b/scrapy/core/downloader/__init__.py
index 8eb99d9d0..b4768f5a9 100644
--- a/scrapy/core/downloader/__init__.py
+++ b/scrapy/core/downloader/__init__.py
@@ -1,162 +1,141 @@
-"""
-Download web pages using asynchronous IO
-"""
-
import random
+import warnings
from time import time
+from collections import deque
+from functools import partial
from twisted.internet import reactor, defer
from twisted.python.failure import Failure
-from scrapy.exceptions import IgnoreRequest
-from scrapy.conf import settings
from scrapy.utils.defer import mustbe_deferred
from scrapy.utils.signal import send_catch_log
-from scrapy.utils import deprecate
+from scrapy.utils.httpobj import urlparse_cached
+from scrapy.resolver import dnscache
+from scrapy.exceptions import ScrapyDeprecationWarning
from scrapy import signals
from scrapy import log
from .middleware import DownloaderMiddlewareManager
from .handlers import DownloadHandlers
+class Slot(object):
+ """Downloader slot"""
-class SpiderInfo(object):
- """Simple class to keep information and state for each open spider"""
-
- def __init__(self, spider):
- if hasattr(spider, 'download_delay'):
- deprecate.attribute(spider, 'download_delay', 'DOWNLOAD_DELAY')
- self._download_delay = spider.download_delay
- else:
- self._download_delay = spider.settings.getfloat('DOWNLOAD_DELAY')
- if self._download_delay:
- self.max_concurrent_requests = 1
- else:
- if hasattr(spider, 'max_concurrent_requests'):
- deprecate.attribute(spider, 'max_concurrent_requests', 'CONCURRENT_REQUESTS_PER_SPIDER')
- self.max_concurrent_requests = spider.max_concurrent_requests
- else:
- self.max_concurrent_requests = spider.settings.getint('CONCURRENT_REQUESTS_PER_SPIDER')
- if self._download_delay and spider.settings.getbool('RANDOMIZE_DOWNLOAD_DELAY'):
- # same policy as wget --random-wait
- self.random_delay_interval = (0.5*self._download_delay, \
- 1.5*self._download_delay)
- else:
- self.random_delay_interval = None
-
+ def __init__(self, concurrency, delay, settings):
+ self.concurrency = concurrency
+ self.delay = delay
+ self.randomize_delay = settings.getbool('RANDOMIZE_DOWNLOAD_DELAY')
self.active = set()
- self.queue = []
+ self.queue = deque()
self.transferring = set()
- self.closing = False
self.lastseen = 0
- self.next_request_calls = set()
def free_transfer_slots(self):
- return self.max_concurrent_requests - len(self.transferring)
-
- def needs_backout(self):
- # use self.active to include requests in the downloader middleware
- return len(self.active) > 2 * self.max_concurrent_requests
+ return self.concurrency - len(self.transferring)
def download_delay(self):
- if self.random_delay_interval:
- return random.uniform(*self.random_delay_interval)
- else:
- return self._download_delay
+ if self.randomize_delay:
+ return random.uniform(0.5*self.delay, 1.5*self.delay)
+ return self.delay
- def cancel_request_calls(self):
- for call in self.next_request_calls:
- call.cancel()
- self.next_request_calls.clear()
+
+def _get_concurrency_delay(concurrency, spider, settings):
+ delay = settings.getfloat('DOWNLOAD_DELAY')
+ if hasattr(spider, 'download_delay'):
+ delay = spider.download_delay
+
+ # TODO: remove for Scrapy 0.15
+ c = settings.getint('CONCURRENT_REQUESTS_PER_SPIDER')
+ if c:
+ warnings.warn("CONCURRENT_REQUESTS_PER_SPIDER setting is deprecated, " \
+ "use CONCURRENT_REQUESTS_PER_DOMAIN instead", ScrapyDeprecationWarning)
+ concurrency = c
+ # ----------------------------
+
+ if hasattr(spider, 'max_concurrent_requests'):
+ concurrency = spider.max_concurrent_requests
+
+ if delay > 0:
+ concurrency = 1 # force concurrency=1 if download delay required
+
+ return concurrency, delay
class Downloader(object):
- """Mantain many concurrent downloads and provide an HTTP abstraction.
- It supports a limited number of connections per spider and many spiders in
- parallel.
- """
- def __init__(self):
- self.sites = {}
+ def __init__(self, crawler):
+ self.settings = crawler.settings
+ self.slots = {}
+ self.active = set()
self.handlers = DownloadHandlers()
- self.middleware = DownloaderMiddlewareManager.from_settings(settings)
- self.concurrent_spiders = settings.getint('CONCURRENT_SPIDERS')
+ self.total_concurrency = self.settings.getint('CONCURRENT_REQUESTS')
+ self.domain_concurrency = self.settings.getint('CONCURRENT_REQUESTS_PER_DOMAIN')
+ self.ip_concurrency = self.settings.getint('CONCURRENT_REQUESTS_PER_IP')
+ self.middleware = DownloaderMiddlewareManager.from_crawler(crawler)
+
def fetch(self, request, spider):
- """Main method to use to request a download
+ key, slot = self._get_slot(request, spider)
- This method includes middleware mangling. Middleware can returns a
- Response object, then request never reach downloader queue, and it will
- not be downloaded from site.
- """
- site = self.sites[spider]
- if site.closing:
- raise IgnoreRequest('Cannot fetch on a closing spider')
-
- site.active.add(request)
+ self.active.add(request)
+ slot.active.add(request)
def _deactivate(response):
- send_catch_log(signal=signals.response_received, \
- response=response, request=request, spider=spider)
- site.active.remove(request)
- self._close_if_idle(spider)
+ self.active.remove(request)
+ slot.active.remove(request)
+ if not slot.active: # remove empty slots
+ del self.slots[key]
return response
- dfd = self.middleware.download(self.enqueue, request, spider)
+ dlfunc = partial(self._enqueue_request, slot=slot)
+ dfd = self.middleware.download(dlfunc, request, spider)
return dfd.addBoth(_deactivate)
- def enqueue(self, request, spider):
- """Enqueue a Request for a effective download from site"""
- site = self.sites[spider]
- if site.closing:
- raise IgnoreRequest
+ def needs_backout(self):
+ return len(self.active) >= self.total_concurrency
+ def _get_slot(self, request, spider):
+ key = urlparse_cached(request).hostname or ''
+ if self.ip_concurrency:
+ key = dnscache.get(key, key)
+ if key not in self.slots:
+ if self.ip_concurrency:
+ concurrency = self.ip_concurrency
+ else:
+ concurrency = self.domain_concurrency
+ concurrency, delay = _get_concurrency_delay(concurrency, spider, self.settings)
+ self.slots[key] = Slot(concurrency, delay, self.settings)
+ return key, self.slots[key]
+
+ def _enqueue_request(self, request, spider, slot):
def _downloaded(response):
send_catch_log(signal=signals.response_downloaded, \
response=response, request=request, spider=spider)
return response
deferred = defer.Deferred().addCallback(_downloaded)
- site.queue.append((request, deferred))
- self._process_queue(spider)
+ slot.queue.append((request, deferred))
+ self._process_queue(spider, slot)
return deferred
- def _process_queue(self, spider):
- """Effective download requests from site queue"""
- site = self.sites.get(spider)
- if not site:
- return
-
+ def _process_queue(self, spider, slot):
# Delay queue processing if a download_delay is configured
now = time()
- delay = site.download_delay()
+ delay = slot.download_delay()
if delay:
- penalty = delay - now + site.lastseen
- if penalty > 0:
+ penalty = delay - now + slot.lastseen
+ if penalty > 0 and slot.free_transfer_slots():
d = defer.Deferred()
- d.addCallback(self._process_queue)
- call = reactor.callLater(penalty, d.callback, spider)
- site.next_request_calls.add(call)
- d.addBoth(lambda x: site.next_request_calls.remove(call))
+ d.addCallback(self._process_queue, slot)
+ reactor.callLater(penalty, d.callback, spider)
return
- site.lastseen = now
+ slot.lastseen = now
- # Process enqueued requests if there are free slots to transfer for this site
- while site.queue and site.free_transfer_slots() > 0:
- request, deferred = site.queue.pop(0)
- if site.closing:
- dfd = defer.fail(Failure(IgnoreRequest()))
- else:
- dfd = self._download(site, request, spider)
+ # Process enqueued requests if there are free slots to transfer for this slot
+ while slot.queue and slot.free_transfer_slots() > 0:
+ request, deferred = slot.queue.popleft()
+ dfd = self._download(slot, request, spider)
dfd.chainDeferred(deferred)
- self._close_if_idle(spider)
-
- def _close_if_idle(self, spider):
- site = self.sites.get(spider)
- if site and site.closing and not site.active:
- del self.sites[spider]
- site.closing.callback(None)
-
- def _download(self, site, request, spider):
+ def _download(self, slot, request, spider):
# The order is very important for the following deferreds. Do not change!
# 1. Create the download deferred
@@ -166,33 +145,13 @@ class Downloader(object):
# state to free up the transferring slot so it can be used by the
# following requests (perhaps those which came from the downloader
# middleware itself)
- site.transferring.add(request)
+ slot.transferring.add(request)
def finish_transferring(_):
- site.transferring.remove(request)
- self._process_queue(spider)
- # avoid partially downloaded responses from propagating to the
- # downloader middleware, to speed-up the closing process
- if site.closing:
- log.msg("Crawled while closing spider: %s" % request, \
- level=log.DEBUG, spider=spider)
- raise IgnoreRequest
+ slot.transferring.remove(request)
+ self._process_queue(spider, slot)
return _
return dfd.addBoth(finish_transferring)
- def open_spider(self, spider):
- """Allocate resources to begin processing a spider"""
- assert spider not in self.sites, "Spider already opened: %s" % spider
- self.sites[spider] = SpiderInfo(spider)
-
- def close_spider(self, spider):
- """Free any resources associated with the given spider"""
- assert spider in self.sites, "Spider not opened: %s" % spider
- site = self.sites.get(spider)
- site.closing = defer.Deferred()
- site.cancel_request_calls()
- self._process_queue(spider)
- return site.closing
-
def is_idle(self):
- return not self.sites
+ return not self.slots
diff --git a/scrapy/core/downloader/handlers/file.py b/scrapy/core/downloader/handlers/file.py
index f53642f21..a63a5ffeb 100644
--- a/scrapy/core/downloader/handlers/file.py
+++ b/scrapy/core/downloader/handlers/file.py
@@ -1,5 +1,5 @@
-from scrapy.core.downloader.responsetypes import responsetypes
-from scrapy.utils.url import file_uri_to_path
+from w3lib.url import file_uri_to_path
+from scrapy.responsetypes import responsetypes
from scrapy.utils.decorator import defers
class FileDownloadHandler(object):
diff --git a/scrapy/core/downloader/handlers/s3.py b/scrapy/core/downloader/handlers/s3.py
index 9b89a7936..9033126c6 100644
--- a/scrapy/core/downloader/handlers/s3.py
+++ b/scrapy/core/downloader/handlers/s3.py
@@ -4,6 +4,29 @@ from scrapy.utils.httpobj import urlparse_cached
from scrapy.conf import settings
from .http import HttpDownloadHandler
+try:
+ from boto.s3.connection import S3Connection
+except ImportError:
+ S3Connection = object
+
+class _v19_S3Connection(S3Connection):
+ """A dummy S3Connection wrapper that doesn't do any syncronous download"""
+ def _mexe(self, method, bucket, key, headers, *args, **kwargs):
+ return headers
+
+class _v20_S3Connection(S3Connection):
+ """A dummy S3Connection wrapper that doesn't do any syncronous download"""
+ def _mexe(self, http_request, *args):
+ http_request.authorize(connection=self)
+ return http_request.headers
+
+try:
+ import boto.auth
+except ImportError:
+ _S3Connection = _v19_S3Connection
+else:
+ _S3Connection = _v20_S3Connection
+
class S3DownloadHandler(object):
@@ -17,9 +40,8 @@ class S3DownloadHandler(object):
if not aws_secret_access_key:
aws_secret_access_key = settings['AWS_SECRET_ACCESS_KEY']
- from boto import connect_s3
try:
- self.conn = connect_s3(aws_access_key_id, aws_secret_access_key)
+ self.conn = _S3Connection(aws_access_key_id, aws_secret_access_key)
except Exception, ex:
raise NotConfigured(str(ex))
self._download_http = httpdownloadhandler().download_request
@@ -27,8 +49,15 @@ class S3DownloadHandler(object):
def download_request(self, request, spider):
p = urlparse_cached(request)
scheme = 'https' if request.meta.get('is_secure') else 'http'
- url = '%s://%s.s3.amazonaws.com%s' % (scheme, p.hostname, p.path)
- httpreq = request.replace(url=url)
- self.conn.add_aws_auth_header(httpreq.headers, httpreq.method, \
- '%s/%s' % (p.hostname, p.path))
+ bucket = p.hostname
+ path = p.path + '?' + p.query if p.query else p.path
+ url = '%s://%s.s3.amazonaws.com%s' % (scheme, bucket, path)
+ signed_headers = self.conn.make_request(
+ method=request.method,
+ bucket=bucket,
+ key=p.path,
+ query_args=p.query,
+ headers=request.headers,
+ data=request.body)
+ httpreq = request.replace(url=url, headers=signed_headers)
return self._download_http(httpreq, spider)
diff --git a/scrapy/core/downloader/webclient.py b/scrapy/core/downloader/webclient.py
index 16ee24a3c..a1eaa7a07 100644
--- a/scrapy/core/downloader/webclient.py
+++ b/scrapy/core/downloader/webclient.py
@@ -1,3 +1,4 @@
+from time import time
from urlparse import urlparse, urlunparse, urldefrag
from twisted.python import failure
@@ -7,7 +8,7 @@ from twisted.internet import defer
from scrapy.http import Headers
from scrapy.utils.httpobj import urlparse_cached
-from scrapy.core.downloader.responsetypes import responsetypes
+from scrapy.responsetypes import responsetypes
def _parsed_url_args(parsed):
@@ -97,7 +98,8 @@ class ScrapyHTTPClientFactory(HTTPClientFactory):
self.headers = Headers(request.headers)
self.response_headers = None
self.timeout = request.meta.get('download_timeout') or timeout
- self.deferred = defer.Deferred().addCallback(self._build_response)
+ self.start_time = time()
+ self.deferred = defer.Deferred().addCallback(self._build_response, request)
self._set_connection_attributes(request)
@@ -110,7 +112,8 @@ class ScrapyHTTPClientFactory(HTTPClientFactory):
# just in case a broken http/1.1 decides to keep connection alive
self.headers.setdefault("Connection", "close")
- def _build_response(self, body):
+ def _build_response(self, body, request):
+ request.meta['download_latency'] = self.headers_time-self.start_time
status = int(self.status)
headers = Headers(self.response_headers)
respcls = responsetypes.from_args(headers=headers, url=self.url)
@@ -125,4 +128,5 @@ class ScrapyHTTPClientFactory(HTTPClientFactory):
self.path = self.url
def gotHeaders(self, headers):
+ self.headers_time = time()
self.response_headers = headers
diff --git a/scrapy/core/engine.py b/scrapy/core/engine.py
index 207517826..e545e89c2 100644
--- a/scrapy/core/engine.py
+++ b/scrapy/core/engine.py
@@ -6,31 +6,60 @@ For more information see docs/topics/architecture.rst
"""
from time import time
-from twisted.internet import reactor, defer
+from twisted.internet import defer
from twisted.python.failure import Failure
from scrapy import log, signals
from scrapy.stats import stats
from scrapy.core.downloader import Downloader
from scrapy.core.scraper import Scraper
-from scrapy.exceptions import IgnoreRequest, DontCloseSpider
+from scrapy.exceptions import DontCloseSpider
from scrapy.http import Response, Request
from scrapy.utils.misc import load_object
from scrapy.utils.signal import send_catch_log, send_catch_log_deferred
-from scrapy.utils.defer import mustbe_deferred
+from scrapy.utils.reactor import CallLaterOnce
+
+
+class Slot(object):
+
+ def __init__(self, start_requests, close_if_idle, nextcall, scheduler):
+ self.closing = False
+ self.inprogress = set() # requests in progress
+ self.start_requests = iter(start_requests)
+ self.close_if_idle = close_if_idle
+ self.nextcall = nextcall
+ self.scheduler = scheduler
+
+ def add_request(self, request):
+ self.inprogress.add(request)
+
+ def remove_request(self, request):
+ self.inprogress.remove(request)
+ self._maybe_fire_closing()
+
+ def close(self):
+ self.closing = defer.Deferred()
+ self._maybe_fire_closing()
+ return self.closing
+
+ def _maybe_fire_closing(self):
+ if self.closing and not self.inprogress:
+ if self.nextcall:
+ self.nextcall.cancel()
+ self.closing.callback(None)
+
class ExecutionEngine(object):
- def __init__(self, settings, spider_closed_callback):
- self.settings = settings
- self.closing = {} # dict (spider -> reason) of spiders being closed
- self.closing_dfds = {} # dict (spider -> deferred) of spiders being closed
+ def __init__(self, crawler, spider_closed_callback):
+ self.settings = crawler.settings
+ self.slots = {}
self.running = False
self.paused = False
- self._next_request_calls = {}
- self.scheduler = load_object(settings['SCHEDULER'])()
- self.downloader = Downloader()
- self.scraper = Scraper(self, self.settings)
+ self.scheduler_cls = load_object(self.settings['SCHEDULER'])
+ self.downloader = Downloader(crawler)
+ self.scraper = Scraper(crawler)
+ self._concurrent_spiders = self.settings.getint('CONCURRENT_SPIDERS')
self._spider_closed_callback = spider_closed_callback
@defer.inlineCallbacks
@@ -56,146 +85,139 @@ class ExecutionEngine(object):
"""Resume the execution engine"""
self.paused = False
- def is_idle(self):
- return self.scheduler.is_idle() and self.downloader.is_idle() and \
- self.scraper.is_idle()
-
- def next_request(self, spider, now=False):
- """Scrape the next request for the spider passed.
-
- The next request to be scraped is retrieved from the scheduler and
- requested from the downloader.
-
- The spider is closed if there are no more pages to scrape.
- """
- if now:
- self._next_request_calls.pop(spider, None)
- elif spider not in self._next_request_calls:
- call = reactor.callLater(0, self.next_request, spider, now=True)
- self._next_request_calls[spider] = call
- return call
- else:
+ def _next_request(self, spider):
+ try:
+ slot = self.slots[spider]
+ except KeyError:
return
if self.paused:
- return reactor.callLater(5, self.next_request, spider)
+ slot.nextcall.schedule(5)
+ return
while not self._needs_backout(spider):
- if not self._next_request(spider):
+ if not self._next_request_from_scheduler(spider):
break
- if self.spider_is_idle(spider):
+ if slot.start_requests and not self._needs_backout(spider):
+ try:
+ request = slot.start_requests.next()
+ self.crawl(request, spider)
+ except StopIteration:
+ slot.start_requests = None
+
+ if self.spider_is_idle(spider) and slot.close_if_idle:
self._spider_idle(spider)
def _needs_backout(self, spider):
+ slot = self.slots[spider]
return not self.running \
- or self.spider_is_closed(spider) \
- or self.downloader.sites[spider].needs_backout() \
- or self.scraper.sites[spider].needs_backout()
+ or slot.closing \
+ or self.downloader.needs_backout() \
+ or self.scraper.slots[spider].needs_backout()
- def _next_request(self, spider):
- # Next pending request from scheduler
- request, deferred = self.scheduler.next_request(spider)
- if request:
- dwld = mustbe_deferred(self.download, request, spider)
- dwld.chainDeferred(deferred).addBoth(lambda _: deferred)
- dwld.addErrback(log.err, "Unhandled error on engine._next_request()",
- spider=spider)
- return dwld
+ def _next_request_from_scheduler(self, spider):
+ slot = self.slots[spider]
+ request = slot.scheduler.next_request()
+ if not request:
+ return
+ d = self._download(request, spider)
+ d.addBoth(self._handle_downloader_output, request, spider)
+ d.addErrback(log.msg, spider=spider)
+ d.addBoth(lambda _: slot.remove_request(request))
+ d.addErrback(log.msg, spider=spider)
+ d.addBoth(lambda _: slot.nextcall.schedule())
+ d.addErrback(log.msg, spider=spider)
+ return d
+
+ def _handle_downloader_output(self, response, request, spider):
+ assert isinstance(response, (Request, Response, Failure)), response
+ # downloader middleware can return requests (for example, redirects)
+ if isinstance(response, Request):
+ self.crawl(response, spider)
+ return
+ # response is a Response or Failure
+ d = self.scraper.enqueue_scrape(response, request, spider)
+ d.addErrback(log.err, spider=spider)
+ return d
def spider_is_idle(self, spider):
- scraper_idle = spider in self.scraper.sites \
- and self.scraper.sites[spider].is_idle()
- pending = self.scheduler.spider_has_pending_requests(spider)
- downloading = spider in self.downloader.sites \
- and self.downloader.sites[spider].active
- return scraper_idle and not (pending or downloading)
-
- def spider_is_closed(self, spider):
- """Return True if the spider is fully closed (ie. not even in the
- closing stage)"""
- return spider not in self.downloader.sites
-
- def spider_is_open(self, spider):
- """Return True if the spider is fully opened (ie. not in closing
- stage)"""
- return spider in self.downloader.sites and spider not in self.closing
+ scraper_idle = spider in self.scraper.slots \
+ and self.scraper.slots[spider].is_idle()
+ pending = self.slots[spider].scheduler.has_pending_requests()
+ downloading = bool(self.downloader.slots)
+ idle = scraper_idle and not (pending or downloading)
+ return idle
@property
def open_spiders(self):
- return self.downloader.sites.keys()
+ return self.slots.keys()
def has_capacity(self):
"""Does the engine have capacity to handle more spiders"""
- return len(self.downloader.sites) < self.downloader.concurrent_spiders
+ return len(self.slots) < self._concurrent_spiders
def crawl(self, request, spider):
- if spider in self.closing: # ignore requests for spiders being closed
- return
assert spider in self.open_spiders, \
"Spider %r not opened when crawling: %s" % (spider.name, request)
- schd = mustbe_deferred(self.schedule, request, spider)
- # FIXME: we can't log errors because we would be preventing them from
- # propagating to the request errback. This should be fixed after the
- # next core refactoring.
- #schd.addErrback(log.err, "Error on engine.crawl()")
- schd.addBoth(self.scraper.enqueue_scrape, request, spider)
- schd.addErrback(log.err, "Unhandled error on engine.crawl()", spider=spider)
- schd.addBoth(lambda _: self.next_request(spider))
+ self.schedule(request, spider)
+ self.slots[spider].nextcall.schedule()
def schedule(self, request, spider):
- if spider in self.closing:
- raise IgnoreRequest()
- self.next_request(spider)
- return self.scheduler.enqueue_request(spider, request)
+ return self.slots[spider].scheduler.enqueue_request(request)
def download(self, request, spider):
+ slot = self.slots[spider]
+ slot.add_request(request)
+ d = self._download(request, spider)
+ d.addBoth(self._downloaded, slot, request, spider)
+ return d
+
+ def _downloaded(self, response, slot, request, spider):
+ slot.remove_request(request)
+ return self.download(response, spider) \
+ if isinstance(response, Request) else response
+
+ def _download(self, request, spider):
+ slot = self.slots[spider]
+ slot.add_request(request)
def _on_success(response):
- """handle the result of a page download"""
assert isinstance(response, (Response, Request))
if isinstance(response, Response):
response.request = request # tie request to response received
log.msg(log.formatter.crawled(request, response, spider), \
level=log.DEBUG, spider=spider)
- return response
- elif isinstance(response, Request):
- return mustbe_deferred(self.schedule, response, spider)
+ send_catch_log(signal=signals.response_received, \
+ response=response, request=request, spider=spider)
+ return response
- def _on_error(_failure):
- """handle an error processing a page"""
- exc = _failure.value
- if isinstance(exc, IgnoreRequest):
- errmsg = _failure.getErrorMessage()
- else:
- errmsg = str(_failure)
- if errmsg:
- log.msg("Error downloading <%s>: %s" % (request.url, errmsg), \
- level=log.ERROR, spider=spider)
- return Failure(IgnoreRequest(str(exc)))
+ def _on_error(failure):
+ failure.request = request
+ return failure
def _on_complete(_):
- self.next_request(spider)
+ slot.nextcall.schedule()
return _
- if spider not in self.downloader.sites:
- return defer.fail(Failure(IgnoreRequest())).addBoth(_on_complete)
-
- dwld = mustbe_deferred(self.downloader.fetch, request, spider)
+ dwld = self.downloader.fetch(request, spider)
dwld.addCallbacks(_on_success, _on_error)
dwld.addBoth(_on_complete)
return dwld
@defer.inlineCallbacks
- def open_spider(self, spider):
+ def open_spider(self, spider, start_requests=None, close_if_idle=True):
assert self.has_capacity(), "No free spider slots when opening %r" % \
spider.name
log.msg("Spider opened", spider=spider)
- yield self.scheduler.open_spider(spider)
- self.downloader.open_spider(spider)
+ nextcall = CallLaterOnce(self._next_request, spider)
+ scheduler = self.scheduler_cls.from_settings(self.settings)
+ slot = Slot(start_requests or (), close_if_idle, nextcall, scheduler)
+ self.slots[spider] = slot
+ yield scheduler.open(spider)
yield self.scraper.open_spider(spider)
stats.open_spider(spider)
yield send_catch_log_deferred(signals.spider_opened, spider=spider)
- self.next_request(spider)
+ slot.nextcall.schedule()
def _spider_idle(self, spider):
"""Called when a spider gets idle. This function is called when there
@@ -209,7 +231,7 @@ class ExecutionEngine(object):
spider=spider, dont_log=DontCloseSpider)
if any(isinstance(x, Failure) and isinstance(x.value, DontCloseSpider) \
for _, x in res):
- reactor.callLater(5, self.next_request, spider)
+ self.slots[spider].nextcall.schedule(5)
return
if self.spider_is_idle(spider):
@@ -217,44 +239,42 @@ class ExecutionEngine(object):
def close_spider(self, spider, reason='cancelled'):
"""Close (cancel) spider and clear all its outstanding requests"""
- if spider in self.closing:
- return defer.succeed(None)
+
+ slot = self.slots[spider]
+ if slot.closing:
+ return slot.closing
log.msg("Closing spider (%s)" % reason, spider=spider)
- self.closing[spider] = reason
- self.scheduler.clear_pending_requests(spider)
- dfd = self.downloader.close_spider(spider)
- self.closing_dfds[spider] = dfd
- dfd.addBoth(lambda _: self.scheduler.close_spider(spider))
- dfd.addErrback(log.err, "Unhandled error in scheduler.close_spider()", \
- spider=spider)
+
+ dfd = slot.close()
+
dfd.addBoth(lambda _: self.scraper.close_spider(spider))
- dfd.addErrback(log.err, "Unhandled error in scraper.close_spider()", \
- spider=spider)
- dfd.addBoth(lambda _: self._finish_closing_spider(spider))
+ dfd.addErrback(log.err, spider=spider)
+
+ dfd.addBoth(lambda _: slot.scheduler.close(reason))
+ dfd.addErrback(log.err, spider=spider)
+
+ dfd.addBoth(lambda _: send_catch_log_deferred(signal=signals.spider_closed, \
+ spider=spider, reason=reason))
+ dfd.addErrback(log.err, spider=spider)
+
+ dfd.addBoth(lambda _: stats.close_spider(spider, reason=reason))
+ dfd.addErrback(log.err, spider=spider)
+
+ dfd.addBoth(lambda _: log.msg("Spider closed (%s)" % reason, spider=spider))
+
+ dfd.addBoth(lambda _: self.slots.pop(spider))
+ dfd.addErrback(log.err, spider=spider)
+
+ dfd.addBoth(lambda _: self._spider_closed_callback(spider))
+
return dfd
def _close_all_spiders(self):
dfds = [self.close_spider(s, reason='shutdown') for s in self.open_spiders]
- dfds += self.closing_dfds.values()
dlist = defer.DeferredList(dfds)
return dlist
- def _finish_closing_spider(self, spider):
- """This function is called after the spider has been closed"""
- reason = self.closing.pop(spider, 'finished')
- call = self._next_request_calls.pop(spider, None)
- if call and call.active():
- call.cancel()
- dfd = send_catch_log_deferred(signal=signals.spider_closed, \
- spider=spider, reason=reason)
- dfd.addBoth(lambda _: stats.close_spider(spider, reason=reason))
- dfd.addErrback(log.err, "Unhandled error in stats.close_spider()",
- spider=spider)
- dfd.addBoth(lambda _: log.msg("Spider closed (%s)" % reason, spider=spider))
- dfd.addBoth(lambda _: self.closing_dfds.pop(spider).callback(spider))
- dfd.addBoth(lambda _: self._spider_closed_callback(spider))
- return dfd
-
@defer.inlineCallbacks
def _finish_stopping_engine(self):
yield send_catch_log_deferred(signal=signals.engine_stopped)
+ yield stats.engine_stopped()
diff --git a/scrapy/core/scheduler.py b/scrapy/core/scheduler.py
index 93987cfba..f6f414411 100644
--- a/scrapy/core/scheduler.py
+++ b/scrapy/core/scheduler.py
@@ -1,85 +1,95 @@
-"""
-The Scrapy Scheduler
-"""
+from __future__ import with_statement
-from twisted.internet import defer
-from twisted.python.failure import Failure
+from os.path import join, exists
-from scrapy.utils.datatypes import PriorityQueue, PriorityStack
-from scrapy.core.schedulermw import SchedulerMiddlewareManager
-from scrapy.exceptions import IgnoreRequest
-from scrapy.conf import settings
+from scrapy.utils.queue import MemoryQueue
+from scrapy.utils.pqueue import PriorityQueue
+from scrapy.utils.reqser import request_to_dict, request_from_dict
+from scrapy.utils.misc import load_object
+from scrapy.utils.job import job_dir
+from scrapy.utils.py26 import json
+from scrapy.stats import stats
+from scrapy import log
class Scheduler(object):
- """The scheduler decides what to scrape next. In other words, it defines the
- crawling order. The scheduler schedules websites and requests to be
- scraped. Individual web pages that are to be scraped are batched up into a
- "run" for a website. New pages discovered through the crawling process are
- also added to the scheduler.
- """
- def __init__(self):
- self.pending_requests = {}
- self.dfo = settings['SCHEDULER_ORDER'].upper() == 'DFO'
- self.middleware = SchedulerMiddlewareManager.from_settings(settings)
+ def __init__(self, dupefilter, jobdir=None, dqclass=None):
+ self.df = dupefilter
+ self.dqdir = join(jobdir, 'requests.queue') if jobdir else None
+ self.dqclass = dqclass
- def spider_is_open(self, spider):
- """Check if scheduler's resources were allocated for a spider"""
- return spider in self.pending_requests
+ @classmethod
+ def from_settings(cls, settings):
+ dupefilter_cls = load_object(settings['DUPEFILTER_CLASS'])
+ dupefilter = dupefilter_cls.from_settings(settings)
+ dqclass = load_object(settings['SCHEDULER_DISK_QUEUE'])
+ return cls(dupefilter, job_dir(settings), dqclass)
- def spider_has_pending_requests(self, spider):
- """Check if are there pending requests for a spider"""
- if spider in self.pending_requests:
- return bool(self.pending_requests[spider])
+ def has_pending_requests(self):
+ return len(self) > 0
- def open_spider(self, spider):
- """Allocates scheduling resources for the given spider"""
- if spider in self.pending_requests:
- raise RuntimeError('Scheduler spider already opened: %s' % spider)
+ def open(self, spider):
+ self.spider = spider
+ self.mqs = PriorityQueue(self._newmq)
+ self.dqs = self._dq() if self.dqdir else None
+ return self.df.open()
- Priority = PriorityStack if self.dfo else PriorityQueue
- self.pending_requests[spider] = Priority()
- return self.middleware.open_spider(spider)
+ def close(self, reason):
+ if self.dqs:
+ prios = self.dqs.close()
+ with open(join(self.dqdir, 'active.json'), 'w') as f:
+ json.dump(prios, f)
+ return self.df.close()
- def close_spider(self, spider):
- """Called when a spider has finished scraping to free any resources
- associated with the spider.
- """
- if spider not in self.pending_requests:
- raise RuntimeError('Scheduler spider is not open: %s' % spider)
- self.pending_requests.pop(spider, None)
- return self.middleware.close_spider(spider)
+ def enqueue_request(self, request):
+ if not request.dont_filter and self.df.request_seen(request):
+ return
+ if not self._dqpush(request):
+ self._mqpush(request)
- def enqueue_request(self, spider, request):
- """Enqueue a request to be downloaded for a spider that is currently being scraped."""
- return self.middleware.enqueue_request(self._enqueue_request, spider, request)
+ def next_request(self):
+ return self.mqs.pop() or self._dqpop()
- def _enqueue_request(self, spider, request):
- dfd = defer.Deferred()
- self.pending_requests[spider].push((request, dfd), -request.priority)
- return dfd
+ def __len__(self):
+ return len(self.dqs) + len(self.mqs) if self.dqs else len(self.mqs)
- def clear_pending_requests(self, spider):
- """Remove all pending requests for the given spider"""
- q = self.pending_requests[spider]
- while q:
- _, dfd = q.pop()[0]
- dfd.errback(Failure(IgnoreRequest()))
-
- def next_request(self, spider):
- """Return the next available request to be downloaded for a spider.
-
- Returns a pair ``(request, deferred)`` where ``deferred`` is the
- `Deferred` instance returned to the original requester.
-
- ``(None, None)`` is returned if there aren't any request pending for
- the given spider.
- """
+ def _dqpush(self, request):
+ if self.dqs is None:
+ return
try:
- return self.pending_requests[spider].pop()[0] # [1] is priority
- except (KeyError, IndexError):
- return (None, None)
+ reqd = request_to_dict(request, self.spider)
+ self.dqs.push(reqd, request.priority)
+ except ValueError: # non serializable request
+ return
+ else:
+ stats.inc_value('scheduler/disk_enqueued', spider=self.spider)
+ return True
- def is_idle(self):
- """Checks if the schedulers has any request pendings"""
- return not self.pending_requests
+ def _mqpush(self, request):
+ stats.inc_value('scheduler/memory_enqueued', spider=self.spider)
+ self.mqs.push(request, request.priority)
+
+ def _dqpop(self):
+ if self.dqs:
+ d = self.dqs.pop()
+ if d:
+ return request_from_dict(d, self.spider)
+
+ def _newmq(self, priority):
+ return MemoryQueue()
+
+ def _newdq(self, priority):
+ return self.dqclass(join(self.dqdir, 'p%s' % priority))
+
+ def _dq(self):
+ activef = join(self.dqdir, 'active.json')
+ if exists(activef):
+ with open(activef) as f:
+ prios = json.load(f)
+ else:
+ prios = ()
+ q = PriorityQueue(self._newdq, startprios=prios)
+ if q:
+ log.msg("Resuming crawl (%d requests scheduled)" % len(q), \
+ spider=self.spider)
+ return q
diff --git a/scrapy/core/schedulermw.py b/scrapy/core/schedulermw.py
deleted file mode 100644
index 4ea7f3e0b..000000000
--- a/scrapy/core/schedulermw.py
+++ /dev/null
@@ -1,39 +0,0 @@
-"""
-Scheduler Middleware manager
-
-TODO: To be removed in Scrapy 0.11
-"""
-
-from twisted.internet.defer import Deferred
-
-from scrapy.middleware import MiddlewareManager
-from scrapy.utils.defer import mustbe_deferred
-from scrapy.utils.conf import build_component_list
-
-class SchedulerMiddlewareManager(MiddlewareManager):
-
- component_name = 'scheduler middleware'
-
- @classmethod
- def _get_mwlist_from_settings(cls, settings):
- return build_component_list(settings['SCHEDULER_MIDDLEWARES_BASE'], \
- settings['SCHEDULER_MIDDLEWARES'])
-
- def _add_middleware(self, mw):
- super(SchedulerMiddlewareManager, self)._add_middleware(mw)
- if hasattr(mw, 'enqueue_request'):
- self.methods['enqueue_request'].append(mw.enqueue_request)
-
- def enqueue_request(self, wrappedfunc, spider, request):
- def _enqueue_request(request):
- for mwfunc in self.methods['enqueue_request']:
- result = mwfunc(spider=spider, request=request)
- assert result is None or isinstance(result, Deferred), \
- 'Middleware %s.enqueue_request must return None or Deferred, got %s' % \
- (mwfunc.im_self.__class__.__name__, result.__class__.__name__)
- if result:
- return result
- return wrappedfunc(spider=spider, request=request)
-
- deferred = mustbe_deferred(_enqueue_request, request)
- return deferred
diff --git a/scrapy/core/scraper.py b/scrapy/core/scraper.py
index 7e2dd9822..9e46b6b59 100644
--- a/scrapy/core/scraper.py
+++ b/scrapy/core/scraper.py
@@ -1,6 +1,8 @@
"""This module implements the Scraper component which parses responses and
extracts information from them"""
+from collections import deque
+
from twisted.python.failure import Failure
from twisted.internet import defer
@@ -8,7 +10,7 @@ from scrapy.utils.defer import defer_result, defer_succeed, parallel, iter_errba
from scrapy.utils.spider import iterate_spider_output
from scrapy.utils.misc import load_object
from scrapy.utils.signal import send_catch_log, send_catch_log_deferred
-from scrapy.exceptions import IgnoreRequest, DropItem
+from scrapy.exceptions import CloseSpider, DropItem
from scrapy import signals
from scrapy.http import Request, Response
from scrapy.item import BaseItem
@@ -17,14 +19,14 @@ from scrapy import log
from scrapy.stats import stats
-class SpiderInfo(object):
- """Object for holding data of the responses being scraped"""
+class Slot(object):
+ """Scraper slot (one per running spider)"""
MIN_RESPONSE_SIZE = 1024
def __init__(self, max_active_size=5000000):
self.max_active_size = max_active_size
- self.queue = []
+ self.queue = deque()
self.active = set()
self.active_size = 0
self.itemproc_size = 0
@@ -40,12 +42,12 @@ class SpiderInfo(object):
return deferred
def next_response_request_deferred(self):
- response, request, deferred = self.queue.pop(0)
- self.active.add(response)
+ response, request, deferred = self.queue.popleft()
+ self.active.add(request)
return response, request, deferred
- def finish_response(self, response):
- self.active.remove(response)
+ def finish_response(self, response, request):
+ self.active.remove(request)
if isinstance(response, Response):
self.active_size -= max(len(response.body), self.MIN_RESPONSE_SIZE)
else:
@@ -59,58 +61,56 @@ class SpiderInfo(object):
class Scraper(object):
- def __init__(self, engine, settings):
- self.sites = {}
- self.spidermw = SpiderMiddlewareManager.from_settings(settings)
- itemproc_cls = load_object(settings['ITEM_PROCESSOR'])
- self.itemproc = itemproc_cls.from_settings(settings)
- self.concurrent_items = settings.getint('CONCURRENT_ITEMS')
- self.engine = engine
+ def __init__(self, crawler):
+ self.slots = {}
+ self.spidermw = SpiderMiddlewareManager.from_crawler(crawler)
+ itemproc_cls = load_object(crawler.settings['ITEM_PROCESSOR'])
+ self.itemproc = itemproc_cls.from_crawler(crawler)
+ self.concurrent_items = crawler.settings.getint('CONCURRENT_ITEMS')
+ self.crawler = crawler
@defer.inlineCallbacks
def open_spider(self, spider):
"""Open the given spider for scraping and allocate resources for it"""
- assert spider not in self.sites, "Spider already opened: %s" % spider
- self.sites[spider] = SpiderInfo()
+ assert spider not in self.slots, "Spider already opened: %s" % spider
+ self.slots[spider] = Slot()
yield self.itemproc.open_spider(spider)
def close_spider(self, spider):
"""Close a spider being scraped and release its resources"""
- assert spider in self.sites, "Spider not opened: %s" % spider
- site = self.sites[spider]
- site.closing = defer.Deferred()
- site.closing.addCallback(self.itemproc.close_spider)
- self._check_if_closing(spider, site)
- return site.closing
+ assert spider in self.slots, "Spider not opened: %s" % spider
+ slot = self.slots[spider]
+ slot.closing = defer.Deferred()
+ slot.closing.addCallback(self.itemproc.close_spider)
+ self._check_if_closing(spider, slot)
+ return slot.closing
def is_idle(self):
"""Return True if there isn't any more spiders to process"""
- return not self.sites
+ return not self.slots
- def _check_if_closing(self, spider, site):
- if site.closing and site.is_idle():
- del self.sites[spider]
- site.closing.callback(spider)
+ def _check_if_closing(self, spider, slot):
+ if slot.closing and slot.is_idle():
+ del self.slots[spider]
+ slot.closing.callback(spider)
def enqueue_scrape(self, response, request, spider):
- site = self.sites.get(spider, None)
- if site is None:
- return
- dfd = site.add_response_request(response, request)
+ slot = self.slots[spider]
+ dfd = slot.add_response_request(response, request)
def finish_scraping(_):
- site.finish_response(response)
- self._check_if_closing(spider, site)
- self._scrape_next(spider, site)
+ slot.finish_response(response, request)
+ self._check_if_closing(spider, slot)
+ self._scrape_next(spider, slot)
return _
dfd.addBoth(finish_scraping)
dfd.addErrback(log.err, 'Scraper bug processing %s' % request, \
spider=spider)
- self._scrape_next(spider, site)
+ self._scrape_next(spider, slot)
return dfd
- def _scrape_next(self, spider, site):
- while site.queue:
- response, request, deferred = site.next_response_request_deferred()
+ def _scrape_next(self, spider, slot):
+ while slot.queue:
+ response, request, deferred = slot.next_response_request_deferred()
self._scrape(response, request, spider).chainDeferred(deferred)
def _scrape(self, response, request, spider):
@@ -119,7 +119,7 @@ class Scraper(object):
assert isinstance(response, (Response, Failure))
dfd = self._scrape2(response, request, spider) # returns spiders processed output
- dfd.addErrback(self.handle_spider_error, request, spider)
+ dfd.addErrback(self.handle_spider_error, request, response, spider)
dfd.addCallback(self.handle_spider_output, request, response, spider)
return dfd
@@ -132,7 +132,7 @@ class Scraper(object):
else:
# FIXME: don't ignore errors in spider middleware
dfd = self.call_spider(request_result, request, spider)
- return dfd.addErrback(self._check_propagated_failure, \
+ return dfd.addErrback(self._log_download_errors, \
request_result, request, spider)
def call_spider(self, result, request, spider):
@@ -140,18 +140,21 @@ class Scraper(object):
dfd.addCallbacks(request.callback or spider.parse, request.errback)
return dfd.addCallback(iterate_spider_output)
- def handle_spider_error(self, _failure, request, spider, propagated_failure=None):
- referer = request.headers.get('Referer', None)
- msg = "Spider error processing <%s> (referer: <%s>)" % \
- (request.url, referer)
- log.err(_failure, msg, spider=spider)
+ def handle_spider_error(self, _failure, request, response, spider):
+ exc = _failure.value
+ if isinstance(exc, CloseSpider):
+ self.crawler.engine.close_spider(spider, exc.reason or 'cancelled')
+ return
+ log.err(_failure, "Spider error processing %s" % request, spider=spider)
+ send_catch_log(signal=signals.spider_error, failure=_failure, response=response, \
+ spider=spider)
stats.inc_value("spider_exceptions/%s" % _failure.value.__class__.__name__, \
spider=spider)
def handle_spider_output(self, result, request, response, spider):
if not result:
return defer_succeed(None)
- it = iter_errback(result, self.handle_spider_error, request, spider)
+ it = iter_errback(result, self.handle_spider_error, request, response, spider)
dfd = parallel(it, self.concurrent_items,
self._process_spidermw_output, request, response, spider)
return dfd
@@ -163,15 +166,11 @@ class Scraper(object):
if isinstance(output, Request):
send_catch_log(signal=signals.request_received, request=output, \
spider=spider)
- self.engine.crawl(request=output, spider=spider)
+ self.crawler.engine.crawl(request=output, spider=spider)
elif isinstance(output, BaseItem):
- log.msg(log.formatter.scraped(output, request, response, spider), \
- level=log.DEBUG, spider=spider)
- self.sites[spider].itemproc_size += 1
- dfd = send_catch_log_deferred(signal=signals.item_scraped, \
- item=output, spider=spider, response=response)
- dfd.addBoth(lambda _: self.itemproc.process_item(output, spider))
- dfd.addBoth(self._itemproc_finished, output, spider)
+ self.slots[spider].itemproc_size += 1
+ dfd = self.itemproc.process_item(output, spider)
+ dfd.addBoth(self._itemproc_finished, output, response, spider)
return dfd
elif output is None:
pass
@@ -179,37 +178,32 @@ class Scraper(object):
log.msg("Spider must return Request, BaseItem or None, got %r in %s" % \
(type(output).__name__, request), log.ERROR, spider=spider)
- def _check_propagated_failure(self, spider_failure, propagated_failure, request, spider):
- """Log and silence the bugs raised outside of spiders, but still allow
- spiders to be notified about general failures while downloading spider
- generated requests
+ def _log_download_errors(self, spider_failure, download_failure, request, spider):
+ """Log and silence errors that come from the engine (typically download
+ errors that got propagated thru here)
"""
- # ignored requests are commonly propagated exceptions safes to be silenced
- if isinstance(spider_failure.value, IgnoreRequest):
+ if spider_failure is download_failure:
+ log.msg("Error downloading %s: %s" % \
+ (request, spider_failure.getErrorMessage()), log.ERROR, spider=spider)
return
- elif spider_failure is propagated_failure:
- log.err(spider_failure, 'Unhandled error propagated to spider', \
- spider=spider)
- return # stop propagating this error
- else:
- return spider_failure # exceptions raised in the spider code
+ return spider_failure
- def _itemproc_finished(self, output, item, spider):
+ def _itemproc_finished(self, output, item, response, spider):
"""ItemProcessor finished for the given ``item`` and returned ``output``
"""
- self.sites[spider].itemproc_size -= 1
+ self.slots[spider].itemproc_size -= 1
if isinstance(output, Failure):
ex = output.value
if isinstance(ex, DropItem):
- log.msg(log.formatter.dropped(item, ex, spider), \
+ log.msg(log.formatter.dropped(item, ex, response, spider), \
level=log.WARNING, spider=spider)
return send_catch_log_deferred(signal=signals.item_dropped, \
item=item, spider=spider, exception=output.value)
else:
log.err(output, 'Error processing %s' % item, spider=spider)
else:
- log.msg(log.formatter.passed(output, spider), log.INFO, spider=spider)
- # TODO: remove item_passed 'output' parameter for Scrapy 0.12
- return send_catch_log_deferred(signal=signals.item_passed, \
- item=output, spider=spider, output=output, original_item=item)
+ log.msg(log.formatter.scraped(output, response, spider), \
+ log.DEBUG, spider=spider)
+ return send_catch_log_deferred(signal=signals.item_scraped, \
+ item=output, response=response, spider=spider)
diff --git a/scrapy/crawler.py b/scrapy/crawler.py
index 22d0f2f91..4386e7c64 100644
--- a/scrapy/crawler.py
+++ b/scrapy/crawler.py
@@ -3,8 +3,8 @@ import signal
from twisted.internet import reactor, defer
from scrapy.xlib.pydispatch import dispatcher
-from scrapy.queue import ExecutionQueue
from scrapy.core.engine import ExecutionEngine
+from scrapy.resolver import CachingThreadedResolver
from scrapy.extension import ExtensionManager
from scrapy.utils.ossignal import install_shutdown_handlers, signal_names
from scrapy.utils.misc import load_object
@@ -31,54 +31,28 @@ class Crawler(object):
if self.configured:
return
self.configured = True
- self.extensions = ExtensionManager.from_settings(self.settings)
+ self.extensions = ExtensionManager.from_crawler(self)
spman_cls = load_object(self.settings['SPIDER_MANAGER_CLASS'])
self.spiders = spman_cls.from_settings(self.settings)
- spq_cls = load_object(self.settings['SPIDER_QUEUE_CLASS'])
- spq = spq_cls.from_settings(self.settings)
- keepalive = self.settings.getbool('KEEP_ALIVE')
- pollint = self.settings.getfloat('QUEUE_POLL_INTERVAL')
- self.queue = ExecutionQueue(self.spiders, spq, poll_interval=pollint,
- keep_alive=keepalive)
- self.engine = ExecutionEngine(self.settings, self._spider_closed)
+ self.engine = ExecutionEngine(self, self._spider_closed)
- @defer.inlineCallbacks
- def _start_next_spider(self):
- spider, requests = yield defer.maybeDeferred(self.queue.get_next)
- if spider:
- self._start_spider(spider, requests)
- if self.engine.has_capacity() and not self._nextcall.active():
- self._nextcall = reactor.callLater(self.queue.poll_interval, \
- self._spider_closed)
-
- @defer.inlineCallbacks
- def _start_spider(self, spider, requests):
- """Don't call this method. Use self.queue to start new spiders"""
+ def crawl(self, spider, requests=None):
spider.set_crawler(self)
- yield defer.maybeDeferred(self.engine.open_spider, spider)
- for request in requests:
- self.engine.crawl(request, spider)
+ if requests is None:
+ requests = spider.start_requests()
+ return self.engine.open_spider(spider, requests)
- @defer.inlineCallbacks
def _spider_closed(self, spider=None):
if not self.engine.open_spiders:
- is_finished = yield defer.maybeDeferred(self.queue.is_finished)
- if is_finished:
- self.stop()
- return
- if self.engine.has_capacity():
- self._start_next_spider()
+ self.stop()
@defer.inlineCallbacks
def start(self):
yield defer.maybeDeferred(self.configure)
yield defer.maybeDeferred(self.engine.start)
- self._nextcall = reactor.callLater(0, self._start_next_spider)
@defer.inlineCallbacks
def stop(self):
- if self._nextcall.active():
- self._nextcall.cancel()
if self.engine.running:
yield defer.maybeDeferred(self.engine.stop)
@@ -96,6 +70,8 @@ class CrawlerProcess(Crawler):
def start(self):
super(CrawlerProcess, self).start()
+ if self.settings.getbool('DNSCACHE_ENABLED'):
+ reactor.installResolver(CachingThreadedResolver(reactor))
reactor.addSystemEventTrigger('before', 'shutdown', self.stop)
reactor.run(installSignalHandlers=False) # blocking call
diff --git a/scrapy/dupefilter.py b/scrapy/dupefilter.py
new file mode 100644
index 000000000..69d95b181
--- /dev/null
+++ b/scrapy/dupefilter.py
@@ -0,0 +1,46 @@
+import os
+from scrapy.utils.request import request_fingerprint
+from scrapy.utils.job import job_dir
+
+
+class BaseDupeFilter(object):
+
+ @classmethod
+ def from_settings(cls, settings):
+ return cls()
+
+ def request_seen(self, request):
+ return False
+
+ def open(self): # can return deferred
+ pass
+
+ def close(self): # can return a deferred
+ pass
+
+
+class RFPDupeFilter(BaseDupeFilter):
+ """Request Fingerprint duplicates filter"""
+
+ def __init__(self, path=None):
+ self.file = None
+ self.fingerprints = set()
+ if path:
+ self.file = open(os.path.join(path, 'requests.seen'), 'a+')
+ self.fingerprints.update(x.rstrip() for x in self.file)
+
+ @classmethod
+ def from_settings(cls, settings):
+ return cls(job_dir(settings))
+
+ def request_seen(self, request):
+ fp = request_fingerprint(request)
+ if fp in self.fingerprints:
+ return True
+ self.fingerprints.add(fp)
+ if self.file:
+ self.file.write(fp + os.linesep)
+
+ def close(self):
+ if self.file:
+ self.file.close()
diff --git a/scrapy/exceptions.py b/scrapy/exceptions.py
index e52dafc6d..8f29a4c8d 100644
--- a/scrapy/exceptions.py
+++ b/scrapy/exceptions.py
@@ -20,6 +20,12 @@ class DontCloseSpider(Exception):
"""Request the spider not to be closed yet"""
pass
+class CloseSpider(Exception):
+ """Raise this from callbacks to request the spider to be closed"""
+
+ def __init__(self, reason='cancelled'):
+ self.reason = reason
+
# Items
class DropItem(Exception):
@@ -37,3 +43,10 @@ class UsageError(Exception):
def __init__(self, *a, **kw):
self.print_help = kw.pop('print_help', True)
super(UsageError, self).__init__(*a, **kw)
+
+class ScrapyDeprecationWarning(Warning):
+ """Warning category for deprecated features, since the default
+ DeprecationWarning is silenced on Python 2.7+
+ """
+ pass
+
diff --git a/scrapy/http/common.py b/scrapy/http/common.py
index 63d264264..34d5389bf 100644
--- a/scrapy/http/common.py
+++ b/scrapy/http/common.py
@@ -1,9 +1,10 @@
import warnings
+from scrapy.exceptions import ScrapyDeprecationWarning
def deprecated_setter(setter, attrname):
def newsetter(self, value):
c = self.__class__.__name__
warnings.warn("Don't modify %s.%s attribute, use %s.replace() instead" % \
- (c, attrname, c), DeprecationWarning, stacklevel=2)
+ (c, attrname, c), ScrapyDeprecationWarning, stacklevel=2)
return setter(self, value)
return newsetter
diff --git a/scrapy/http/headers.py b/scrapy/http/headers.py
index 0ab2258e4..5efeda29c 100644
--- a/scrapy/http/headers.py
+++ b/scrapy/http/headers.py
@@ -1,5 +1,5 @@
+from w3lib.http import headers_dict_to_raw
from scrapy.utils.datatypes import CaselessDict
-from scrapy.utils.http import headers_dict_to_raw
class Headers(CaselessDict):
@@ -19,12 +19,10 @@ class Headers(CaselessDict):
def normvalue(self, value):
"""Headers must not be unicode"""
- if isinstance(value, unicode):
- value = value.encode(self.encoding)
-
- if isinstance(value, (list, tuple)):
- return list(value)
- return [value]
+ if not hasattr(value, '__iter__'):
+ value = [value]
+ return [x.encode(self.encoding) if isinstance(x, unicode) else x \
+ for x in value]
def __getitem__(self, key):
try:
diff --git a/scrapy/http/request/__init__.py b/scrapy/http/request/__init__.py
index f791aded5..3fa41ccb7 100644
--- a/scrapy/http/request/__init__.py
+++ b/scrapy/http/request/__init__.py
@@ -7,8 +7,9 @@ See documentation in docs/topics/request-response.rst
import copy
+from w3lib.url import safe_url_string
+
from scrapy.http.headers import Headers
-from scrapy.utils.url import safe_url_string
from scrapy.utils.trackref import object_ref
from scrapy.utils.decorator import deprecated
from scrapy.http.common import deprecated_setter
@@ -20,13 +21,14 @@ class Request(object_ref):
'__weakref__']
def __init__(self, url, callback=None, method='GET', headers=None, body=None,
- cookies=None, meta=None, encoding='utf-8', priority=0.0,
+ cookies=None, meta=None, encoding='utf-8', priority=0,
dont_filter=False, errback=None):
self._encoding = encoding # this one has to be set first
- self.method = method.upper()
+ self.method = str(method).upper()
self._set_url(url)
self._set_body(body)
+ assert isinstance(priority, int), "Request priority not an integer: %r" % priority
self.priority = priority
assert callback or not errback, "Cannot use errback without a callback"
@@ -59,6 +61,8 @@ class Request(object_ref):
self._url = safe_url_string(unicode_url, self.encoding)
else:
raise TypeError('Request url must be str or unicode, got %s:' % type(url).__name__)
+ if ':' not in self._url:
+ raise ValueError('Missing scheme in request url: %s' % self._url)
url = property(_get_url, deprecated_setter(_set_url, 'url'))
@@ -87,10 +91,7 @@ class Request(object_ref):
def __str__(self):
return "<%s %s>" % (self.method, self.url)
- def __repr__(self):
- attrs = ['url', 'method', 'body', 'headers', 'cookies', 'meta']
- args = ", ".join(["%s=%r" % (a, getattr(self, a)) for a in attrs])
- return "%s(%s)" % (self.__class__.__name__, args)
+ __repr__ = __str__
def copy(self):
"""Return a copy of this Request"""
diff --git a/scrapy/http/response/__init__.py b/scrapy/http/response/__init__.py
index 2d0ff5fa8..ed4e3e3b4 100644
--- a/scrapy/http/response/__init__.py
+++ b/scrapy/http/response/__init__.py
@@ -61,14 +61,11 @@ class Response(object_ref):
body = property(_get_body, deprecated_setter(_set_body, 'body'))
- def __repr__(self):
- attrs = ['url', 'status', 'body', 'headers', 'request', 'flags']
- args = ", ".join(["%s=%r" % (a, getattr(self, a)) for a in attrs])
- return "%s(%s)" % (self.__class__.__name__, args)
-
def __str__(self):
return "<%d %s>" % (self.status, self.url)
+ __repr__ = __str__
+
def copy(self):
"""Return a copy of this Response"""
return self.replace()
diff --git a/scrapy/http/response/dammit.py b/scrapy/http/response/dammit.py
new file mode 100644
index 000000000..b9254904d
--- /dev/null
+++ b/scrapy/http/response/dammit.py
@@ -0,0 +1,269 @@
+"""
+This module contains a fork of the UnicodeDammit class from BeautifulSoup, that
+expliclty disabled any usage of chardet library.
+
+The UnicodeDammit class is used as a last resource for detecting the encoding
+of a response.
+"""
+
+import re
+import codecs
+
+chardet = None # we don't want to use chardet since it's very slow,
+
+class UnicodeDammit:
+ """A class for detecting the encoding of a *ML document and
+ converting it to a Unicode string. If the source encoding is
+ windows-1252, can replace MS smart quotes with their HTML or XML
+ equivalents."""
+
+ # This dictionary maps commonly seen values for "charset" in HTML
+ # meta tags to the corresponding Python codec names. It only covers
+ # values that aren't in Python's aliases and can't be determined
+ # by the heuristics in find_codec.
+ CHARSET_ALIASES = { "macintosh" : "mac-roman",
+ "x-sjis" : "shift-jis" }
+
+ def __init__(self, markup, overrideEncodings=[],
+ smartQuotesTo='xml', isHTML=False):
+ self.declaredHTMLEncoding = None
+ self.markup, documentEncoding, sniffedEncoding = \
+ self._detectEncoding(markup, isHTML)
+ self.smartQuotesTo = smartQuotesTo
+ self.triedEncodings = []
+ if markup == '' or isinstance(markup, unicode):
+ self.originalEncoding = None
+ self.unicode = unicode(markup)
+ return
+
+ u = None
+ for proposedEncoding in overrideEncodings:
+ u = self._convertFrom(proposedEncoding)
+ if u: break
+ if not u:
+ for proposedEncoding in (documentEncoding, sniffedEncoding):
+ u = self._convertFrom(proposedEncoding)
+ if u: break
+
+ # If no luck and we have auto-detection library, try that:
+ if not u and chardet and not isinstance(self.markup, unicode):
+ u = self._convertFrom(chardet.detect(self.markup)['encoding'])
+
+ # As a last resort, try utf-8 and windows-1252:
+ if not u:
+ for proposed_encoding in ("utf-8", "windows-1252"):
+ u = self._convertFrom(proposed_encoding)
+ if u: break
+
+ self.unicode = u
+ if not u: self.originalEncoding = None
+
+ def _subMSChar(self, orig):
+ """Changes a MS smart quote character to an XML or HTML
+ entity."""
+ sub = self.MS_CHARS.get(orig)
+ if isinstance(sub, tuple):
+ if self.smartQuotesTo == 'xml':
+ sub = '%s;' % sub[1]
+ else:
+ sub = '&%s;' % sub[0]
+ return sub
+
+ def _convertFrom(self, proposed):
+ proposed = self.find_codec(proposed)
+ if not proposed or proposed in self.triedEncodings:
+ return None
+ self.triedEncodings.append(proposed)
+ markup = self.markup
+
+ # Convert smart quotes to HTML if coming from an encoding
+ # that might have them.
+ if self.smartQuotesTo and proposed.lower() in("windows-1252",
+ "iso-8859-1",
+ "iso-8859-2"):
+ markup = re.compile("([\x80-\x9f])").sub \
+ (lambda(x): self._subMSChar(x.group(1)),
+ markup)
+
+ try:
+ # print "Trying to convert document to %s" % proposed
+ u = self._toUnicode(markup, proposed)
+ self.markup = u
+ self.originalEncoding = proposed
+ except Exception, e:
+ # print "That didn't work!"
+ # print e
+ return None
+ #print "Correct encoding: %s" % proposed
+ return self.markup
+
+ def _toUnicode(self, data, encoding):
+ '''Given a string and its encoding, decodes the string into Unicode.
+ %encoding is a string recognized by encodings.aliases'''
+
+ # strip Byte Order Mark (if present)
+ if (len(data) >= 4) and (data[:2] == '\xfe\xff') \
+ and (data[2:4] != '\x00\x00'):
+ encoding = 'utf-16be'
+ data = data[2:]
+ elif (len(data) >= 4) and (data[:2] == '\xff\xfe') \
+ and (data[2:4] != '\x00\x00'):
+ encoding = 'utf-16le'
+ data = data[2:]
+ elif data[:3] == '\xef\xbb\xbf':
+ encoding = 'utf-8'
+ data = data[3:]
+ elif data[:4] == '\x00\x00\xfe\xff':
+ encoding = 'utf-32be'
+ data = data[4:]
+ elif data[:4] == '\xff\xfe\x00\x00':
+ encoding = 'utf-32le'
+ data = data[4:]
+ newdata = unicode(data, encoding)
+ return newdata
+
+ def _detectEncoding(self, xml_data, isHTML=False):
+ """Given a document, tries to detect its XML encoding."""
+ xml_encoding = sniffed_xml_encoding = None
+ try:
+ if xml_data[:4] == '\x4c\x6f\xa7\x94':
+ # EBCDIC
+ xml_data = self._ebcdic_to_ascii(xml_data)
+ elif xml_data[:4] == '\x00\x3c\x00\x3f':
+ # UTF-16BE
+ sniffed_xml_encoding = 'utf-16be'
+ xml_data = unicode(xml_data, 'utf-16be').encode('utf-8')
+ elif (len(xml_data) >= 4) and (xml_data[:2] == '\xfe\xff') \
+ and (xml_data[2:4] != '\x00\x00'):
+ # UTF-16BE with BOM
+ sniffed_xml_encoding = 'utf-16be'
+ xml_data = unicode(xml_data[2:], 'utf-16be').encode('utf-8')
+ elif xml_data[:4] == '\x3c\x00\x3f\x00':
+ # UTF-16LE
+ sniffed_xml_encoding = 'utf-16le'
+ xml_data = unicode(xml_data, 'utf-16le').encode('utf-8')
+ elif (len(xml_data) >= 4) and (xml_data[:2] == '\xff\xfe') and \
+ (xml_data[2:4] != '\x00\x00'):
+ # UTF-16LE with BOM
+ sniffed_xml_encoding = 'utf-16le'
+ xml_data = unicode(xml_data[2:], 'utf-16le').encode('utf-8')
+ elif xml_data[:4] == '\x00\x00\x00\x3c':
+ # UTF-32BE
+ sniffed_xml_encoding = 'utf-32be'
+ xml_data = unicode(xml_data, 'utf-32be').encode('utf-8')
+ elif xml_data[:4] == '\x3c\x00\x00\x00':
+ # UTF-32LE
+ sniffed_xml_encoding = 'utf-32le'
+ xml_data = unicode(xml_data, 'utf-32le').encode('utf-8')
+ elif xml_data[:4] == '\x00\x00\xfe\xff':
+ # UTF-32BE with BOM
+ sniffed_xml_encoding = 'utf-32be'
+ xml_data = unicode(xml_data[4:], 'utf-32be').encode('utf-8')
+ elif xml_data[:4] == '\xff\xfe\x00\x00':
+ # UTF-32LE with BOM
+ sniffed_xml_encoding = 'utf-32le'
+ xml_data = unicode(xml_data[4:], 'utf-32le').encode('utf-8')
+ elif xml_data[:3] == '\xef\xbb\xbf':
+ # UTF-8 with BOM
+ sniffed_xml_encoding = 'utf-8'
+ xml_data = unicode(xml_data[3:], 'utf-8').encode('utf-8')
+ else:
+ sniffed_xml_encoding = 'ascii'
+ pass
+ except:
+ xml_encoding_match = None
+ xml_encoding_match = re.compile(
+ '^<\?.*encoding=[\'"](.*?)[\'"].*\?>').match(xml_data)
+ if not xml_encoding_match and isHTML:
+ regexp = re.compile('<\s*meta[^>]+charset=([^>]*?)[;\'">]', re.I)
+ xml_encoding_match = regexp.search(xml_data)
+ if xml_encoding_match is not None:
+ xml_encoding = xml_encoding_match.groups()[0].lower()
+ if isHTML:
+ self.declaredHTMLEncoding = xml_encoding
+ if sniffed_xml_encoding and \
+ (xml_encoding in ('iso-10646-ucs-2', 'ucs-2', 'csunicode',
+ 'iso-10646-ucs-4', 'ucs-4', 'csucs4',
+ 'utf-16', 'utf-32', 'utf_16', 'utf_32',
+ 'utf16', 'u16')):
+ xml_encoding = sniffed_xml_encoding
+ return xml_data, xml_encoding, sniffed_xml_encoding
+
+
+ def find_codec(self, charset):
+ return self._codec(self.CHARSET_ALIASES.get(charset, charset)) \
+ or (charset and self._codec(charset.replace("-", ""))) \
+ or (charset and self._codec(charset.replace("-", "_"))) \
+ or charset
+
+ def _codec(self, charset):
+ if not charset: return charset
+ codec = None
+ try:
+ codecs.lookup(charset)
+ codec = charset
+ except (LookupError, ValueError):
+ pass
+ return codec
+
+ EBCDIC_TO_ASCII_MAP = None
+ def _ebcdic_to_ascii(self, s):
+ c = self.__class__
+ if not c.EBCDIC_TO_ASCII_MAP:
+ emap = (0,1,2,3,156,9,134,127,151,141,142,11,12,13,14,15,
+ 16,17,18,19,157,133,8,135,24,25,146,143,28,29,30,31,
+ 128,129,130,131,132,10,23,27,136,137,138,139,140,5,6,7,
+ 144,145,22,147,148,149,150,4,152,153,154,155,20,21,158,26,
+ 32,160,161,162,163,164,165,166,167,168,91,46,60,40,43,33,
+ 38,169,170,171,172,173,174,175,176,177,93,36,42,41,59,94,
+ 45,47,178,179,180,181,182,183,184,185,124,44,37,95,62,63,
+ 186,187,188,189,190,191,192,193,194,96,58,35,64,39,61,34,
+ 195,97,98,99,100,101,102,103,104,105,196,197,198,199,200,
+ 201,202,106,107,108,109,110,111,112,113,114,203,204,205,
+ 206,207,208,209,126,115,116,117,118,119,120,121,122,210,
+ 211,212,213,214,215,216,217,218,219,220,221,222,223,224,
+ 225,226,227,228,229,230,231,123,65,66,67,68,69,70,71,72,
+ 73,232,233,234,235,236,237,125,74,75,76,77,78,79,80,81,
+ 82,238,239,240,241,242,243,92,159,83,84,85,86,87,88,89,
+ 90,244,245,246,247,248,249,48,49,50,51,52,53,54,55,56,57,
+ 250,251,252,253,254,255)
+ import string
+ c.EBCDIC_TO_ASCII_MAP = string.maketrans( \
+ ''.join(map(chr, range(256))), ''.join(map(chr, emap)))
+ return s.translate(c.EBCDIC_TO_ASCII_MAP)
+
+ MS_CHARS = { '\x80' : ('euro', '20AC'),
+ '\x81' : ' ',
+ '\x82' : ('sbquo', '201A'),
+ '\x83' : ('fnof', '192'),
+ '\x84' : ('bdquo', '201E'),
+ '\x85' : ('hellip', '2026'),
+ '\x86' : ('dagger', '2020'),
+ '\x87' : ('Dagger', '2021'),
+ '\x88' : ('circ', '2C6'),
+ '\x89' : ('permil', '2030'),
+ '\x8A' : ('Scaron', '160'),
+ '\x8B' : ('lsaquo', '2039'),
+ '\x8C' : ('OElig', '152'),
+ '\x8D' : '?',
+ '\x8E' : ('#x17D', '17D'),
+ '\x8F' : '?',
+ '\x90' : '?',
+ '\x91' : ('lsquo', '2018'),
+ '\x92' : ('rsquo', '2019'),
+ '\x93' : ('ldquo', '201C'),
+ '\x94' : ('rdquo', '201D'),
+ '\x95' : ('bull', '2022'),
+ '\x96' : ('ndash', '2013'),
+ '\x97' : ('mdash', '2014'),
+ '\x98' : ('tilde', '2DC'),
+ '\x99' : ('trade', '2122'),
+ '\x9a' : ('scaron', '161'),
+ '\x9b' : ('rsaquo', '203A'),
+ '\x9c' : ('oelig', '153'),
+ '\x9d' : '?',
+ '\x9e' : ('#x17E', '17E'),
+ '\x9f' : ('Yuml', ''),}
+
+#######################################################################
+
diff --git a/scrapy/http/response/html.py b/scrapy/http/response/html.py
index dc812ac0e..1ef52490c 100644
--- a/scrapy/http/response/html.py
+++ b/scrapy/http/response/html.py
@@ -18,15 +18,15 @@ class HtmlResponse(TextResponse):
_httpequiv_re = _template % ('http-equiv', 'Content-Type')
_content_re = _template % ('content', r'(?P[^;]+);\s*charset=(?P[\w-]+)')
- _encoding_re = _template % ('encoding', r'(?P[\w-]+)')
+ _content2_re = _template % ('charset', r'(?P[\w-]+)')
METATAG_RE = re.compile(r' ' % (self.url, self.text)
+ return 'Link(url=%r, text=%r, fragment=%r, nofollow=%r)' % \
+ (self.url, self.text, self.fragment, self.nofollow)
diff --git a/scrapy/linkextractor.py b/scrapy/linkextractor.py
new file mode 100644
index 000000000..5c2100d74
--- /dev/null
+++ b/scrapy/linkextractor.py
@@ -0,0 +1,21 @@
+"""
+Common code and definitions used by Link extractors (located in
+scrapy.contrib.linkextractor).
+"""
+
+# common file extensions that are not followed if they occur in links
+IGNORED_EXTENSIONS = [
+ # images
+ 'mng', 'pct', 'bmp', 'gif', 'jpg', 'jpeg', 'png', 'pst', 'psp', 'tif',
+ 'tiff', 'ai', 'drw', 'dxf', 'eps', 'ps', 'svg',
+
+ # audio
+ 'mp3', 'wma', 'ogg', 'wav', 'ra', 'aac', 'mid', 'au', 'aiff',
+
+ # video
+ '3gp', 'asf', 'asx', 'avi', 'mov', 'mp4', 'mpg', 'qt', 'rm', 'swf', 'wmv',
+ 'm4a',
+
+ # other
+ 'css', 'pdf', 'doc', 'exe', 'bin', 'rss', 'zip', 'rar',
+]
diff --git a/scrapy/log.py b/scrapy/log.py
index 6285209ce..8d79f3aef 100644
--- a/scrapy/log.py
+++ b/scrapy/log.py
@@ -13,6 +13,7 @@ import scrapy
from scrapy.conf import settings
from scrapy.utils.python import unicode_to_str
from scrapy.utils.misc import load_object
+from scrapy.exceptions import ScrapyDeprecationWarning
# Logging levels
DEBUG = logging.DEBUG
@@ -114,7 +115,7 @@ def start(logfile=None, loglevel=None, logstdout=None):
def msg(message, level=INFO, **kw):
if 'component' in kw:
warnings.warn("Argument `component` of scrapy.log.msg() is deprecated", \
- DeprecationWarning, stacklevel=2)
+ ScrapyDeprecationWarning, stacklevel=2)
kw.setdefault('system', 'scrapy')
kw['logLevel'] = level
log.msg(message, **kw)
diff --git a/scrapy/logformatter.py b/scrapy/logformatter.py
index 7e7ba01b2..fdbd8def9 100644
--- a/scrapy/logformatter.py
+++ b/scrapy/logformatter.py
@@ -1,3 +1,6 @@
+import os
+
+from twisted.python.failure import Failure
class LogFormatter(object):
"""Class for generating log messages for different actions. All methods
@@ -8,14 +11,12 @@ class LogFormatter(object):
def crawled(self, request, response, spider):
referer = request.headers.get('Referer')
flags = ' %s' % str(response.flags) if response.flags else ''
- return "Crawled (%d) %s (referer: %s)%s" % (response.status, \
+ return u"Crawled (%d) %s (referer: %s)%s" % (response.status, \
request, referer, flags)
- def scraped(self, item, request, response, spider):
- return "Scraped %s in <%s>" % (item, request.url)
+ def scraped(self, item, response, spider):
+ src = response.getErrorMessage() if isinstance(response, Failure) else response
+ return u"Scraped from %s%s%s" % (src, os.linesep, item)
- def dropped(self, item, exception, spider):
- return "Dropped %s - %s" % (item, unicode(exception))
-
- def passed(self, item, spider):
- return "Passed %s" % item
+ def dropped(self, item, exception, response, spider):
+ return u"Dropped: %s%s%s" % (exception, os.linesep, item)
diff --git a/scrapy/middleware.py b/scrapy/middleware.py
index c83b0d44f..031d27846 100644
--- a/scrapy/middleware.py
+++ b/scrapy/middleware.py
@@ -21,13 +21,15 @@ class MiddlewareManager(object):
raise NotImplementedError
@classmethod
- def from_settings(cls, settings):
+ def from_settings(cls, settings, crawler=None):
mwlist = cls._get_mwlist_from_settings(settings)
middlewares = []
for clspath in mwlist:
try:
mwcls = load_object(clspath)
- if hasattr(mwcls, 'from_settings'):
+ if crawler and hasattr(mwcls, 'from_crawler'):
+ mw = mwcls.from_crawler(crawler)
+ elif hasattr(mwcls, 'from_settings'):
mw = mwcls.from_settings(settings)
else:
mw = mwcls()
@@ -41,6 +43,10 @@ class MiddlewareManager(object):
level=log.DEBUG)
return cls(*middlewares)
+ @classmethod
+ def from_crawler(cls, crawler):
+ return cls.from_settings(crawler.settings, crawler)
+
def _add_middleware(self, mw):
if hasattr(mw, 'open_spider'):
self.methods['open_spider'].append(mw.open_spider)
diff --git a/scrapy/core/downloader/responsetypes/mime.types b/scrapy/mime.types
similarity index 100%
rename from scrapy/core/downloader/responsetypes/mime.types
rename to scrapy/mime.types
diff --git a/scrapy/project.py b/scrapy/project.py
index bbcb0fd27..bbe947761 100644
--- a/scrapy/project.py
+++ b/scrapy/project.py
@@ -1,11 +1,13 @@
"""
-This module contains the Scrapy Crawler once installed by calling the crawler
-``install`` method, like this::
+--------- WARNING: THIS MODULE IS DEPRECATED -----------
- crawler.install()
+This module is deprecated. If you want to get the Scrapy crawler from your
+extension, middleware or pipeline implement the `from_crawler` class method.
-After that, you can import the (singleton) crawler like this::
+For example:
- from scrapy.project import crawler
+ @classmethod
+ def from_crawler(cls, crawler):
+ return cls(crawler)
"""
diff --git a/scrapy/queue.py b/scrapy/queue.py
deleted file mode 100644
index 2f2a17de5..000000000
--- a/scrapy/queue.py
+++ /dev/null
@@ -1,96 +0,0 @@
-from twisted.internet import defer
-
-from scrapy.http import Request
-from scrapy.utils.misc import arg_to_iter
-from scrapy.utils.spider import create_spider_for_request
-from scrapy.utils.python import stringify_dict
-from scrapy import log
-
-
-class ExecutionQueue(object):
-
- def __init__(self, spiders, queue, poll_interval=5, keep_alive=False):
- self.spider_requests = []
- self.poll_interval = poll_interval
- self._spiders = spiders
- self._queue = queue
- self._keepalive = keep_alive
-
- @defer.inlineCallbacks
- def _append_next(self):
- """Called when there are no more items left in self.spider_requests.
- This method is meant to be overriden in subclasses to add new (spider,
- requests) tuples to self.spider_requests. It can return a Deferred.
- """
- msg = yield self._queue.pop()
- if msg:
- name = msg.pop('name')
- msg = stringify_dict(msg) # see #250
- self.append_spider_name(name, **msg)
-
- def get_next(self):
- """Return a tuple (spider, requests) containing a list of Requests and
- the Spider which will be used to crawl those Requests. If there aren't
- any more spiders to crawl it must return (None, []).
-
- This method can return a deferred.
- """
- if self.spider_requests:
- return self._get_next_now()
- d = defer.maybeDeferred(self._append_next)
- d.addCallback(lambda _: self._get_next_now())
- return d
-
- def _get_next_now(self):
- try:
- return self.spider_requests.pop(0)
- except IndexError:
- return (None, [])
-
- def is_finished(self):
- """Return True if the queue is empty and there won't be any more
- spiders to crawl (this is for one-shot runs). If it returns ``False``
- Scrapy will keep polling this queue for new requests to scrape
- """
- return not self._keepalive and not bool(self.spider_requests)
-
- def append_spider(self, spider):
- """Append a Spider to crawl"""
- requests = spider.start_requests()
- self.spider_requests.append((spider, requests))
-
- def append_request(self, request, spider=None, **kwargs):
- if spider is None:
- spider = create_spider_for_request(self._spiders, request, **kwargs)
- if spider:
- self.spider_requests.append((spider, [request]))
-
- def append_url(self, url=None, spider=None, **kwargs):
- """Append a URL to crawl with the given spider. If the spider is not
- given, a spider will be looked up based on the URL
- """
- if url is None:
- raise ValueError("A url is required")
- if spider is None:
- spider = create_spider_for_request(self._spiders, Request(url), \
- **kwargs)
- if spider:
- requests = arg_to_iter(spider.make_requests_from_url(url))
- self.spider_requests.append((spider, requests))
-
- def append_spider_name(self, name=None, **spider_kwargs):
- """Append a spider to crawl given its name and optional arguments,
- which are used to instantiate it. The SpiderManager is used to lookup
- the spider
- """
- if name is None:
- raise ValueError("A spider name is required")
- try:
- spider = self._spiders.create(name, **spider_kwargs)
- except KeyError:
- log.msg('Unable to find spider: %s' % name, log.ERROR)
- except:
- log.err(None, 'Error creating spider %r with arguments: %r' % \
- (name, spider_kwargs))
- else:
- self.append_spider(spider)
diff --git a/scrapy/resolver.py b/scrapy/resolver.py
new file mode 100644
index 000000000..6ba89ac94
--- /dev/null
+++ b/scrapy/resolver.py
@@ -0,0 +1,24 @@
+import socket
+
+from twisted.internet import defer
+from twisted.internet.base import ThreadedResolver
+
+from scrapy.utils.datatypes import LocalCache
+
+# TODO: cache misses
+# TODO: make cache size a setting
+
+dnscache = LocalCache(10000)
+
+class CachingThreadedResolver(ThreadedResolver):
+
+ def getHostByName(self, name, timeout = (1, 3, 11, 45)):
+ if name in dnscache:
+ return defer.succeed(dnscache[name])
+ d = ThreadedResolver.getHostByName(self, name, timeout)
+ d.addCallback(self._cache_result, name)
+ return d
+
+ def _cache_result(self, result, name):
+ dnscache[name] = result
+ return result
diff --git a/scrapy/core/downloader/responsetypes/__init__.py b/scrapy/responsetypes.py
similarity index 97%
rename from scrapy/core/downloader/responsetypes/__init__.py
rename to scrapy/responsetypes.py
index 99ee291b6..66f3c05db 100644
--- a/scrapy/core/downloader/responsetypes/__init__.py
+++ b/scrapy/responsetypes.py
@@ -14,8 +14,6 @@ from scrapy.utils.python import isbinarytext
from scrapy.utils.py26 import get_data
from scrapy.conf import settings
-__package__ = 'scrapy.core.downloader.responsetypes' # required for python 2.5
-
class ResponseTypes(object):
CLASSES = {
@@ -36,7 +34,7 @@ class ResponseTypes(object):
self.CLASSES.update(settings.get('RESPONSE_CLASSES', {}))
self.classes = {}
self.mimetypes = MimeTypes()
- mimedata = get_data(__package__, 'mime.types')
+ mimedata = get_data('scrapy', 'mime.types')
self.mimetypes.readfp(StringIO(mimedata))
for mimetype, cls in self.CLASSES.iteritems():
self.classes[mimetype] = load_object(cls)
diff --git a/scrapy/settings/default_settings.py b/scrapy/settings/default_settings.py
index 015b1d911..2c7a5e8a0 100644
--- a/scrapy/settings/default_settings.py
+++ b/scrapy/settings/default_settings.py
@@ -13,6 +13,7 @@ Scrapy developers, if you add a setting here remember to:
"""
+import sys, os
from os.path import join, abspath, dirname
BOT_NAME = 'scrapybot'
@@ -20,14 +21,19 @@ BOT_VERSION = '1.0'
CLOSESPIDER_TIMEOUT = 0
CLOSESPIDER_PAGECOUNT = 0
-CLOSESPIDER_ITEMPASSED = 0
+CLOSESPIDER_ITEMCOUNT = 0
COMMANDS_MODULE = ''
CONCURRENT_ITEMS = 100
-CONCURRENT_REQUESTS_PER_SPIDER = 8
+
+CONCURRENT_REQUESTS = 16
+CONCURRENT_REQUESTS_PER_DOMAIN = 8
+CONCURRENT_REQUESTS_PER_IP = 0
+
CONCURRENT_SPIDERS = 8
+COOKIES_ENABLED = True
COOKIES_DEBUG = False
DEFAULT_ITEM_CLASS = 'scrapy.item.Item'
@@ -41,6 +47,9 @@ DEFAULT_RESPONSE_ENCODING = 'ascii'
DEPTH_LIMIT = 0
DEPTH_STATS = True
+DEPTH_PRIORITY = 1
+
+DNSCACHE_ENABLED = True
DOWNLOAD_DELAY = 0
@@ -72,6 +81,7 @@ DOWNLOADER_MIDDLEWARES_BASE = {
'scrapy.contrib.downloadermiddleware.cookies.CookiesMiddleware': 700,
'scrapy.contrib.downloadermiddleware.httpproxy.HttpProxyMiddleware': 750,
'scrapy.contrib.downloadermiddleware.httpcompression.HttpCompressionMiddleware': 800,
+ 'scrapy.contrib.downloadermiddleware.chunked.ChunkedTransferMiddleware': 830,
'scrapy.contrib.downloadermiddleware.stats.DownloaderStats': 850,
'scrapy.contrib.downloadermiddleware.httpcache.HttpCacheMiddleware': 900,
# Downloader side
@@ -79,7 +89,15 @@ DOWNLOADER_MIDDLEWARES_BASE = {
DOWNLOADER_STATS = True
-DUPEFILTER_CLASS = 'scrapy.contrib.dupefilter.RequestFingerprintDupeFilter'
+DUPEFILTER_CLASS = 'scrapy.dupefilter.RFPDupeFilter'
+
+try:
+ EDITOR = os.environ['EDITOR']
+except KeyError:
+ if sys.platform == 'win32':
+ EDITOR = '%s -m idlelib.idle'
+ else:
+ EDITOR = 'vi'
ENCODING_ALIASES = {}
@@ -126,6 +144,7 @@ EXTENSIONS_BASE = {
'scrapy.contrib.closespider.CloseSpider': 0,
'scrapy.contrib.feedexport.FeedExporter': 0,
'scrapy.contrib.spidercontext.SpiderContext': 0,
+ 'scrapy.contrib.logstats.LogStats': 0,
}
FEED_URI = None
@@ -146,6 +165,7 @@ FEED_EXPORTERS_BASE = {
'jsonlines': 'scrapy.contrib.exporter.JsonLinesItemExporter',
'csv': 'scrapy.contrib.exporter.CsvItemExporter',
'xml': 'scrapy.contrib.exporter.XmlItemExporter',
+ 'marshal': 'scrapy.contrib.exporter.MarshalItemExporter',
}
HTTPCACHE_ENABLED = False
@@ -155,14 +175,13 @@ HTTPCACHE_STORAGE = 'scrapy.contrib.downloadermiddleware.httpcache.FilesystemCac
HTTPCACHE_EXPIRATION_SECS = 0
HTTPCACHE_IGNORE_HTTP_CODES = []
HTTPCACHE_IGNORE_SCHEMES = ['file']
+HTTPCACHE_DBM_MODULE = 'anydbm'
ITEM_PROCESSOR = 'scrapy.contrib.pipeline.ItemPipelineManager'
# Item pipelines are typically set in specific commands settings
ITEM_PIPELINES = []
-KEEP_ALIVE = False
-
LOG_ENABLED = True
LOG_ENCODING = 'utf-8'
LOG_FORMATTER = 'scrapy.logformatter.LogFormatter'
@@ -170,6 +189,8 @@ LOG_STDOUT = False
LOG_LEVEL = 'DEBUG'
LOG_FILE = None
+LOGSTATS_INTERVAL = 60.0
+
MAIL_DEBUG = False
MAIL_HOST = 'localhost'
MAIL_PORT = 25
@@ -188,30 +209,22 @@ MEMUSAGE_WARNING_MB = 0
NEWSPIDER_MODULE = ''
-QUEUE_POLL_INTERVAL = 5
-
RANDOMIZE_DOWNLOAD_DELAY = True
+REDIRECT_ENABLED = True
REDIRECT_MAX_METAREFRESH_DELAY = 100
REDIRECT_MAX_TIMES = 20 # uses Firefox default setting
REDIRECT_PRIORITY_ADJUST = +2
-# contrib.middleware.retry.RetryMiddleware default settings
+RETRY_ENABLED = True
RETRY_TIMES = 2 # initial response + 2 retries = 3 requests
-RETRY_HTTP_CODES = ['500', '503', '504', '400', '408']
+RETRY_HTTP_CODES = [500, 503, 504, 400, 408]
RETRY_PRIORITY_ADJUST = -1
ROBOTSTXT_OBEY = False
SCHEDULER = 'scrapy.core.scheduler.Scheduler'
-
-SCHEDULER_MIDDLEWARES = {}
-
-SCHEDULER_MIDDLEWARES_BASE = {
- 'scrapy.contrib.schedulermiddleware.duplicatesfilter.DuplicatesFilterMiddleware': 500,
-}
-
-SCHEDULER_ORDER = 'DFO'
+SCHEDULER_DISK_QUEUE = 'scrapy.squeue.MarshalDiskQueue'
SELECTORS_BACKEND = None # possible values: libxml2, lxml
@@ -231,24 +244,15 @@ SPIDER_MIDDLEWARES_BASE = {
SPIDER_MODULES = []
-SPIDER_QUEUE_CLASS = 'scrapy.spiderqueue.SqliteSpiderQueue'
-
SPIDER_CONTEXT_ENABLED = True
SPIDER_CONTEXT_STORAGE_CLASS = 'scrapy.contrib.spidercontext.SqliteSpiderContextStorage'
SQLITE_DB = 'scrapy.db'
-SQS_QUEUE = 'scrapy'
-SQS_VISIBILITY_TIMEOUT = 7200
-SQS_REGION = 'us-east-1'
-
STATS_CLASS = 'scrapy.statscol.MemoryStatsCollector'
STATS_ENABLED = True
-STATS_DUMP = False
-
-STATS_SDB_DOMAIN = 'scrapy_stats'
-STATS_SDB_ASYNC = False
+STATS_DUMP = True
STATSMAILER_RCPTS = []
diff --git a/scrapy/shell.py b/scrapy/shell.py
index 15da950b7..258c03ba6 100644
--- a/scrapy/shell.py
+++ b/scrapy/shell.py
@@ -7,14 +7,15 @@ See documentation in docs/topics/shell.rst
import signal
from twisted.internet import reactor, threads
+from w3lib.url import any_to_uri
from scrapy.item import BaseItem
from scrapy.spider import BaseSpider
from scrapy.selector import XPathSelector, XmlXPathSelector, HtmlXPathSelector
from scrapy.utils.spider import create_spider_for_request
from scrapy.utils.misc import load_object
+from scrapy.utils.request import request_deferred
from scrapy.utils.response import open_in_browser
-from scrapy.utils.url import any_to_uri
from scrapy.utils.console import start_python_console
from scrapy.settings import Settings
from scrapy.http import Request, Response, HtmlResponse, XmlResponse
@@ -60,9 +61,10 @@ class Shell(object):
spider = create_spider_for_request(self.crawler.spiders, request, \
BaseSpider('default'), log_multiple=True)
spider.set_crawler(self.crawler)
- self.crawler.engine.open_spider(spider)
- d = self.crawler.engine.schedule(request, spider)
+ self.crawler.engine.open_spider(spider, close_if_idle=False)
+ d = request_deferred(request)
d.addCallback(lambda x: (x, spider))
+ self.crawler.engine.crawl(request, spider)
return d
def fetch(self, request_or_url, spider=None):
@@ -72,6 +74,7 @@ class Shell(object):
else:
url = any_to_uri(request_or_url)
request = Request(url, dont_filter=True)
+ request.meta['handle_httpstatus_all'] = True
response = None
response, spider = threads.blockingCallFromThread(reactor, \
self._schedule, request, spider)
diff --git a/scrapy/signals.py b/scrapy/signals.py
index e907e5fcb..d2708d588 100644
--- a/scrapy/signals.py
+++ b/scrapy/signals.py
@@ -10,12 +10,14 @@ engine_stopped = object()
spider_opened = object()
spider_idle = object()
spider_closed = object()
+spider_error = object()
request_received = object()
response_received = object()
response_downloaded = object()
item_scraped = object()
-item_passed = object()
item_dropped = object()
stats_spider_opened = object()
stats_spider_closing = object()
stats_spider_closed = object()
+
+item_passed = item_scraped # for backwards compatibility
diff --git a/scrapy/spidermanager.py b/scrapy/spidermanager.py
index a398e553b..25f984aa0 100644
--- a/scrapy/spidermanager.py
+++ b/scrapy/spidermanager.py
@@ -33,7 +33,10 @@ class SpiderManager(object):
return cls(settings.getlist('SPIDER_MODULES'))
def create(self, spider_name, **spider_kwargs):
- return self._spiders[spider_name](**spider_kwargs)
+ try:
+ return self._spiders[spider_name](**spider_kwargs)
+ except KeyError:
+ raise KeyError("Spider not found: %s" % spider_name)
def find_by_request(self, request):
return [name for name, cls in self._spiders.iteritems()
diff --git a/scrapy/squeue.py b/scrapy/squeue.py
new file mode 100644
index 000000000..2fd4f05ee
--- /dev/null
+++ b/scrapy/squeue.py
@@ -0,0 +1,17 @@
+"""
+Scheduler disk-based queues
+"""
+
+import marshal
+
+from scrapy.utils.queue import DiskQueue
+
+class MarshalDiskQueue(DiskQueue):
+
+ def push(self, obj):
+ super(MarshalDiskQueue, self).push(marshal.dumps(obj))
+
+ def pop(self):
+ s = super(MarshalDiskQueue, self).pop()
+ if s:
+ return marshal.loads(s)
diff --git a/scrapy/statscol.py b/scrapy/statscol.py
index c69510dd0..b4ecb2f05 100644
--- a/scrapy/statscol.py
+++ b/scrapy/statscol.py
@@ -17,7 +17,6 @@ class StatsCollector(object):
def __init__(self):
self._dump = settings.getbool('STATS_DUMP')
self._stats = {None: {}} # None is for global stats
- dispatcher.connect(self._engine_stopped, signal=signals.engine_stopped)
def get_value(self, key, default=None, spider=None):
return self._stats[spider].get(key, default)
@@ -63,7 +62,7 @@ class StatsCollector(object):
spider=spider)
self._persist_stats(stats, spider)
- def _engine_stopped(self):
+ def engine_stopped(self):
stats = self.get_stats()
if self._dump:
log.msg("Dumping global stats:\n" + pprint.pformat(stats))
diff --git a/scrapy/telnet.py b/scrapy/telnet.py
index cd52b0b8d..2d9b056be 100644
--- a/scrapy/telnet.py
+++ b/scrapy/telnet.py
@@ -12,14 +12,12 @@ from twisted.internet import protocol
from scrapy.xlib.pydispatch import dispatcher
from scrapy.exceptions import NotConfigured
-from scrapy.project import crawler
from scrapy.stats import stats
from scrapy import log, signals
from scrapy.utils.signal import send_catch_log
from scrapy.utils.trackref import print_live_refs
from scrapy.utils.engine import print_engine_status
from scrapy.utils.reactor import listen_tcp
-from scrapy.conf import settings
try:
import guppy
@@ -34,15 +32,20 @@ update_telnet_vars = object()
class TelnetConsole(protocol.ServerFactory):
- def __init__(self):
- if not settings.getbool('TELNETCONSOLE_ENABLED'):
+ def __init__(self, crawler):
+ if not crawler.settings.getbool('TELNETCONSOLE_ENABLED'):
raise NotConfigured
+ self.crawler = crawler
self.noisy = False
- self.portrange = map(int, settings.getlist('TELNETCONSOLE_PORT'))
- self.host = settings['TELNETCONSOLE_HOST']
+ self.portrange = map(int, crawler.settings.getlist('TELNETCONSOLE_PORT'))
+ self.host = crawler.settings['TELNETCONSOLE_HOST']
dispatcher.connect(self.start_listening, signals.engine_started)
dispatcher.connect(self.stop_listening, signals.engine_stopped)
+ @classmethod
+ def from_crawler(cls, crawler):
+ return cls(crawler)
+
def start_listening(self):
self.port = listen_tcp(self.portrange, self.host, self)
h = self.port.getHost()
@@ -58,14 +61,19 @@ class TelnetConsole(protocol.ServerFactory):
def _get_telnet_vars(self):
# Note: if you add entries here also update topics/telnetconsole.rst
+ slots = self.crawler.engine.slots
+ if len(slots) == 1:
+ spider, slot = slots.items()[0]
telnet_vars = {
- 'engine': crawler.engine,
- 'manager': crawler,
- 'extensions': crawler.extensions,
+ 'engine': self.crawler.engine,
+ 'spider': spider,
+ 'slot': slot,
+ 'manager': self.crawler,
+ 'extensions': self.crawler.extensions,
'stats': stats,
- 'spiders': crawler.spiders,
- 'settings': settings,
- 'est': print_engine_status,
+ 'spiders': self.crawler.spiders,
+ 'settings': self.crawler.settings,
+ 'est': lambda: print_engine_status(self.crawler.engine),
'p': pprint.pprint,
'prefs': print_live_refs,
'hpy': hpy,
diff --git a/scrapy/templates/project/module/settings.py.tmpl b/scrapy/templates/project/module/settings.py.tmpl
index ce2751f0f..5ae6cbf5a 100644
--- a/scrapy/templates/project/module/settings.py.tmpl
+++ b/scrapy/templates/project/module/settings.py.tmpl
@@ -11,6 +11,5 @@ BOT_VERSION = '1.0'
SPIDER_MODULES = ['$project_name.spiders']
NEWSPIDER_MODULE = '$project_name.spiders'
-DEFAULT_ITEM_CLASS = '$project_name.items.${ProjectName}Item'
USER_AGENT = '%s/%s' % (BOT_NAME, BOT_VERSION)
diff --git a/scrapy/templates/spiders/crawl.tmpl b/scrapy/templates/spiders/crawl.tmpl
index d0036443f..c6d0ab9f7 100644
--- a/scrapy/templates/spiders/crawl.tmpl
+++ b/scrapy/templates/spiders/crawl.tmpl
@@ -1,5 +1,3 @@
-import re
-
from scrapy.selector import HtmlXPathSelector
from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor
from scrapy.contrib.spiders import CrawlSpider, Rule
diff --git a/scrapy/tests/sample_data/compressed/truncated-crc-error.gz b/scrapy/tests/sample_data/compressed/truncated-crc-error.gz
new file mode 100644
index 000000000..2eeb4da16
Binary files /dev/null and b/scrapy/tests/sample_data/compressed/truncated-crc-error.gz differ
diff --git a/scrapy/tests/test_cmdline/__init__.py b/scrapy/tests/test_cmdline/__init__.py
index d08f266f1..2fb08e119 100644
--- a/scrapy/tests/test_cmdline/__init__.py
+++ b/scrapy/tests/test_cmdline/__init__.py
@@ -3,13 +3,12 @@ import os
from subprocess import Popen, PIPE
import unittest
-import scrapy
-
class CmdlineTest(unittest.TestCase):
def setUp(self):
self.env = os.environ.copy()
- self.env['PYTHONPATH'] = os.path.dirname(scrapy.__path__[0])
+ if 'PYTHONPATH' in os.environ:
+ self.env['PYTHONPATH'] = os.environ['PYTHONPATH']
self.env['SCRAPY_SETTINGS_MODULE'] = 'scrapy.tests.test_cmdline.settings'
def _execute(self, *new_args, **kwargs):
diff --git a/scrapy/tests/test_command_fetch.py b/scrapy/tests/test_command_fetch.py
index 2e36c8c6e..5283852b7 100644
--- a/scrapy/tests/test_command_fetch.py
+++ b/scrapy/tests/test_command_fetch.py
@@ -18,6 +18,5 @@ class FetchTest(ProcessTest, SiteTest, unittest.TestCase):
def test_headers(self):
_, out, _ = yield self.execute([self.url('/text'), '--headers'])
out = out.replace('\r', '') # required on win32
- headers = eval(out)
- assert 'TwistedWeb' in headers['Server'][0]
- self.assertEqual(headers['Content-Type'], ['text/plain'])
+ assert 'Server: TwistedWeb' in out
+ assert 'Content-Type: text/plain' in out
diff --git a/scrapy/tests/test_command_shell.py b/scrapy/tests/test_command_shell.py
index ffba30415..068492503 100644
--- a/scrapy/tests/test_command_shell.py
+++ b/scrapy/tests/test_command_shell.py
@@ -12,7 +12,7 @@ class ShellTest(ProcessTest, SiteTest, unittest.TestCase):
@defer.inlineCallbacks
def test_empty(self):
_, out, _ = yield self.execute(['-c', 'item'])
- assert 'Item' in out
+ assert '{}' in out
@defer.inlineCallbacks
def test_response_body(self):
diff --git a/scrapy/tests/test_commands.py b/scrapy/tests/test_commands.py
index e2b671d19..374872e54 100644
--- a/scrapy/tests/test_commands.py
+++ b/scrapy/tests/test_commands.py
@@ -3,14 +3,12 @@ from __future__ import with_statement
import sys
import os
import subprocess
-from os.path import exists, join, dirname, abspath
+from os.path import exists, join, abspath
from shutil import rmtree
from tempfile import mkdtemp
from twisted.trial import unittest
-import scrapy
-
class ProjectTest(unittest.TestCase):
project_name = 'testproject'
@@ -21,7 +19,8 @@ class ProjectTest(unittest.TestCase):
self.proj_path = join(self.temp_path, self.project_name)
self.proj_mod_path = join(self.proj_path, self.project_name)
self.env = os.environ.copy()
- self.env['PYTHONPATH'] = dirname(scrapy.__path__[0])
+ if 'PYTHONPATH' in os.environ:
+ self.env['PYTHONPATH'] = os.environ['PYTHONPATH']
def tearDown(self):
rmtree(self.temp_path)
@@ -104,9 +103,6 @@ class GenspiderCommandTest(CommandTest):
class MiscCommandsTest(CommandTest):
- def test_crawl(self):
- self.assertEqual(0, self.call('crawl'))
-
def test_list(self):
self.assertEqual(0, self.call('list'))
diff --git a/scrapy/tests/test_contrib_exp_crawlspider_matchers.py b/scrapy/tests/test_contrib_exp_crawlspider_matchers.py
deleted file mode 100644
index 4cb832aa1..000000000
--- a/scrapy/tests/test_contrib_exp_crawlspider_matchers.py
+++ /dev/null
@@ -1,94 +0,0 @@
-from twisted.trial import unittest
-
-from scrapy.http import Request
-from scrapy.http import Response
-
-from scrapy.contrib_exp.crawlspider.matchers import BaseMatcher
-from scrapy.contrib_exp.crawlspider.matchers import UrlMatcher
-from scrapy.contrib_exp.crawlspider.matchers import UrlRegexMatcher
-from scrapy.contrib_exp.crawlspider.matchers import UrlListMatcher
-
-import re
-
-class MatchersTest(unittest.TestCase):
-
- def setUp(self):
- pass
-
- def test_base_matcher(self):
- matcher = BaseMatcher()
-
- request = Request('http://example.com')
- response = Response('http://example.com')
-
- self.assertTrue(matcher.matches_request(request))
- self.assertTrue(matcher.matches_response(response))
-
- def test_url_matcher(self):
- matcher = UrlMatcher('http://example.com')
-
- request = Request('http://example.com')
- response = Response('http://example.com')
-
- self.failUnless(matcher.matches_request(request))
- self.failUnless(matcher.matches_request(response))
-
- request = Request('http://example2.com')
- response = Response('http://example2.com')
-
- self.failIf(matcher.matches_request(request))
- self.failIf(matcher.matches_request(response))
-
- def test_url_regex_matcher(self):
- matcher = UrlRegexMatcher(r'sample')
- urls = (
- 'http://example.com/sample1.html',
- 'http://example.com/sample2.html',
- 'http://example.com/sample3.html',
- 'http://example.com/sample4.html',
- )
- for url in urls:
- request, response = Request(url), Response(url)
- self.failUnless(matcher.matches_request(request))
- self.failUnless(matcher.matches_response(response))
-
- matcher = UrlRegexMatcher(r'sample_fail')
- for url in urls:
- request, response = Request(url), Response(url)
- self.failIf(matcher.matches_request(request))
- self.failIf(matcher.matches_response(response))
-
- matcher = UrlRegexMatcher(r'SAMPLE\d+', re.IGNORECASE)
- for url in urls:
- request, response = Request(url), Response(url)
- self.failUnless(matcher.matches_request(request))
- self.failUnless(matcher.matches_response(response))
-
- def test_url_list_matcher(self):
- urls = (
- 'http://example.com/sample1.html',
- 'http://example.com/sample2.html',
- 'http://example.com/sample3.html',
- 'http://example.com/sample4.html',
- )
- urls2 = (
- 'http://example.com/sample5.html',
- 'http://example.com/sample6.html',
- 'http://example.com/sample7.html',
- 'http://example.com/sample8.html',
- 'http://example.com/',
- )
- matcher = UrlListMatcher(urls)
-
- # match urls
- for url in urls:
- request, response = Request(url), Response(url)
- self.failUnless(matcher.matches_request(request))
- self.failUnless(matcher.matches_response(response))
-
- # non-match urls
- for url in urls2:
- request, response = Request(url), Response(url)
- self.failIf(matcher.matches_request(request))
- self.failIf(matcher.matches_response(response))
-
diff --git a/scrapy/tests/test_contrib_exp_crawlspider_reqext.py b/scrapy/tests/test_contrib_exp_crawlspider_reqext.py
deleted file mode 100644
index 0259b30fb..000000000
--- a/scrapy/tests/test_contrib_exp_crawlspider_reqext.py
+++ /dev/null
@@ -1,156 +0,0 @@
-from twisted.trial import unittest
-
-from scrapy.http import Request
-from scrapy.http import HtmlResponse
-from scrapy.tests import get_testdata
-
-from scrapy.contrib_exp.crawlspider.reqext import BaseSgmlRequestExtractor
-from scrapy.contrib_exp.crawlspider.reqext import SgmlRequestExtractor
-from scrapy.contrib_exp.crawlspider.reqext import XPathRequestExtractor
-
-class AbstractRequestExtractorTest(unittest.TestCase):
-
- def _requests_equals(self, list1, list2):
- """Compares request's urls and link_text"""
- for (r1, r2) in zip(list1, list2):
- if r1.url != r2.url:
- return False
- if r1.meta['link_text'] != r2.meta['link_text']:
- return False
- # all equal
- return True
-
-
-class RequestExtractorTest(AbstractRequestExtractorTest):
-
- def test_basic(self):
- base_url = 'http://example.org/somepage/index.html'
- html = """Page title
- Item 12
- About us
-
- Other category
-
"""
- requests = [
- Request('http://example.org/somepage/item/12.html',
- meta={'link_text': 'Item 12'}),
- Request('http://example.org/about.html',
- meta={'link_text': 'About us'}),
- Request('http://example.org/othercat.html',
- meta={'link_text': 'Other category'}),
- Request('http://example.org/',
- meta={'link_text': ''}),
- ]
-
- response = HtmlResponse(base_url, body=html)
- reqx = BaseSgmlRequestExtractor() # default: tag=a, attr=href
-
- self.failUnless(
- self._requests_equals(requests, reqx.extract_requests(response))
- )
-
- def test_base_url(self):
- reqx = BaseSgmlRequestExtractor()
-
- html = """Page title
-
- Item 12
- """
- response = HtmlResponse("https://example.org/p/index.html", body=html)
- reqs = reqx.extract_requests(response)
- self.failUnless(self._requests_equals( \
- [Request('http://otherdomain.com/base/item/12.html', \
- meta={'link_text': 'Item 12'})], reqs), reqs)
-
- # base url is an absolute path and relative to host
- html = """Page title
-
- Item 12
- """
- response = HtmlResponse("https://example.org/p/index.html", body=html)
- reqs = reqx.extract_requests(response)
- self.failUnless(self._requests_equals( \
- [Request('https://example.org/item/12.html', \
- meta={'link_text': 'Item 12'})], reqs), reqs)
-
- # base url has no scheme
- html = """Page title
-
- Item 12
- """
- response = HtmlResponse("https://example.org/p/index.html", body=html)
- reqs = reqx.extract_requests(response)
- self.failUnless(self._requests_equals( \
- [Request('https://noscheme.com/base/item/12.html', \
- meta={'link_text': 'Item 12'})], reqs), reqs)
-
- def test_extraction_encoding(self):
- #TODO: use own fixtures
- body = get_testdata('link_extractor', 'linkextractor_noenc.html')
- response_utf8 = HtmlResponse(url='http://example.com/utf8', body=body,
- headers={'Content-Type': ['text/html; charset=utf-8']})
- response_noenc = HtmlResponse(url='http://example.com/noenc',
- body=body)
- body = get_testdata('link_extractor', 'linkextractor_latin1.html')
- response_latin1 = HtmlResponse(url='http://example.com/latin1',
- body=body)
-
- reqx = BaseSgmlRequestExtractor()
- self.failUnless(
- self._requests_equals(
- reqx.extract_requests(response_utf8),
- [ Request(url='http://example.com/sample_%C3%B1.html',
- meta={'link_text': ''}),
- Request(url='http://example.com/sample_%E2%82%AC.html',
- meta={'link_text':
- 'sample \xe2\x82\xac text'.decode('utf-8')}) ]
- )
- )
-
- self.failUnless(
- self._requests_equals(
- reqx.extract_requests(response_noenc),
- [ Request(url='http://example.com/sample_%C3%B1.html',
- meta={'link_text': ''}),
- Request(url='http://example.com/sample_%E2%82%AC.html',
- meta={'link_text':
- 'sample \xe2\x82\xac text'.decode('utf-8')}) ]
- )
- )
-
- self.failUnless(
- self._requests_equals(
- reqx.extract_requests(response_latin1),
- [ Request(url='http://example.com/sample_%F1.html',
- meta={'link_text': ''}),
- Request(url='http://example.com/sample_%E1.html',
- meta={'link_text':
- 'sample \xe1 text'.decode('latin1')}) ]
- )
- )
-
-
-class SgmlRequestExtractorTest(AbstractRequestExtractorTest):
- pass
-
-
-class XPathRequestExtractorTest(AbstractRequestExtractorTest):
-
- def setUp(self):
- # TODO: use own fixtures
- body = get_testdata('link_extractor', 'sgml_linkextractor.html')
- self.response = HtmlResponse(url='http://example.com/index', body=body)
-
-
- def test_restrict_xpaths(self):
- reqx = XPathRequestExtractor('//div[@id="subwrapper"]')
- self.failUnless(
- self._requests_equals(
- reqx.extract_requests(self.response),
- [ Request(url='http://example.com/sample1.html',
- meta={'link_text': ''}),
- Request(url='http://example.com/sample2.html',
- meta={'link_text': 'sample 2'}) ]
- )
- )
-
diff --git a/scrapy/tests/test_contrib_exp_crawlspider_reqgen.py b/scrapy/tests/test_contrib_exp_crawlspider_reqgen.py
deleted file mode 100644
index b6e1ea932..000000000
--- a/scrapy/tests/test_contrib_exp_crawlspider_reqgen.py
+++ /dev/null
@@ -1,124 +0,0 @@
-from twisted.internet import defer
-from twisted.trial import unittest
-
-from scrapy.http import Request
-from scrapy.http import HtmlResponse
-from scrapy.utils.python import equal_attributes
-
-from scrapy.contrib_exp.crawlspider.reqext import SgmlRequestExtractor
-from scrapy.contrib_exp.crawlspider.reqgen import RequestGenerator
-from scrapy.contrib_exp.crawlspider.reqproc import Canonicalize
-from scrapy.contrib_exp.crawlspider.reqproc import FilterDomain
-from scrapy.contrib_exp.crawlspider.reqproc import FilterUrl
-from scrapy.contrib_exp.crawlspider.reqproc import FilterDupes
-
-class RequestGeneratorTest(unittest.TestCase):
-
- def setUp(self):
- url = 'http://example.org/somepage/index.html'
- html = """Page title
- Item 12
- About us
-
- Other category
-
"""
-
- self.response = HtmlResponse(url, body=html)
- self.deferred = defer.Deferred()
- self.requests = [
- Request('http://example.org/somepage/item/12.html',
- meta={'link_text': 'Item 12'}),
- Request('http://example.org/about.html',
- meta={'link_text': 'About us'}),
- Request('http://example.org/othercat.html',
- meta={'link_text': 'Other category'}),
- Request('http://example.org/',
- meta={'link_text': ''}),
- ]
-
- def _equal_requests_list(self, list1, list2):
- list1 = list(list1)
- list2 = list(list2)
- if not len(list1) == len(list2):
- return False
-
- for (req1, req2) in zip(list1, list2):
- if not equal_attributes(req1, req2, ['url']):
- return False
- return True
-
- def test_basic(self):
- reqgen = RequestGenerator([], [], callback=self.deferred)
- # returns generator
- requests = reqgen.generate_requests(self.response)
- self.failUnlessEqual(list(requests), [])
-
- def test_request_extractor(self):
- extractors = [
- SgmlRequestExtractor()
- ]
-
- # extract all requests
- reqgen = RequestGenerator(extractors, [], callback=self.deferred)
- requests = reqgen.generate_requests(self.response)
- self.failUnless(self._equal_requests_list(requests, self.requests))
-
- def test_request_processor(self):
- extractors = [
- SgmlRequestExtractor()
- ]
-
- processors = [
- Canonicalize(),
- FilterDupes(),
- ]
-
- reqgen = RequestGenerator(extractors, processors, callback=self.deferred)
- requests = reqgen.generate_requests(self.response)
- self.failUnless(self._equal_requests_list(requests, self.requests))
-
- # filter domain
- processors = [
- Canonicalize(),
- FilterDupes(),
- FilterDomain(deny='example.org'),
- ]
-
- reqgen = RequestGenerator(extractors, processors, callback=self.deferred)
- requests = reqgen.generate_requests(self.response)
- self.failUnlessEqual(list(requests), [])
-
- # filter url
- processors = [
- Canonicalize(),
- FilterDupes(),
- FilterUrl(deny=(r'about', r'othercat')),
- ]
-
- reqgen = RequestGenerator(extractors, processors, callback=self.deferred)
- requests = reqgen.generate_requests(self.response)
-
- self.failUnless(self._equal_requests_list(requests, [
- Request('http://example.org/somepage/item/12.html',
- meta={'link_text': 'Item 12'}),
- Request('http://example.org/',
- meta={'link_text': ''}),
- ]))
-
- processors = [
- Canonicalize(),
- FilterDupes(),
- FilterUrl(allow=r'/somepage/'),
- ]
-
- reqgen = RequestGenerator(extractors, processors, callback=self.deferred)
- requests = reqgen.generate_requests(self.response)
-
- self.failUnless(self._equal_requests_list(requests, [
- Request('http://example.org/somepage/item/12.html',
- meta={'link_text': 'Item 12'}),
- ]))
-
-
-
-
diff --git a/scrapy/tests/test_contrib_exp_crawlspider_reqproc.py b/scrapy/tests/test_contrib_exp_crawlspider_reqproc.py
deleted file mode 100644
index da5db67b2..000000000
--- a/scrapy/tests/test_contrib_exp_crawlspider_reqproc.py
+++ /dev/null
@@ -1,144 +0,0 @@
-from twisted.trial import unittest
-
-from scrapy.http import Request
-
-from scrapy.contrib_exp.crawlspider.reqproc import Canonicalize
-from scrapy.contrib_exp.crawlspider.reqproc import FilterDomain
-from scrapy.contrib_exp.crawlspider.reqproc import FilterUrl
-from scrapy.contrib_exp.crawlspider.reqproc import FilterDupes
-
-import copy
-
-class RequestProcessorsTest(unittest.TestCase):
-
- def test_canonicalize_requests(self):
- urls = [
- 'http://example.com/do?&b=1&a=2&c=3',
- 'http://example.com/do?123,&q=a space',
- ]
- urls_after = [
- 'http://example.com/do?a=2&b=1&c=3',
- 'http://example.com/do?123%2C=&q=a+space',
- ]
-
- proc = Canonicalize()
- results = [req.url for req in proc(Request(url) for url in urls)]
- self.failUnlessEquals(results, urls_after)
-
- def test_unique_requests(self):
- urls = [
- 'http://example.com/sample1.html',
- 'http://example.com/sample2.html',
- 'http://example.com/sample3.html',
- 'http://example.com/sample1.html',
- 'http://example.com/sample2.html',
- ]
- urls_unique = [
- 'http://example.com/sample1.html',
- 'http://example.com/sample2.html',
- 'http://example.com/sample3.html',
- ]
-
- proc = FilterDupes()
- results = [req.url for req in proc(Request(url) for url in urls)]
- self.failUnlessEquals(results, urls_unique)
-
- # Check custom attributes
- requests = [
- Request('http://example.com', method='GET'),
- Request('http://example.com', method='POST'),
- ]
- proc = FilterDupes('url', 'method')
- self.failUnlessEqual(len(list(proc(requests))), 2)
-
- proc = FilterDupes('url')
- self.failUnlessEqual(len(list(proc(requests))), 1)
-
- def test_filter_domain(self):
- urls = [
- 'http://blah1.com/index',
- 'http://blah2.com/index',
- 'http://blah1.com/section',
- 'http://blah2.com/section',
- ]
-
- proc = FilterDomain(allow=('blah1.com'), deny=('blah2.com'))
- filtered = [req.url for req in proc(Request(url) for url in urls)]
- self.failUnlessEquals(filtered, [
- 'http://blah1.com/index',
- 'http://blah1.com/section',
- ])
-
- proc = FilterDomain(deny=('blah1.com', 'blah2.com'))
- filtered = [req.url for req in proc(Request(url) for url in urls)]
- self.failUnlessEquals(filtered, [])
-
- proc = FilterDomain(allow=('blah1.com', 'blah2.com'))
- filtered = [req.url for req in proc(Request(url) for url in urls)]
- self.failUnlessEquals(filtered, urls)
-
- def test_filter_url(self):
- urls = [
- 'http://blah1.com/index',
- 'http://blah2.com/index',
- 'http://blah1.com/section',
- 'http://blah2.com/section',
- ]
-
- proc = FilterUrl(allow=(r'blah1'), deny=(r'blah2'))
- filtered = [req.url for req in proc(Request(url) for url in urls)]
- self.failUnlessEquals(filtered, [
- 'http://blah1.com/index',
- 'http://blah1.com/section',
- ])
-
- proc = FilterUrl(deny=('blah1', 'blah2'))
- filtered = [req.url for req in proc(Request(url) for url in urls)]
- self.failUnlessEquals(filtered, [])
-
- proc = FilterUrl(allow=('index$', 'section$'))
- filtered = [req.url for req in proc(Request(url) for url in urls)]
- self.failUnlessEquals(filtered, urls)
-
-
-
- def test_all_processors(self):
- urls = [
- 'http://example.com/sample1.html',
- 'http://example.com/sample2.html',
- 'http://example.com/sample3.html',
- 'http://example.com/sample1.html',
- 'http://example.com/sample2.html',
- 'http://example.com/do?&b=1&a=2&c=3',
- 'http://example.com/do?123,&q=a space',
- ]
- urls_processed = [
- 'http://example.com/sample1.html',
- 'http://example.com/sample2.html',
- 'http://example.com/sample3.html',
- 'http://example.com/do?a=2&b=1&c=3',
- 'http://example.com/do?123%2C=&q=a+space',
- ]
-
- processors = [
- Canonicalize(),
- FilterDupes(),
- ]
-
- def _process(requests):
- """Apply all processors"""
- # copy list
- processed = [copy.copy(req) for req in requests]
- for proc in processors:
- processed = proc(processed)
- return processed
-
- # empty requests
- results1 = [r.url for r in _process([])]
- self.failUnlessEquals(results1, [])
-
- # try urls
- requests = (Request(url) for url in urls)
- results2 = [r.url for r in _process(requests)]
- self.failUnlessEquals(results2, urls_processed)
-
diff --git a/scrapy/tests/test_contrib_exp_crawlspider_rules.py b/scrapy/tests/test_contrib_exp_crawlspider_rules.py
deleted file mode 100644
index e04eb7b06..000000000
--- a/scrapy/tests/test_contrib_exp_crawlspider_rules.py
+++ /dev/null
@@ -1,262 +0,0 @@
-from twisted.trial import unittest
-
-from scrapy.http import HtmlResponse
-from scrapy.spider import BaseSpider
-from scrapy.contrib_exp.crawlspider.matchers import BaseMatcher
-from scrapy.contrib_exp.crawlspider.matchers import UrlMatcher
-from scrapy.contrib_exp.crawlspider.matchers import UrlRegexMatcher
-
-from scrapy.contrib_exp.crawlspider.rules import CompiledRule
-from scrapy.contrib_exp.crawlspider.rules import Rule
-from scrapy.contrib_exp.crawlspider.rules import RulesManager
-
-from functools import partial
-
-class RuleInitializationTest(unittest.TestCase):
-
- def test_fail_if_rule_null(self):
- # fail on empty rule
- self.failUnlessRaises(ValueError, Rule)
- self.failUnlessRaises(ValueError, Rule,
- **dict(callback=None, follow=None))
- self.failUnlessRaises(ValueError, Rule,
- **dict(callback=None, follow=False))
-
- def test_minimal_arguments_to_instantiation(self):
- # not fail if callback set
- self.failUnless(Rule(callback=lambda: True))
- # not fail if follow set
- self.failUnless(Rule(follow=True))
-
- def test_validate_default_attributes(self):
- # test null Rule
- rule = Rule(follow=True)
- self.failUnlessEqual(None, rule.matcher)
- self.failUnlessEqual(None, rule.callback)
- self.failUnlessEqual({}, rule.cb_kwargs)
- # follow default False
- self.failUnlessEqual(True, rule.follow)
-
- def test_validate_attributes_set(self):
- matcher = BaseMatcher()
- callback = lambda: True
- rule = Rule(matcher, callback, True, a=1)
- # test attributes
- self.failUnlessEqual(matcher, rule.matcher)
- self.failUnlessEqual(callback, rule.callback)
- self.failUnlessEqual({'a': 1}, rule.cb_kwargs)
- self.failUnlessEqual(True, rule.follow)
-
-class CompiledRuleInitializationTest(unittest.TestCase):
-
- def test_fail_on_invalid_matcher(self):
- # pass with valid matcher
- self.failUnless(CompiledRule(BaseMatcher()),
- "Failed CompiledRule instantiation")
-
- # at least needs valid matcher
- self.assertRaises(AssertionError, CompiledRule, None)
- self.assertRaises(AssertionError, CompiledRule, False)
- self.assertRaises(AssertionError, CompiledRule, True)
-
- def test_fail_on_invalid_callback(self):
- # pass with valid callback
- callback = lambda: True
- self.failUnless(CompiledRule(BaseMatcher(), callback))
- # pass with callback none
- self.failUnless(CompiledRule(BaseMatcher(), None))
-
- # assert on invalid callback
- self.assertRaises(AssertionError, CompiledRule, BaseMatcher(),
- 'myfunc')
-
- # numeric variable
- var = 123
- self.assertRaises(AssertionError, CompiledRule, BaseMatcher(),
- var)
-
- class A:
- pass
-
- # random instance
- self.assertRaises(AssertionError, CompiledRule, BaseMatcher(),
- A())
-
-
- def test_fail_on_invalid_follow_value(self):
- callback = lambda: True
- matcher = BaseMatcher()
- # pass bool
- self.failUnless(CompiledRule(matcher, callback, True))
- self.failUnless(CompiledRule(matcher, callback, False))
-
- # assert with non-bool
- self.assertRaises(AssertionError, CompiledRule, matcher,
- callback, None)
- self.assertRaises(AssertionError, CompiledRule, matcher,
- callback, 1)
-
- def test_validate_default_attributes(self):
- callback = lambda: True
- matcher = BaseMatcher()
- rule = CompiledRule(matcher, callback, True)
-
- # test attributes
- self.failUnlessEqual(matcher, rule.matcher)
- self.failUnlessEqual(callback, rule.callback)
- self.failUnlessEqual(True, rule.follow)
-
-
-class RulesTest(unittest.TestCase):
- def test_rules_manager_basic(self):
- spider = BaseSpider('foo')
- response1 = HtmlResponse('http://example.org')
- response2 = HtmlResponse('http://othersite.org')
- rulesman = RulesManager([], spider)
-
- # should return none
- self.failIf(rulesman.get_rule_from_response(response1))
- self.failIf(rulesman.get_rule_from_response(response2))
-
- # rules manager with match-all rule
- rulesman = RulesManager([
- Rule(BaseMatcher(), follow=True),
- ], spider)
-
- # returns CompiledRule
- rule1 = rulesman.get_rule_from_response(response1)
- rule2 = rulesman.get_rule_from_response(response2)
-
- self.failUnless(isinstance(rule1, CompiledRule))
- self.failUnless(isinstance(rule2, CompiledRule))
- self.assert_(rule1 is rule2)
- self.failUnlessEqual(rule1.callback, None)
- self.failUnlessEqual(rule1.follow, True)
-
- def test_rules_manager_empty_rule(self):
- spider = BaseSpider('foo')
- response = HtmlResponse('http://example.org')
-
- rulesman = RulesManager([Rule(follow=True)], spider)
-
- rule = rulesman.get_rule_from_response(response)
- # default matcher if None: BaseMatcher
- self.failUnless(isinstance(rule.matcher, BaseMatcher))
-
- def test_rules_manager_default_matcher(self):
- spider = BaseSpider('foo')
- response = HtmlResponse('http://example.org')
- callback = lambda x: None
-
- rulesman = RulesManager([
- Rule('http://example.org', callback),
- ], spider, default_matcher=UrlMatcher)
-
- rule = rulesman.get_rule_from_response(response)
- self.failUnless(isinstance(rule.matcher, UrlMatcher))
-
- def test_rules_manager_matchers(self):
- spider = BaseSpider('foo')
- response1 = HtmlResponse('http://example.org')
- response2 = HtmlResponse('http://othersite.org')
-
- urlmatcher = UrlMatcher('http://example.org')
- basematcher = BaseMatcher()
- # callback needed for Rule
- callback = lambda x: None
-
- # test fail matcher resolve
- self.assertRaises(ValueError, RulesManager,
- [Rule(False, callback)], spider)
- self.assertRaises(ValueError, RulesManager,
- [Rule(spider, callback)], spider)
-
- rulesman = RulesManager([
- Rule(urlmatcher, callback),
- Rule(basematcher, callback),
- ], spider)
-
- # response1 matches example.org
- rule1 = rulesman.get_rule_from_response(response1)
- # response2 is catch by BaseMatcher()
- rule2 = rulesman.get_rule_from_response(response2)
-
- self.failUnlessEqual(rule1.matcher, urlmatcher)
- self.failUnlessEqual(rule2.matcher, basematcher)
-
- # reverse order. BaseMatcher should match all
- rulesman = RulesManager([
- Rule(basematcher, callback),
- Rule(urlmatcher, callback),
- ], spider)
-
- rule1 = rulesman.get_rule_from_response(response1)
- rule2 = rulesman.get_rule_from_response(response2)
-
- self.failUnlessEqual(rule1.matcher, basematcher)
- self.failUnlessEqual(rule2.matcher, basematcher)
- self.failUnless(rule1 is rule2)
-
- def test_rules_manager_callbacks(self):
- mycallback = lambda: True
-
- spider = BaseSpider('foo')
- spider.parse_item = lambda: True
-
- response1 = HtmlResponse('http://example.org')
- response2 = HtmlResponse('http://othersite.org')
-
- rulesman = RulesManager([
- Rule('example', mycallback),
- Rule('othersite', 'parse_item'),
- ], spider, default_matcher=UrlRegexMatcher)
-
- rule1 = rulesman.get_rule_from_response(response1)
- rule2 = rulesman.get_rule_from_response(response2)
-
- self.failUnlessEqual(rule1.callback, mycallback)
- self.failUnlessEqual(rule2.callback, spider.parse_item)
-
- # fail unknown callback
- self.assertRaises(AttributeError, RulesManager, [
- Rule(BaseMatcher(), 'mycallback')
- ], spider)
- # fail not callable
- spider.not_callable = True
- self.assertRaises(AttributeError, RulesManager, [
- Rule(BaseMatcher(), 'not_callable')
- ], spider)
-
-
- def test_rules_manager_callback_with_arguments(self):
- spider = BaseSpider('foo')
- response = HtmlResponse('http://example.org')
-
- kwargs = {'a': 1}
-
- def myfunc(**mykwargs):
- return mykwargs
-
- # verify return validation
- self.failUnlessEquals(kwargs, myfunc(**kwargs))
-
- # test callback w/o arguments
- rulesman = RulesManager([
- Rule(BaseMatcher(), myfunc),
- ], spider)
- rule = rulesman.get_rule_from_response(response)
-
- # without arguments should return same callback
- self.failUnlessEqual(rule.callback, myfunc)
-
- # test callback w/ arguments
- rulesman = RulesManager([
- Rule(BaseMatcher(), myfunc, **kwargs),
- ], spider)
- rule = rulesman.get_rule_from_response(response)
-
- # with argument should return partial applied callback
- self.failUnless(isinstance(rule.callback, partial))
- self.failUnlessEquals(kwargs, rule.callback())
-
-
diff --git a/scrapy/tests/test_contrib_exp_crawlspider_spider.py b/scrapy/tests/test_contrib_exp_crawlspider_spider.py
deleted file mode 100644
index 21f7f71e4..000000000
--- a/scrapy/tests/test_contrib_exp_crawlspider_spider.py
+++ /dev/null
@@ -1,222 +0,0 @@
-from twisted.trial import unittest
-
-from scrapy.http import Request
-from scrapy.http import HtmlResponse
-from scrapy.item import BaseItem
-from scrapy.utils.spider import iterate_spider_output
-
-# basics
-from scrapy.contrib_exp.crawlspider import CrawlSpider
-from scrapy.contrib_exp.crawlspider import Rule
-
-# matchers
-from scrapy.contrib_exp.crawlspider.matchers import BaseMatcher
-from scrapy.contrib_exp.crawlspider.matchers import UrlRegexMatcher
-from scrapy.contrib_exp.crawlspider.matchers import UrlListMatcher
-
-# extractors
-from scrapy.contrib_exp.crawlspider.reqext import SgmlRequestExtractor
-
-# processors
-from scrapy.contrib_exp.crawlspider.reqproc import Canonicalize
-from scrapy.contrib_exp.crawlspider.reqproc import FilterDupes
-
-
-# mock items
-class Item1(BaseItem):
- pass
-
-class Item2(BaseItem):
- pass
-
-class Item3(BaseItem):
- pass
-
-
-class CrawlSpiderTest(unittest.TestCase):
-
- def spider_factory(self, rules=[],
- extractors=[], processors=[],
- start_urls=[]):
- # mock spider
- class Spider(CrawlSpider):
- def parse_item1(self, response):
- return Item1()
-
- def parse_item2(self, response):
- return Item2()
-
- def parse_item3(self, response):
- return Item3()
-
- def parse_request1(self, response):
- return Request('http://example.org/request1')
-
- def parse_request2(self, response):
- return Request('http://example.org/request2')
-
- Spider.start_urls = start_urls
- Spider.rules = rules
- Spider.request_extractors = extractors
- Spider.request_processors = processors
-
- return Spider('foo')
-
- def test_start_url_auto_rule(self):
- spider = self.spider_factory()
- # zero spider rules
- self.failUnlessEqual(len(spider.rules), 0)
- self.failUnlessEqual(len(spider._rulesman._rules), 0)
-
- spider = self.spider_factory(start_urls=['http://example.org'])
-
- self.failUnlessEqual(len(spider.rules), 0)
- self.failUnlessEqual(len(spider._rulesman._rules), 1)
-
- def test_start_url_matcher(self):
- url = 'http://example.org'
- spider = self.spider_factory(start_urls=[url])
-
- response = HtmlResponse(url)
-
- rule = spider._rulesman.get_rule_from_response(response)
- self.failUnless(isinstance(rule.matcher, UrlListMatcher))
-
- response = HtmlResponse(url + '/item.html')
-
- rule = spider._rulesman.get_rule_from_response(response)
- self.failUnless(rule is None)
-
- # TODO: remove this block
- # in previous version get_rule returns rule from response.request
- response.request = Request(url)
- rule = spider._rulesman.get_rule_from_response(response.request)
- self.failUnless(isinstance(rule.matcher, UrlListMatcher))
- self.failUnlessEqual(rule.follow, True)
-
- def test_parse_callback(self):
- response = HtmlResponse('http://example.org')
- rules = (
- Rule(BaseMatcher(), 'parse_item1'),
- )
- spider = self.spider_factory(rules)
-
- result = list(spider.parse(response))
- self.failUnlessEqual(len(result), 1)
- self.failUnless(isinstance(result[0], Item1))
-
- def test_crawling_start_url(self):
- url = 'http://example.org/'
- html = """Page title
- Item 12
- About us
-
- Other category
-
"""
- response = HtmlResponse(url, body=html)
-
- extractors = (SgmlRequestExtractor(), )
- spider = self.spider_factory(start_urls=[url],
- extractors=extractors)
- result = list(spider.parse(response))
-
- # 1 request extracted: example.org/
- # because requests returns only matching
- self.failUnlessEqual(len(result), 1)
-
- # we will add catch-all rule to extract all
- callback = lambda x: None
- rules = [Rule(r'\.html$', callback=callback)]
- spider = self.spider_factory(rules, start_urls=[url],
- extractors=extractors)
- result = list(spider.parse(response))
-
- # 4 requests extracted
- # 3 of .html pattern
- # 1 of start url patter
- self.failUnlessEqual(len(result), 4)
-
- def test_crawling_simple_rule(self):
- url = 'http://example.org/somepage/index.html'
- html = """Page title
- Item 12
- About us
-
- Other category
-
"""
-
- response = HtmlResponse(url, body=html)
-
- rules = (
- # first response callback
- Rule(r'index\.html', 'parse_item1'),
- )
- spider = self.spider_factory(rules)
- result = list(spider.parse(response))
-
- # should return Item1
- self.failUnlessEqual(len(result), 1)
- self.failUnless(isinstance(result[0], Item1))
-
- # test request generation
- rules = (
- # first response without callback and follow flag
- Rule(r'index\.html', follow=True),
- Rule(r'(\.html|/)$', 'parse_item1'),
- )
- spider = self.spider_factory(rules)
- result = list(spider.parse(response))
-
- # 0 because spider does not have extractors
- self.failUnlessEqual(len(result), 0)
-
- extractors = (SgmlRequestExtractor(), )
-
- # instance spider with extractor
- spider = self.spider_factory(rules, extractors)
- result = list(spider.parse(response))
- # 4 requests extracted
- self.failUnlessEqual(len(result), 4)
-
- def test_crawling_multiple_rules(self):
- html = """Page title
- Item 12
- About us
-
- Other category
-
"""
-
- response = HtmlResponse('http://example.org/index.html', body=html)
- response1 = HtmlResponse('http://example.org/1.html')
- response2 = HtmlResponse('http://example.org/othercat.html')
-
- rules = (
- Rule(r'\d+\.html$', 'parse_item1'),
- Rule(r'othercat\.html$', 'parse_item2'),
- # follow-only rules
- Rule(r'index\.html', 'parse_item3', follow=True)
- )
- extractors = [SgmlRequestExtractor()]
- spider = self.spider_factory(rules, extractors)
-
- result = list(spider.parse(response))
- # 1 Item 2 Requests
- self.failUnlessEqual(len(result), 3)
- # parse_item3
- self.failUnless(isinstance(result[0], Item3))
- only_requests = lambda r: isinstance(r, Request)
- requests = filter(only_requests, result[1:])
- self.failUnlessEqual(len(requests), 2)
- self.failUnless(all(requests))
-
- result1 = list(spider.parse(response1))
- # parse_item1
- self.failUnlessEqual(len(result1), 1)
- self.failUnless(isinstance(result1[0], Item1))
-
- result2 = list(spider.parse(response2))
- # parse_item2
- self.failUnlessEqual(len(result2), 1)
- self.failUnless(isinstance(result2[0], Item2))
-
-
diff --git a/scrapy/tests/test_contrib_exporter.py b/scrapy/tests/test_contrib_exporter.py
index 8b776f587..974174c42 100644
--- a/scrapy/tests/test_contrib_exporter.py
+++ b/scrapy/tests/test_contrib_exporter.py
@@ -127,6 +127,18 @@ class CsvItemExporterTest(BaseItemExporterTest):
ie.finish_exporting()
self.assertEqual(output.getvalue(), '22,John\xc2\xa3\r\n')
+ def test_join_multivalue(self):
+ class TestItem2(Item):
+ name = Field()
+ friends = Field()
+
+ i = TestItem2(name='John', friends=['Mary', 'Paul'])
+ output = StringIO()
+ ie = CsvItemExporter(output, include_headers_line=False)
+ ie.start_exporting()
+ ie.export_item(i)
+ ie.finish_exporting()
+ self.assertEqual(output.getvalue(), '"Mary,Paul",John\r\n')
class XmlItemExporterTest(BaseItemExporterTest):
diff --git a/scrapy/tests/test_contrib_feedexport.py b/scrapy/tests/test_contrib_feedexport.py
index fa3977533..5e07b3f14 100644
--- a/scrapy/tests/test_contrib_feedexport.py
+++ b/scrapy/tests/test_contrib_feedexport.py
@@ -1,13 +1,13 @@
import os, urlparse
+from cStringIO import StringIO
from zope.interface.verify import verifyObject
from twisted.trial import unittest
from twisted.internet import defer
-from cStringIO import StringIO
+from w3lib.url import path_to_file_uri
from scrapy.spider import BaseSpider
from scrapy.contrib.feedexport import IFeedStorage, FileFeedStorage, FTPFeedStorage, S3FeedStorage, StdoutFeedStorage
-from scrapy.utils.url import path_to_file_uri
from scrapy.utils.test import assert_aws_environ
class FeedStorageTest(unittest.TestCase):
diff --git a/scrapy/tests/test_contrib_ibl/__init__.py b/scrapy/tests/test_contrib_ibl/__init__.py
deleted file mode 100644
index f5fa69d7a..000000000
--- a/scrapy/tests/test_contrib_ibl/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-import sys
-path = sys.modules[__name__].__path__[0]
diff --git a/scrapy/tests/test_contrib_ibl/samples/samples_htmlpage_0.html b/scrapy/tests/test_contrib_ibl/samples/samples_htmlpage_0.html
deleted file mode 100644
index f0d980b5d..000000000
--- a/scrapy/tests/test_contrib_ibl/samples/samples_htmlpage_0.html
+++ /dev/null
@@ -1,190 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-retrosixty - Charlotte Perriand Infraphil lamp, c1960s for Philips, Netherlands
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Lighting..
-
- Please click the thumbnails for larger
- images and the back button to return to the Lighting index.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Designer :
-
-
- Charlotte Perriand
- Manufacturer:
-
- Philips, Netherlands
-
- Description:
-
-
-
- A Perriand designed 'infraphil' infrared heat lamp
- designed in c1960s. This example is in good vintage
- condition with some minor wear as one would expect.
- Original Philips sticker intact, although it has some
- wear as pictured.
-
-
- As with all electrical items we always
- recommend having them tested by a professional prior to
- use although it is in full working order. The lamp can
- be used as a table lamp, or mounted on the wall - full
- adjustable ...
- Price: £60
- Size:
-
- N/A
-
-
- Shipping:
-
- £7 to mainland UK .
- Please enquire for other locations.
- Ref #: 0642
-
-
-
-
-
-
-
-
- << BACK
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Site Layout, Design &
- Content Copyright 2006-09 - retrosixty.co.uk
-
-
-
-
-
\ No newline at end of file
diff --git a/scrapy/tests/test_contrib_ibl/samples/samples_htmlpage_0.json b/scrapy/tests/test_contrib_ibl/samples/samples_htmlpage_0.json
deleted file mode 100644
index 08826aa69..000000000
--- a/scrapy/tests/test_contrib_ibl/samples/samples_htmlpage_0.json
+++ /dev/null
@@ -1,3099 +0,0 @@
-[
- {
- "attributes": {},
- "tag": "head",
- "end": 6,
- "start": 0,
- "tag_type": 1
- },
- {
- "start": 6,
- "end": 11
- },
- {
- "attributes": {
- "content": "text/html; charset=utf-8",
- "http-equiv": "Content-Type"
- },
- "tag": "meta",
- "end": 78,
- "start": 11,
- "tag_type": 1
- },
- {
- "start": 78,
- "end": 79
- },
- {
- "attributes": {
- "content": "Site Layout, Design & Content Copyright 2005 - retrosixty.co.uk",
- "name": "Copyright"
- },
- "tag": "meta",
- "end": 180,
- "start": 79,
- "tag_type": 1
- },
- {
- "start": 180,
- "end": 181
- },
- {
- "attributes": {
- "content": "EN",
- "http-equiv": "content-language"
- },
- "tag": "meta",
- "end": 230,
- "start": 181,
- "tag_type": 1
- },
- {
- "start": 230,
- "end": 231
- },
- {
- "attributes": {
- "content": "Max Williams",
- "name": "Designer"
- },
- "tag": "meta",
- "end": 276,
- "start": 231,
- "tag_type": 1
- },
- {
- "start": 276,
- "end": 277
- },
- {
- "attributes": {
- "content": "retrosixty, retro sixty, retro, furniture, retro furniture, lighting ,retro lighting, art, retro art, ceramics, retro ceramics, technology, retro technology, fifties, sixties, seventies, 20th century design, post-war, post-war decorative, retro accessories",
- "name": "Keywords"
- },
- "tag": "meta",
- "end": 566,
- "start": 277,
- "tag_type": 1
- },
- {
- "start": 566,
- "end": 567
- },
- {
- "attributes": {
- "content": "retrosixty - retrosixty.co.uk",
- "name": "Title"
- },
- "tag": "meta",
- "end": 626,
- "start": 567,
- "tag_type": 1
- },
- {
- "start": 626,
- "end": 627
- },
- {
- "attributes": {
- "content": "7",
- "name": "revisit-after"
- },
- "tag": "meta",
- "end": 666,
- "start": 627,
- "tag_type": 1
- },
- {
- "start": 666,
- "end": 667
- },
- {
- "attributes": {
- "content": "index,follow",
- "name": "Robots"
- },
- "tag": "meta",
- "end": 710,
- "start": 667,
- "tag_type": 1
- },
- {
- "start": 710,
- "end": 711
- },
- {
- "attributes": {
- "content": "Dealers of retro furniture, post-war decorative and fine arts.",
- "name": "Description"
- },
- "tag": "meta",
- "end": 809,
- "start": 711,
- "tag_type": 1
- },
- {
- "start": 809,
- "end": 810
- },
- {
- "attributes": {
- "content": "no-cache",
- "http-equiv": "Cache-Control"
- },
- "tag": "meta",
- "end": 862,
- "start": 810,
- "tag_type": 1
- },
- {
- "start": 862,
- "end": 863
- },
- {
- "attributes": {
- "content": "0",
- "http-equiv": "Expires"
- },
- "tag": "meta",
- "end": 902,
- "start": 863,
- "tag_type": 1
- },
- {
- "start": 902,
- "end": 903
- },
- {
- "attributes": {
- "content": "Nick Waters",
- "name": "Author"
- },
- "tag": "meta",
- "end": 945,
- "start": 903,
- "tag_type": 1
- },
- {
- "start": 945,
- "end": 947
- },
- {
- "attributes": {},
- "tag": "title",
- "end": 954,
- "start": 947,
- "tag_type": 1
- },
- {
- "start": 954,
- "end": 1033
- },
- {
- "attributes": {},
- "tag": "title",
- "end": 1041,
- "start": 1033,
- "tag_type": 2
- },
- {
- "start": 1041,
- "end": 1043
- },
- {
- "attributes": {
- "language": "JavaScript"
- },
- "tag": "script",
- "end": 1073,
- "start": 1043,
- "tag_type": 1
- },
- {
- "start": 1073,
- "end": 1074
- },
- {
- "start": 1074,
- "end": 2052
- },
- {
- "start": 2052,
- "end": 2053
- },
- {
- "attributes": {},
- "tag": "script",
- "end": 2062,
- "start": 2053,
- "tag_type": 2
- },
- {
- "start": 2062,
- "end": 2064
- },
- {
- "attributes": {
- "fprolloverstyle": null
- },
- "tag": "style",
- "end": 2090,
- "start": 2064,
- "tag_type": 1
- },
- {
- "start": 2090,
- "end": 2154
- },
- {
- "attributes": {},
- "tag": "style",
- "end": 2162,
- "start": 2154,
- "tag_type": 2
- },
- {
- "start": 2162,
- "end": 2164
- },
- {
- "attributes": {
- "type": "text/css",
- "id": "mydeco-style"
- },
- "tag": "style",
- "end": 2205,
- "start": 2164,
- "tag_type": 1
- },
- {
- "start": 2205,
- "end": 2265
- },
- {
- "attributes": {},
- "tag": "style",
- "end": 2273,
- "start": 2265,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "head",
- "end": 2280,
- "start": 2273,
- "tag_type": 2
- },
- {
- "attributes": {
- "onload": null,
- "bottommargin": "0",
- "topmargin": "0",
- "rightmargin": "0",
- "alink": "#000000",
- "bgcolor": "#c0c0c0",
- "link": "#000000",
- "vlink": "#000000",
- "leftmargin": "0"
- },
- "tag": "body",
- "end": 2423,
- "start": 2280,
- "tag_type": 1
- },
- {
- "start": 2423,
- "end": 2425
- },
- {
- "attributes": {
- "align": "center",
- "class": "mydeco-selected"
- },
- "tag": "div",
- "end": 2469,
- "start": 2425,
- "tag_type": 1
- },
- {
- "start": 2469,
- "end": 2471
- },
- {
- "attributes": {
- "bgcolor": "#ffffff",
- "border": "0",
- "height": "100%",
- "width": "765",
- "cellpadding": "0",
- "cellspacing": "0",
- "id": "table1"
- },
- "tag": "table",
- "end": 2577,
- "start": 2471,
- "tag_type": 1
- },
- {
- "start": 2577,
- "end": 2580
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 2587,
- "start": 2580,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 2591,
- "start": 2587,
- "tag_type": 1
- },
- {
- "start": 2591,
- "end": 2595
- },
- {
- "attributes": {
- "colspan": "3",
- "style": "border-left: 1px solid rgb(0, 0, 0); border-right: 1px solid rgb(0, 0, 0);",
- "align": "center",
- "height": "120"
- },
- "tag": "td",
- "end": 2722,
- "start": 2595,
- "tag_type": 1
- },
- {
- "start": 2722,
- "end": 2726
- },
- {
- "attributes": {
- "align": "center"
- },
- "tag": "p",
- "end": 2744,
- "start": 2726,
- "tag_type": 1
- },
- {
- "start": 2744,
- "end": 2748
- },
- {
- "attributes": {
- "src": "../images/logo.jpg",
- "alt": "retrosixty",
- "border": "0",
- "width": "745",
- "height": "102"
- },
- "tag": "img",
- "end": 2831,
- "start": 2748,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 2835,
- "start": 2831,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 2840,
- "start": 2835,
- "tag_type": 2
- },
- {
- "start": 2840,
- "end": 2843
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 2848,
- "start": 2843,
- "tag_type": 2
- },
- {
- "start": 2848,
- "end": 2851
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 2855,
- "start": 2851,
- "tag_type": 1
- },
- {
- "start": 2855,
- "end": 2859
- },
- {
- "attributes": {
- "width": "177",
- "style": "border-left: 1px solid rgb(0, 0, 0);",
- "height": "20"
- },
- "tag": "td",
- "end": 2932,
- "start": 2859,
- "tag_type": 1
- },
- {
- "start": 2932,
- "end": 2936
- },
- {
- "attributes": {
- "style": "margin-left: 10px;"
- },
- "tag": "p",
- "end": 2966,
- "start": 2936,
- "tag_type": 1
- },
- {
- "start": 2966,
- "end": 2970
- },
- {
- "attributes": {
- "src": "../images/top.gif",
- "alt": "retrosixty",
- "border": "0",
- "width": "160",
- "height": "20"
- },
- "tag": "img",
- "end": 3051,
- "start": 2970,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 3055,
- "start": 3051,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 3060,
- "start": 3055,
- "tag_type": 2
- },
- {
- "start": 3060,
- "end": 3064
- },
- {
- "attributes": {
- "colspan": "2",
- "style": "border-right: 1px solid rgb(0, 0, 0);",
- "width": "586",
- "height": "20"
- },
- "tag": "td",
- "end": 3150,
- "start": 3064,
- "tag_type": 1
- },
- {
- "start": 3150,
- "end": 3160
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 3165,
- "start": 3160,
- "tag_type": 2
- },
- {
- "start": 3165,
- "end": 3168
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 3173,
- "start": 3168,
- "tag_type": 2
- },
- {
- "start": 3173,
- "end": 3176
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 3180,
- "start": 3176,
- "tag_type": 1
- },
- {
- "start": 3180,
- "end": 3184
- },
- {
- "attributes": {
- "width": "180",
- "style": "border-left: 1px solid rgb(0, 0, 0);",
- "background": "../images/bg.gif",
- "valign": "top"
- },
- "tag": "td",
- "end": 3288,
- "start": 3184,
- "tag_type": 1
- },
- {
- "start": 3288,
- "end": 3292
- },
- {
- "attributes": {
- "style": "margin-top: 0pt; margin-bottom: 0pt;",
- "align": "center"
- },
- "tag": "p",
- "end": 3355,
- "start": 3292,
- "tag_type": 1
- },
- {
- "start": 3355,
- "end": 3359
- },
- {
- "attributes": {
- "href": "../index.html"
- },
- "tag": "a",
- "end": 3383,
- "start": 3359,
- "tag_type": 1
- },
- {
- "start": 3383,
- "end": 3387
- },
- {
- "attributes": {
- "src": "../buttons/button3.jpg",
- "onmouseout": null,
- "fp-title": "Home",
- "height": "31",
- "width": "125",
- "onmouseover": null,
- "alt": "Home",
- "border": "0",
- "id": "img31",
- "fp-style": "fp-btn: Linked Column 9; fp-font-style: Bold; fp-img-press: 0; fp-bgcolor: #7B7B7B; fp-proportional: 0"
- },
- "tag": "img",
- "end": 3637,
- "start": 3387,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 3641,
- "start": 3637,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 3645,
- "start": 3641,
- "tag_type": 2
- },
- {
- "attributes": {
- "style": "margin-top: 0pt; margin-bottom: 0pt;",
- "align": "center"
- },
- "tag": "p",
- "end": 3708,
- "start": 3645,
- "tag_type": 1
- },
- {
- "start": 3708,
- "end": 3712
- },
- {
- "attributes": {
- "href": "../about.html"
- },
- "tag": "a",
- "end": 3736,
- "start": 3712,
- "tag_type": 1
- },
- {
- "start": 3736,
- "end": 3740
- },
- {
- "attributes": {
- "src": "../buttons/button32.jpg",
- "onmouseout": null,
- "fp-title": "About Us",
- "height": "31",
- "width": "125",
- "onmouseover": null,
- "alt": "About Us",
- "border": "0",
- "id": "img42",
- "fp-style": "fp-btn: Linked Column 9; fp-font-style: Bold; fp-img-press: 0; fp-bgcolor: #7B7B7B; fp-proportional: 0"
- },
- "tag": "img",
- "end": 3999,
- "start": 3740,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 4003,
- "start": 3999,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 4007,
- "start": 4003,
- "tag_type": 2
- },
- {
- "attributes": {
- "style": "margin-top: 0pt; margin-bottom: 0pt;",
- "align": "center"
- },
- "tag": "p",
- "end": 4070,
- "start": 4007,
- "tag_type": 1
- },
- {
- "start": 4070,
- "end": 4074
- },
- {
- "attributes": {
- "href": "../shipping.html"
- },
- "tag": "a",
- "end": 4101,
- "start": 4074,
- "tag_type": 1
- },
- {
- "start": 4101,
- "end": 4105
- },
- {
- "attributes": {
- "src": "../buttons/button34.jpg",
- "onmouseout": null,
- "fp-title": "Shipping",
- "height": "31",
- "width": "125",
- "onmouseover": null,
- "alt": "Shipping",
- "border": "0",
- "id": "img43",
- "fp-style": "fp-btn: Linked Column 9; fp-font-style: Bold; fp-img-press: 0; fp-bgcolor: #7B7B7B; fp-proportional: 0"
- },
- "tag": "img",
- "end": 4364,
- "start": 4105,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 4368,
- "start": 4364,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 4372,
- "start": 4368,
- "tag_type": 2
- },
- {
- "attributes": {
- "style": "margin-top: 0pt; margin-bottom: 0pt;",
- "align": "center"
- },
- "tag": "p",
- "end": 4435,
- "start": 4372,
- "tag_type": 1
- },
- {
- "start": 4435,
- "end": 4439
- },
- {
- "attributes": {
- "href": "../links.html"
- },
- "tag": "a",
- "end": 4463,
- "start": 4439,
- "tag_type": 1
- },
- {
- "start": 4463,
- "end": 4467
- },
- {
- "attributes": {
- "src": "../buttons/button1.jpg",
- "onmouseout": null,
- "fp-title": "Links",
- "height": "31",
- "width": "125",
- "onmouseover": null,
- "alt": "Links",
- "border": "0",
- "id": "img45",
- "fp-style": "fp-btn: Linked Column 9; fp-font-style: Bold; fp-img-press: 0; fp-bgcolor: #7B7B7B; fp-proportional: 0; fp-orig: 0"
- },
- "tag": "img",
- "end": 4731,
- "start": 4467,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 4735,
- "start": 4731,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 4739,
- "start": 4735,
- "tag_type": 2
- },
- {
- "attributes": {
- "style": "margin-top: 0pt; margin-bottom: 0pt;",
- "align": "center"
- },
- "tag": "p",
- "end": 4802,
- "start": 4739,
- "tag_type": 1
- },
- {
- "start": 4802,
- "end": 4806
- },
- {
- "attributes": {
- "href": "../contact.php"
- },
- "tag": "a",
- "end": 4831,
- "start": 4806,
- "tag_type": 1
- },
- {
- "start": 4831,
- "end": 4835
- },
- {
- "attributes": {
- "src": "../buttons/button36.jpg",
- "onmouseout": null,
- "fp-title": "Contact",
- "height": "31",
- "width": "125",
- "onmouseover": null,
- "alt": "Contact",
- "border": "0",
- "id": "img44",
- "fp-style": "fp-btn: Linked Column 9; fp-font-style: Bold; fp-img-press: 0; fp-bgcolor: #7B7B7B; fp-proportional: 0"
- },
- "tag": "img",
- "end": 5092,
- "start": 4835,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 5096,
- "start": 5092,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 5100,
- "start": 5096,
- "tag_type": 2
- },
- {
- "attributes": {
- "style": "margin-top: 0pt; margin-bottom: 0pt;",
- "align": "center"
- },
- "tag": "p",
- "end": 5163,
- "start": 5100,
- "tag_type": 1
- },
- {
- "start": 5163,
- "end": 5173
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 5177,
- "start": 5173,
- "tag_type": 2
- },
- {
- "attributes": {
- "style": "margin-top: 0pt; margin-bottom: 0pt;",
- "align": "center"
- },
- "tag": "p",
- "end": 5240,
- "start": 5177,
- "tag_type": 1
- },
- {
- "start": 5240,
- "end": 5244
- },
- {
- "attributes": {
- "href": "../furniture.html"
- },
- "tag": "a",
- "end": 5272,
- "start": 5244,
- "tag_type": 1
- },
- {
- "start": 5272,
- "end": 5276
- },
- {
- "attributes": {
- "src": "../buttons/buttonB.jpg",
- "onmouseout": null,
- "fp-title": "Furniture",
- "height": "31",
- "width": "125",
- "onmouseover": null,
- "alt": "Furniture",
- "border": "0",
- "id": "img33",
- "fp-style": "fp-btn: Linked Column 9; fp-img-press: 0; fp-bgcolor: #7B7B7B; fp-proportional: 0"
- },
- "tag": "img",
- "end": 5515,
- "start": 5276,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 5519,
- "start": 5515,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 5523,
- "start": 5519,
- "tag_type": 2
- },
- {
- "attributes": {
- "style": "margin-top: 0pt; margin-bottom: 0pt;",
- "align": "center"
- },
- "tag": "p",
- "end": 5586,
- "start": 5523,
- "tag_type": 1
- },
- {
- "start": 5586,
- "end": 5590
- },
- {
- "attributes": {
- "href": "../lighting.html"
- },
- "tag": "a",
- "end": 5617,
- "start": 5590,
- "tag_type": 1
- },
- {
- "start": 5617,
- "end": 5621
- },
- {
- "attributes": {
- "src": "../buttons/buttonD.jpg",
- "onmouseout": null,
- "fp-title": "Lighting",
- "height": "31",
- "width": "125",
- "onmouseover": null,
- "alt": "Lighting",
- "border": "0",
- "id": "img34",
- "fp-style": "fp-btn: Linked Column 9; fp-img-press: 0; fp-bgcolor: #7B7B7B; fp-proportional: 0"
- },
- "tag": "img",
- "end": 5858,
- "start": 5621,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 5862,
- "start": 5858,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 5866,
- "start": 5862,
- "tag_type": 2
- },
- {
- "attributes": {
- "style": "margin-top: 0pt; margin-bottom: 0pt;",
- "align": "center"
- },
- "tag": "p",
- "end": 5929,
- "start": 5866,
- "tag_type": 1
- },
- {
- "start": 5929,
- "end": 5933
- },
- {
- "attributes": {
- "href": "../tech.html"
- },
- "tag": "a",
- "end": 5956,
- "start": 5933,
- "tag_type": 1
- },
- {
- "start": 5956,
- "end": 5960
- },
- {
- "attributes": {
- "src": "../buttons/buttonF.jpg",
- "onmouseout": null,
- "fp-title": "Technology",
- "height": "31",
- "width": "125",
- "onmouseover": null,
- "alt": "Technology",
- "border": "0",
- "id": "img35",
- "fp-style": "fp-btn: Linked Column 9; fp-img-press: 0; fp-bgcolor: #7B7B7B; fp-proportional: 0"
- },
- "tag": "img",
- "end": 6201,
- "start": 5960,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 6205,
- "start": 6201,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 6209,
- "start": 6205,
- "tag_type": 2
- },
- {
- "attributes": {
- "style": "margin-top: 0pt; margin-bottom: 0pt;",
- "align": "center"
- },
- "tag": "p",
- "end": 6272,
- "start": 6209,
- "tag_type": 1
- },
- {
- "start": 6272,
- "end": 6276
- },
- {
- "attributes": {
- "href": "../ceramics.html"
- },
- "tag": "a",
- "end": 6303,
- "start": 6276,
- "tag_type": 1
- },
- {
- "start": 6303,
- "end": 6307
- },
- {
- "attributes": {
- "src": "../buttons/button11.jpg",
- "onmouseout": null,
- "fp-title": "Ceramics",
- "height": "31",
- "width": "125",
- "onmouseover": null,
- "alt": "Ceramics",
- "border": "0",
- "id": "img36",
- "fp-style": "fp-btn: Linked Column 9; fp-img-press: 0; fp-bgcolor: #7B7B7B; fp-proportional: 0"
- },
- "tag": "img",
- "end": 6545,
- "start": 6307,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 6549,
- "start": 6545,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 6553,
- "start": 6549,
- "tag_type": 2
- },
- {
- "attributes": {
- "style": "margin-top: 0pt; margin-bottom: 0pt;",
- "align": "center"
- },
- "tag": "p",
- "end": 6616,
- "start": 6553,
- "tag_type": 1
- },
- {
- "start": 6616,
- "end": 6620
- },
- {
- "attributes": {
- "href": "../art.html"
- },
- "tag": "a",
- "end": 6642,
- "start": 6620,
- "tag_type": 1
- },
- {
- "start": 6642,
- "end": 6646
- },
- {
- "attributes": {
- "src": "../buttons/button13.jpg",
- "onmouseout": null,
- "fp-title": "Art",
- "height": "31",
- "width": "125",
- "onmouseover": null,
- "alt": "Art",
- "border": "0",
- "id": "img37",
- "fp-style": "fp-btn: Linked Column 9; fp-img-press: 0; fp-bgcolor: #7B7B7B; fp-proportional: 0"
- },
- "tag": "img",
- "end": 6874,
- "start": 6646,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 6878,
- "start": 6874,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 6882,
- "start": 6878,
- "tag_type": 2
- },
- {
- "attributes": {
- "style": "margin-top: 0pt; margin-bottom: 0pt;",
- "align": "center"
- },
- "tag": "p",
- "end": 6945,
- "start": 6882,
- "tag_type": 1
- },
- {
- "start": 6945,
- "end": 6949
- },
- {
- "attributes": {
- "href": "../misc.html"
- },
- "tag": "a",
- "end": 6972,
- "start": 6949,
- "tag_type": 1
- },
- {
- "start": 6972,
- "end": 6976
- },
- {
- "attributes": {
- "src": "../buttons/button15.jpg",
- "onmouseout": null,
- "fp-title": "Misc. Items",
- "height": "31",
- "width": "125",
- "onmouseover": null,
- "alt": "Misc. Items",
- "border": "0",
- "id": "img38",
- "fp-style": "fp-btn: Linked Column 9; fp-img-press: 0; fp-bgcolor: #7B7B7B; fp-proportional: 0"
- },
- "tag": "img",
- "end": 7220,
- "start": 6976,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 7224,
- "start": 7220,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 7228,
- "start": 7224,
- "tag_type": 2
- },
- {
- "attributes": {
- "style": "margin-top: 0pt; margin-bottom: 0pt;",
- "align": "center"
- },
- "tag": "p",
- "end": 7291,
- "start": 7228,
- "tag_type": 1
- },
- {
- "start": 7291,
- "end": 7295
- },
- {
- "attributes": {
- "href": "../contemp.html"
- },
- "tag": "a",
- "end": 7321,
- "start": 7295,
- "tag_type": 1
- },
- {
- "start": 7321,
- "end": 7325
- },
- {
- "attributes": {
- "src": "../buttons/button17.jpg",
- "onmouseout": null,
- "fp-title": "Contemporary",
- "height": "31",
- "width": "125",
- "onmouseover": null,
- "alt": "Contemporary",
- "border": "0",
- "id": "img46",
- "fp-style": "fp-btn: Linked Column 9; fp-img-press: 0; fp-bgcolor: #7B7B7B; fp-proportional: 0; fp-orig: 0"
- },
- "tag": "img",
- "end": 7583,
- "start": 7325,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 7587,
- "start": 7583,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 7591,
- "start": 7587,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 7596,
- "start": 7591,
- "tag_type": 2
- },
- {
- "start": 7596,
- "end": 7600
- },
- {
- "attributes": {
- "width": "433",
- "class": null,
- "valign": "top"
- },
- "tag": "td",
- "end": 7638,
- "start": 7600,
- "tag_type": 1
- },
- {
- "start": 7638,
- "end": 7642
- },
- {
- "attributes": {
- "style": "margin-left: 10px; margin-right: 20px;"
- },
- "tag": "p",
- "end": 7692,
- "start": 7642,
- "tag_type": 1
- },
- {
- "start": 7692,
- "end": 7706
- },
- {
- "attributes": {
- "style": "font-weight: 700;"
- },
- "tag": "span",
- "end": 7738,
- "start": 7706,
- "tag_type": 1
- },
- {
- "attributes": {
- "data-scrapy-annotate": "{"variant": 0, "annotations": {"content": "name"}}",
- "size": "5",
- "id": "anonymous_element_1",
- "face": "Tahoma"
- },
- "tag": "font",
- "end": 7906,
- "start": 7738,
- "tag_type": 1
- },
- {
- "start": 7906,
- "end": 7929
- },
- {
- "attributes": {},
- "tag": "font",
- "end": 7936,
- "start": 7929,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 7943,
- "start": 7936,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 7947,
- "start": 7943,
- "tag_type": 2
- },
- {
- "start": 7947,
- "end": 7951
- },
- {
- "attributes": {
- "style": "margin-left: 10px; margin-right: 20px; margin-bottom: 15px;",
- "align": "justify"
- },
- "tag": "p",
- "end": 8038,
- "start": 7951,
- "tag_type": 1
- },
- {
- "start": 8038,
- "end": 8042
- },
- {
- "attributes": {
- "size": "2",
- "class": null,
- "face": "Tahoma"
- },
- "tag": "font",
- "end": 8080,
- "start": 8042,
- "tag_type": 1
- },
- {
- "start": 8080,
- "end": 8191
- },
- {
- "attributes": {},
- "tag": "font",
- "end": 8198,
- "start": 8191,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 8202,
- "start": 8198,
- "tag_type": 2
- },
- {
- "attributes": {
- "align": "center",
- "class": null
- },
- "tag": "div",
- "end": 8231,
- "start": 8202,
- "tag_type": 1
- },
- {
- "start": 8231,
- "end": 8236
- },
- {
- "attributes": {
- "border": "0",
- "height": "309",
- "width": "400",
- "cellpadding": "0",
- "cellspacing": "0",
- "id": "table2"
- },
- "tag": "table",
- "end": 8323,
- "start": 8236,
- "tag_type": 1
- },
- {
- "start": 8323,
- "end": 8329
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 8336,
- "start": 8329,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 8340,
- "start": 8336,
- "tag_type": 1
- },
- {
- "start": 8340,
- "end": 8347
- },
- {
- "attributes": {
- "width": "130",
- "style": "border-top: 1px solid rgb(123, 123, 123); border-bottom: 1px solid rgb(123, 123, 123);",
- "height": "309"
- },
- "tag": "td",
- "end": 8471,
- "start": 8347,
- "tag_type": 1
- },
- {
- "start": 8471,
- "end": 8478
- },
- {
- "attributes": {
- "align": "center"
- },
- "tag": "p",
- "end": 8496,
- "start": 8478,
- "tag_type": 1
- },
- {
- "start": 8496,
- "end": 8509
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 8513,
- "start": 8509,
- "tag_type": 2
- },
- {
- "attributes": {
- "align": "center",
- "class": null
- },
- "tag": "p",
- "end": 8540,
- "start": 8513,
- "tag_type": 1
- },
- {
- "start": 8540,
- "end": 8547
- },
- {
- "attributes": {
- "href": "../photos/0642-01.JPG",
- "target": "_blank"
- },
- "tag": "a",
- "end": 8595,
- "start": 8547,
- "tag_type": 1
- },
- {
- "start": 8595,
- "end": 8602
- },
- {
- "attributes": {
- "src": "../photos/0642-01_small.jpg",
- "data-scrapy-annotate": "{"variant": 0, "annotations": {"src": "image_urls"}}",
- "border": "1",
- "id": "anonymous_element_2"
- },
- "tag": "img",
- "end": 8793,
- "start": 8602,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 8797,
- "start": 8793,
- "tag_type": 2
- },
- {
- "start": 8797,
- "end": 8817
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 8821,
- "start": 8817,
- "tag_type": 2
- },
- {
- "attributes": {
- "align": "center"
- },
- "tag": "p",
- "end": 8839,
- "start": 8821,
- "tag_type": 1
- },
- {
- "start": 8839,
- "end": 8846
- },
- {
- "attributes": {
- "href": "../photos/0642-02.JPG",
- "target": "_blank"
- },
- "tag": "a",
- "end": 8894,
- "start": 8846,
- "tag_type": 1
- },
- {
- "start": 8894,
- "end": 8901
- },
- {
- "attributes": {
- "src": "../photos/0642-02_small.jpg",
- "border": "1"
- },
- "tag": "img",
- "end": 8951,
- "start": 8901,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 8955,
- "start": 8951,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 8959,
- "start": 8955,
- "tag_type": 2
- },
- {
- "attributes": {
- "align": "center"
- },
- "tag": "p",
- "end": 8977,
- "start": 8959,
- "tag_type": 1
- },
- {
- "start": 8977,
- "end": 8984
- },
- {
- "attributes": {
- "href": "../photos/0642-03.JPG",
- "target": "_blank"
- },
- "tag": "a",
- "end": 9032,
- "start": 8984,
- "tag_type": 1
- },
- {
- "start": 9032,
- "end": 9039
- },
- {
- "attributes": {
- "src": "../photos/0642-03_small.jpg",
- "border": "1"
- },
- "tag": "img",
- "end": 9089,
- "start": 9039,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 9093,
- "start": 9089,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 9097,
- "start": 9093,
- "tag_type": 2
- },
- {
- "attributes": {
- "align": "center"
- },
- "tag": "p",
- "end": 9115,
- "start": 9097,
- "tag_type": 1
- },
- {
- "start": 9115,
- "end": 9122
- },
- {
- "attributes": {
- "href": "../photos/0642-04.JPG",
- "target": "_blank"
- },
- "tag": "a",
- "end": 9170,
- "start": 9122,
- "tag_type": 1
- },
- {
- "start": 9170,
- "end": 9177
- },
- {
- "attributes": {
- "src": "../photos/0642-04_small.jpg",
- "border": "1"
- },
- "tag": "img",
- "end": 9227,
- "start": 9177,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 9231,
- "start": 9227,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 9235,
- "start": 9231,
- "tag_type": 2
- },
- {
- "attributes": {
- "align": "center"
- },
- "tag": "p",
- "end": 9253,
- "start": 9235,
- "tag_type": 1
- },
- {
- "start": 9253,
- "end": 9266
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 9270,
- "start": 9266,
- "tag_type": 2
- },
- {
- "attributes": {
- "align": "center"
- },
- "tag": "p",
- "end": 9288,
- "start": 9270,
- "tag_type": 1
- },
- {
- "start": 9288,
- "end": 9301
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 9305,
- "start": 9301,
- "tag_type": 2
- },
- {
- "attributes": {
- "align": "center"
- },
- "tag": "p",
- "end": 9323,
- "start": 9305,
- "tag_type": 1
- },
- {
- "start": 9323,
- "end": 9336
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 9340,
- "start": 9336,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 9345,
- "start": 9340,
- "tag_type": 2
- },
- {
- "start": 9345,
- "end": 9352
- },
- {
- "attributes": {
- "class": null,
- "align": "left",
- "valign": "top",
- "style": "border-top: 1px solid rgb(123, 123, 123); border-bottom: 1px solid rgb(123, 123, 123);",
- "height": "309"
- },
- "tag": "td",
- "end": 9499,
- "start": 9352,
- "tag_type": 1
- },
- {
- "start": 9499,
- "end": 9506
- },
- {
- "attributes": {
- "style": "margin-left: 15px; margin-top: 25px; margin-bottom: -10px;"
- },
- "tag": "p",
- "end": 9576,
- "start": 9506,
- "tag_type": 1
- },
- {
- "start": 9576,
- "end": 9596
- },
- {
- "attributes": {},
- "tag": "b",
- "end": 9599,
- "start": 9596,
- "tag_type": 1
- },
- {
- "attributes": {
- "size": "2",
- "face": "Tahoma"
- },
- "tag": "font",
- "end": 9628,
- "start": 9599,
- "tag_type": 1
- },
- {
- "start": 9628,
- "end": 9636
- },
- {
- "attributes": {},
- "tag": "font",
- "end": 9643,
- "start": 9636,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "b",
- "end": 9647,
- "start": 9643,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "b",
- "end": 9650,
- "start": 9647,
- "tag_type": 1
- },
- {
- "attributes": {
- "size": "2",
- "face": "Tahoma"
- },
- "tag": "font",
- "end": 9679,
- "start": 9650,
- "tag_type": 1
- },
- {
- "start": 9679,
- "end": 9687
- },
- {
- "attributes": {},
- "tag": "font",
- "end": 9694,
- "start": 9687,
- "tag_type": 2
- },
- {
- "start": 9694,
- "end": 9700
- },
- {
- "attributes": {},
- "tag": "b",
- "end": 9704,
- "start": 9700,
- "tag_type": 2
- },
- {
- "start": 9704,
- "end": 9710
- },
- {
- "attributes": {
- "size": "2",
- "face": "Tahoma,sans-serif"
- },
- "tag": "font",
- "end": 9750,
- "start": 9710,
- "tag_type": 1
- },
- {
- "start": 9750,
- "end": 9768
- },
- {
- "attributes": {},
- "tag": "font",
- "end": 9775,
- "start": 9768,
- "tag_type": 2
- },
- {
- "attributes": {
- "style": "font-size: 10pt; font-family: Tahoma,sans-serif;"
- },
- "tag": "span",
- "end": 9838,
- "start": 9775,
- "tag_type": 1
- },
- {
- "start": 9838,
- "end": 9863
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 9870,
- "start": 9863,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 9874,
- "start": 9870,
- "tag_type": 2
- },
- {
- "attributes": {
- "style": "margin-left: 15px; margin-top: 25px; margin-bottom: -10px;"
- },
- "tag": "p",
- "end": 9944,
- "start": 9874,
- "tag_type": 1
- },
- {
- "start": 9944,
- "end": 9964
- },
- {
- "attributes": {
- "size": "2",
- "face": "Tahoma"
- },
- "tag": "font",
- "end": 9993,
- "start": 9964,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "b",
- "end": 9996,
- "start": 9993,
- "tag_type": 1
- },
- {
- "start": 9996,
- "end": 10010
- },
- {
- "attributes": {},
- "tag": "b",
- "end": 10014,
- "start": 10010,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "font",
- "end": 10021,
- "start": 10014,
- "tag_type": 2
- },
- {
- "start": 10021,
- "end": 10027
- },
- {
- "attributes": {
- "size": "2"
- },
- "tag": "font",
- "end": 10042,
- "start": 10027,
- "tag_type": 1
- },
- {
- "attributes": {
- "style": "font-family: Tahoma,sans-serif;"
- },
- "tag": "span",
- "end": 10088,
- "start": 10042,
- "tag_type": 1
- },
- {
- "start": 10088,
- "end": 10114
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 10121,
- "start": 10114,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "font",
- "end": 10128,
- "start": 10121,
- "tag_type": 2
- },
- {
- "attributes": {
- "style": "font-size: 10pt; font-family: Tahoma,sans-serif;"
- },
- "tag": "span",
- "end": 10191,
- "start": 10128,
- "tag_type": 1
- },
- {
- "start": 10191,
- "end": 10204
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 10211,
- "start": 10204,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 10215,
- "start": 10211,
- "tag_type": 2
- },
- {
- "attributes": {
- "style": "margin-left: 15px; margin-top: 25px; margin-bottom: -10px;"
- },
- "tag": "p",
- "end": 10285,
- "start": 10215,
- "tag_type": 1
- },
- {
- "attributes": {
- "size": "2",
- "face": "Tahoma"
- },
- "tag": "font",
- "end": 10314,
- "start": 10285,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "b",
- "end": 10317,
- "start": 10314,
- "tag_type": 1
- },
- {
- "start": 10317,
- "end": 10406
- },
- {
- "attributes": {},
- "tag": "b",
- "end": 10410,
- "start": 10406,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "font",
- "end": 10417,
- "start": 10410,
- "tag_type": 2
- },
- {
- "start": 10417,
- "end": 10424
- },
- {
- "attributes": {
- "style": "font-size: 10pt; font-family: Tahoma,sans-serif;"
- },
- "tag": "span",
- "end": 10487,
- "start": 10424,
- "tag_type": 1
- },
- {
- "start": 10487,
- "end": 10749
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 10756,
- "start": 10749,
- "tag_type": 2
- },
- {
- "start": 10756,
- "end": 10763
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 10767,
- "start": 10763,
- "tag_type": 2
- },
- {
- "attributes": {
- "style": "margin-left: 15px; margin-top: 25px; margin-bottom: -10px;",
- "class": null
- },
- "tag": "p",
- "end": 10846,
- "start": 10767,
- "tag_type": 1
- },
- {
- "start": 10846,
- "end": 10853
- },
- {
- "attributes": {
- "style": "font-size: 10pt; font-family: Tahoma,sans-serif;",
- "class": null
- },
- "tag": "span",
- "end": 10925,
- "start": 10853,
- "tag_type": 1
- },
- {
- "start": 10925,
- "end": 11175
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 11182,
- "start": 11175,
- "tag_type": 2
- },
- {
- "attributes": {
- "size": "2",
- "face": "Tahoma"
- },
- "tag": "font",
- "end": 11211,
- "start": 11182,
- "tag_type": 1
- },
- {
- "start": 11211,
- "end": 11214
- },
- {
- "attributes": {},
- "tag": "font",
- "end": 11221,
- "start": 11214,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 11225,
- "start": 11221,
- "tag_type": 2
- },
- {
- "attributes": {
- "style": "margin-left: 15px; margin-top: 25px; margin-bottom: -10px;",
- "class": null
- },
- "tag": "p",
- "end": 11304,
- "start": 11225,
- "tag_type": 1
- },
- {
- "start": 11304,
- "end": 11324
- },
- {
- "attributes": {
- "data-scrapy-annotate": "{"variant": 0, "annotations": {"content": "price"}}",
- "size": "2",
- "id": "anonymous_element_3",
- "face": "Tahoma"
- },
- "tag": "font",
- "end": 11493,
- "start": 11324,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "b",
- "end": 11496,
- "start": 11493,
- "tag_type": 1
- },
- {
- "start": 11496,
- "end": 11502
- },
- {
- "attributes": {},
- "tag": "b",
- "end": 11506,
- "start": 11502,
- "tag_type": 2
- },
- {
- "start": 11506,
- "end": 11515
- },
- {
- "attributes": {},
- "tag": "font",
- "end": 11522,
- "start": 11515,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 11526,
- "start": 11522,
- "tag_type": 2
- },
- {
- "attributes": {
- "style": "margin-left: 15px; margin-top: 25px; margin-bottom: -10px;"
- },
- "tag": "p",
- "end": 11596,
- "start": 11526,
- "tag_type": 1
- },
- {
- "start": 11596,
- "end": 11616
- },
- {
- "attributes": {
- "size": "2",
- "face": "Tahoma"
- },
- "tag": "font",
- "end": 11645,
- "start": 11616,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "b",
- "end": 11648,
- "start": 11645,
- "tag_type": 1
- },
- {
- "start": 11648,
- "end": 11653
- },
- {
- "attributes": {},
- "tag": "b",
- "end": 11657,
- "start": 11653,
- "tag_type": 2
- },
- {
- "start": 11657,
- "end": 11658
- },
- {
- "attributes": {},
- "tag": "font",
- "end": 11665,
- "start": 11658,
- "tag_type": 2
- },
- {
- "start": 11665,
- "end": 11671
- },
- {
- "attributes": {
- "size": "2"
- },
- "tag": "font",
- "end": 11686,
- "start": 11671,
- "tag_type": 1
- },
- {
- "attributes": {
- "style": "font-family: Tahoma,sans-serif;"
- },
- "tag": "span",
- "end": 11732,
- "start": 11686,
- "tag_type": 1
- },
- {
- "start": 11732,
- "end": 11741
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 11748,
- "start": 11741,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "font",
- "end": 11755,
- "start": 11748,
- "tag_type": 2
- },
- {
- "attributes": {
- "style": "font-size: 10pt; font-family: Tahoma,sans-serif;"
- },
- "tag": "span",
- "end": 11818,
- "start": 11755,
- "tag_type": 1
- },
- {
- "start": 11818,
- "end": 11824
- },
- {
- "attributes": {
- "class": "auctionblock"
- },
- "tag": "span",
- "end": 11851,
- "start": 11824,
- "tag_type": 1
- },
- {
- "start": 11851,
- "end": 11857
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 11864,
- "start": 11857,
- "tag_type": 2
- },
- {
- "start": 11864,
- "end": 11882
- },
- {
- "attributes": {
- "class": "auctionblock"
- },
- "tag": "span",
- "end": 11909,
- "start": 11882,
- "tag_type": 1
- },
- {
- "start": 11909,
- "end": 11915
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 11922,
- "start": 11915,
- "tag_type": 2
- },
- {
- "start": 11922,
- "end": 11935
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 11942,
- "start": 11935,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 11946,
- "start": 11942,
- "tag_type": 2
- },
- {
- "attributes": {
- "style": "margin-left: 15px; margin-top: 25px; margin-bottom: -10px;"
- },
- "tag": "p",
- "end": 12016,
- "start": 11946,
- "tag_type": 1
- },
- {
- "start": 12016,
- "end": 12036
- },
- {
- "attributes": {
- "size": "2",
- "face": "Tahoma"
- },
- "tag": "font",
- "end": 12065,
- "start": 12036,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "b",
- "end": 12068,
- "start": 12065,
- "tag_type": 1
- },
- {
- "start": 12068,
- "end": 12077
- },
- {
- "attributes": {},
- "tag": "b",
- "end": 12081,
- "start": 12077,
- "tag_type": 2
- },
- {
- "start": 12081,
- "end": 12082
- },
- {
- "attributes": {},
- "tag": "font",
- "end": 12089,
- "start": 12082,
- "tag_type": 2
- },
- {
- "start": 12089,
- "end": 12095
- },
- {
- "attributes": {
- "style": "font-size: 10pt; font-family: Tahoma,sans-serif;"
- },
- "tag": "span",
- "end": 12158,
- "start": 12095,
- "tag_type": 1
- },
- {
- "start": 12158,
- "end": 12181
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 12188,
- "start": 12181,
- "tag_type": 2
- },
- {
- "attributes": {
- "size": "2",
- "face": "Tahoma"
- },
- "tag": "font",
- "end": 12217,
- "start": 12188,
- "tag_type": 1
- },
- {
- "start": 12217,
- "end": 12260
- },
- {
- "attributes": {},
- "tag": "font",
- "end": 12267,
- "start": 12260,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 12271,
- "start": 12267,
- "tag_type": 2
- },
- {
- "attributes": {
- "style": "margin-left: 15px; margin-top: 25px; margin-bottom: -10px;"
- },
- "tag": "p",
- "end": 12341,
- "start": 12271,
- "tag_type": 1
- },
- {
- "start": 12341,
- "end": 12361
- },
- {
- "attributes": {
- "size": "2",
- "face": "Tahoma"
- },
- "tag": "font",
- "end": 12390,
- "start": 12361,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "b",
- "end": 12393,
- "start": 12390,
- "tag_type": 1
- },
- {
- "start": 12393,
- "end": 12399
- },
- {
- "attributes": {},
- "tag": "b",
- "end": 12403,
- "start": 12399,
- "tag_type": 2
- },
- {
- "start": 12403,
- "end": 12408
- },
- {
- "attributes": {},
- "tag": "font",
- "end": 12415,
- "start": 12408,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 12419,
- "start": 12415,
- "tag_type": 2
- },
- {
- "attributes": {
- "style": "margin-left: 15px; margin-top: 25px; margin-bottom: -10px;"
- },
- "tag": "p",
- "end": 12489,
- "start": 12419,
- "tag_type": 1
- },
- {
- "start": 12489,
- "end": 12515
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 12519,
- "start": 12515,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 12524,
- "start": 12519,
- "tag_type": 2
- },
- {
- "start": 12524,
- "end": 12530
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 12535,
- "start": 12530,
- "tag_type": 2
- },
- {
- "start": 12535,
- "end": 12541
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 12549,
- "start": 12541,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "table",
- "end": 12557,
- "start": 12549,
- "tag_type": 2
- },
- {
- "start": 12557,
- "end": 12574
- },
- {
- "attributes": {
- "style": "margin-left: 25px; margin-top: 25px;"
- },
- "tag": "p",
- "end": 12622,
- "start": 12574,
- "tag_type": 1
- },
- {
- "start": 12622,
- "end": 12627
- },
- {
- "attributes": {
- "size": "2",
- "face": "Tahoma"
- },
- "tag": "font",
- "end": 12656,
- "start": 12627,
- "tag_type": 1
- },
- {
- "start": 12656,
- "end": 12661
- },
- {
- "attributes": {
- "style": "text-decoration: none;",
- "href": "about:blank"
- },
- "tag": "a",
- "end": 12714,
- "start": 12661,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "b",
- "end": 12717,
- "start": 12714,
- "tag_type": 1
- },
- {
- "start": 12717,
- "end": 12731
- },
- {
- "attributes": {},
- "tag": "b",
- "end": 12735,
- "start": 12731,
- "tag_type": 2
- },
- {
- "start": 12735,
- "end": 12739
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 12743,
- "start": 12739,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "font",
- "end": 12750,
- "start": 12743,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 12754,
- "start": 12750,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 12760,
- "start": 12754,
- "tag_type": 2
- },
- {
- "start": 12760,
- "end": 12764
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 12769,
- "start": 12764,
- "tag_type": 2
- },
- {
- "start": 12769,
- "end": 12773
- },
- {
- "attributes": {
- "width": "153",
- "style": "border-right: 1px solid rgb(0, 0, 0);",
- "class": null,
- "valign": "top"
- },
- "tag": "td",
- "end": 12857,
- "start": 12773,
- "tag_type": 1
- },
- {
- "start": 12857,
- "end": 12861
- },
- {
- "attributes": {
- "style": "margin-right: 20px;",
- "align": "left"
- },
- "tag": "p",
- "end": 12905,
- "start": 12861,
- "tag_type": 1
- },
- {
- "start": 12905,
- "end": 12909
- },
- {
- "attributes": {
- "src": "../images/icon1.jpg",
- "height": "133",
- "width": "133",
- "alt": "retrosixty",
- "border": "0",
- "class": null
- },
- "tag": "img",
- "end": 13002,
- "start": 12909,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 13006,
- "start": 13002,
- "tag_type": 2
- },
- {
- "start": 13006,
- "end": 13010
- },
- {
- "attributes": {
- "style": "margin-right: 20px;"
- },
- "tag": "p",
- "end": 13041,
- "start": 13010,
- "tag_type": 1
- },
- {
- "start": 13041,
- "end": 13045
- },
- {
- "attributes": {
- "src": "../images/icon2.jpg",
- "height": "133",
- "width": "133",
- "alt": "retrosixty",
- "border": "0",
- "class": null
- },
- "tag": "img",
- "end": 13138,
- "start": 13045,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 13142,
- "start": 13138,
- "tag_type": 2
- },
- {
- "start": 13142,
- "end": 13146
- },
- {
- "attributes": {
- "style": "margin-right: 20px;"
- },
- "tag": "p",
- "end": 13177,
- "start": 13146,
- "tag_type": 1
- },
- {
- "start": 13177,
- "end": 13181
- },
- {
- "attributes": {
- "src": "../images/icon3.jpg",
- "height": "133",
- "width": "133",
- "alt": "retrosixty",
- "border": "0",
- "class": null
- },
- "tag": "img",
- "end": 13274,
- "start": 13181,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 13278,
- "start": 13274,
- "tag_type": 2
- },
- {
- "start": 13278,
- "end": 13282
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 13287,
- "start": 13282,
- "tag_type": 2
- },
- {
- "start": 13287,
- "end": 13290
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 13295,
- "start": 13290,
- "tag_type": 2
- },
- {
- "start": 13295,
- "end": 13298
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 13302,
- "start": 13298,
- "tag_type": 1
- },
- {
- "start": 13302,
- "end": 13306
- },
- {
- "attributes": {
- "width": "177",
- "style": "border-left: 1px solid rgb(0, 0, 0);",
- "height": "25"
- },
- "tag": "td",
- "end": 13379,
- "start": 13306,
- "tag_type": 1
- },
- {
- "start": 13379,
- "end": 13383
- },
- {
- "attributes": {
- "style": "margin-left: 10px; margin-bottom: 10px;"
- },
- "tag": "p",
- "end": 13434,
- "start": 13383,
- "tag_type": 1
- },
- {
- "start": 13434,
- "end": 13438
- },
- {
- "attributes": {
- "src": "../images/bottom.gif",
- "alt": "retrosixty",
- "border": "0",
- "width": "160",
- "height": "25"
- },
- "tag": "img",
- "end": 13522,
- "start": 13438,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 13526,
- "start": 13522,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 13531,
- "start": 13526,
- "tag_type": 2
- },
- {
- "start": 13531,
- "end": 13535
- },
- {
- "attributes": {
- "colspan": "2",
- "style": "border-right: 1px solid rgb(0, 0, 0);",
- "width": "586",
- "height": "25"
- },
- "tag": "td",
- "end": 13621,
- "start": 13535,
- "tag_type": 1
- },
- {
- "start": 13621,
- "end": 13625
- },
- {
- "attributes": {
- "style": "margin-right: 15px;",
- "align": "right"
- },
- "tag": "p",
- "end": 13670,
- "start": 13625,
- "tag_type": 1
- },
- {
- "start": 13670,
- "end": 13674
- },
- {
- "attributes": {
- "style": "font-size: 8pt;",
- "face": "Tahoma"
- },
- "tag": "font",
- "end": 13718,
- "start": 13674,
- "tag_type": 1
- },
- {
- "start": 13718,
- "end": 13792
- },
- {
- "attributes": {},
- "tag": "font",
- "end": 13799,
- "start": 13792,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 13803,
- "start": 13799,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 13808,
- "start": 13803,
- "tag_type": 2
- },
- {
- "start": 13808,
- "end": 13811
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 13816,
- "start": 13811,
- "tag_type": 2
- },
- {
- "start": 13816,
- "end": 13818
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 13826,
- "start": 13818,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "table",
- "end": 13834,
- "start": 13826,
- "tag_type": 2
- },
- {
- "start": 13834,
- "end": 13835
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 13841,
- "start": 13835,
- "tag_type": 2
- },
- {
- "start": 13841,
- "end": 13843
- },
- {
- "attributes": {},
- "tag": "body",
- "end": 13850,
- "start": 13843,
- "tag_type": 2
- }
-]
diff --git a/scrapy/tests/test_contrib_ibl/samples/samples_htmlpage_1.html b/scrapy/tests/test_contrib_ibl/samples/samples_htmlpage_1.html
deleted file mode 100644
index f9cce9745..000000000
--- a/scrapy/tests/test_contrib_ibl/samples/samples_htmlpage_1.html
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Samsung Series 5 550 37" LE37B550 / HD 1080p / Freeview / LCD TV (Black)
( 1 customer rating )
RRP: £749.99 | You save: £170.00 (22%)
In stock | Usually dispatched within 24 hours
Half Price TV Stand Save 50% On This TV Stand When Purchased With This TV
Please be aware that this item will be delivered via a courier and will require a signature. Please contact customer service team with a daytime contact number. Screen Size: 37" Resolution: 1920 x 1080 Technology: CCFL Picture Engine: DNIe+ Dynamic Contrast Ratio: High Contrast Wide Colour Enhancer:WCE 2 1080 24p Real Movie Audio Sound Effect System: SRS Trusurround HD & Dolby Digital Plus Speaker Type: Down Firing Sound Output(RMS): 10W x 2 Features USB 2.0 Teletext(TTXT) Anynet+ (HDMI-CEC) Game mode User Interface OSD Language Sleep Timer Clock & On/Off Timer Auto Channel Search Auto Power Off EPG Auto Volume Leveller Hotel Mode(S/W) System DTV Type DTV Tuner Built-in Inputs / Outputs HDMI: back + side USB: side CI Slot: side Composite(AV): side Service: back PC input (D-sub): back PC Audio Input (Mini Jack): back DVI Audio Input (Mini Jack): back Component(Y/Pb/Pr): back Digital Audio (Optical): back Headphone: back RF Input: back Audio Out(L/R): back RS232C: back Scart: back Design Type: Samsung Crystal TV Colour: Platinum Black Swivel (Left/Right) Dimensions: Set Size(WXDXH) with Stand: 923 x 253 x 659.4 Set Size(WXDXH) without Stand: 923 x 78.5 x 597 Weight Set Weight with Stand: 19.4 Set weight without stand: 14.8 Accessory Vesa Wall Mount (WXH): Yes (32-40":200x200) Remote Controller Batteries Power Cable Average rating (1 review)
This TV is amazing - if you unlock some setting you can play Xvid, Dvix and MKV files through the TV (USB 2.0). The TV is well worth the money.
Related Items - Electronics
£334.99 Free Delivery RRP:£499.99 You save:£165.00
View All »
\ No newline at end of file
diff --git a/scrapy/tests/test_contrib_ibl/samples/samples_htmlpage_1.json b/scrapy/tests/test_contrib_ibl/samples/samples_htmlpage_1.json
deleted file mode 100644
index f94837c4d..000000000
--- a/scrapy/tests/test_contrib_ibl/samples/samples_htmlpage_1.json
+++ /dev/null
@@ -1,21968 +0,0 @@
-[
- {
- "attributes": {},
- "tag": "head",
- "end": 6,
- "tag_type": 1,
- "start": 0
- },
- {
- "attributes": {
- "id": "_pageTemplate__header__title"
- },
- "tag": "title",
- "end": 47,
- "tag_type": 1,
- "start": 6
- },
- {
- "start": 47,
- "end": 165
- },
- {
- "attributes": {},
- "tag": "title",
- "end": 173,
- "tag_type": 2,
- "start": 165
- },
- {
- "start": 173,
- "end": 174
- },
- {
- "attributes": {
- "content": "NOODP",
- "name": "ROBOTS"
- },
- "tag": "meta",
- "end": 210,
- "tag_type": 1,
- "start": 174
- },
- {
- "attributes": {
- "content": "no-cache",
- "http-equiv": "Pragma"
- },
- "tag": "meta",
- "end": 255,
- "tag_type": 1,
- "start": 210
- },
- {
- "attributes": {
- "content": "en-us",
- "http-equiv": "Content-Language"
- },
- "tag": "meta",
- "end": 307,
- "tag_type": 1,
- "start": 255
- },
- {
- "attributes": {
- "content": "Samsung Series 5 550 37" LE37B550 / HD 1080p / Freeview / LCD TV, electronics, dvd players, digital cameras, mobile phones, pc peripherals, buy, free delivery, uk, online, entertainment, shopping, shop, bargain, special offer",
- "id": "_pageTemplate__header__metaKeywords",
- "name": "keywords"
- },
- "tag": "meta",
- "end": 611,
- "tag_type": 1,
- "start": 307
- },
- {
- "attributes": {
- "content": "Play.com - Buy Samsung Series 5 550 37" LE37B550 / HD 1080p / Freeview / LCD TV, with free delivery to UK and Europe. Play.com is the top site for dvds, cds and games in the UK. We stock all major movies on DVD.",
- "id": "_pageTemplate__header__metaDescription",
- "name": "description"
- },
- "tag": "meta",
- "end": 909,
- "tag_type": 1,
- "start": 611
- },
- {
- "attributes": {
- "content": "text/html; charset=ISO-8859-1",
- "http-equiv": "Content-Type"
- },
- "tag": "meta",
- "end": 981,
- "tag_type": 1,
- "start": 909
- },
- {
- "attributes": {
- "href": "http://images.play.com/SiteCSS/Play/Live1/css/play.min.css",
- "type": "text/css",
- "id": "_pageTemplate__header__styleSheet",
- "rel": "stylesheet"
- },
- "tag": "link",
- "end": 1125,
- "tag_type": 1,
- "start": 981
- },
- {
- "attributes": {
- "href": "http://images.play.com/SiteCSS/Play/Live1/img/brand/favicon.ico",
- "rel": "icon"
- },
- "tag": "link",
- "end": 1213,
- "tag_type": 1,
- "start": 1125
- },
- {
- "attributes": {
- "href": "http://images.play.com/SiteCSS/Play/Live1/img/brand/favicon.ico",
- "rel": "shortcut icon"
- },
- "tag": "link",
- "end": 1310,
- "tag_type": 1,
- "start": 1213
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteScript/Play/Components/JavaScript/ChartsMenu.js",
- "type": "text/javascript",
- "language": "JavaScript"
- },
- "tag": "script",
- "end": 1444,
- "tag_type": 1,
- "start": 1310
- },
- {
- "attributes": {},
- "tag": "script",
- "end": 1453,
- "tag_type": 2,
- "start": 1444
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteScript/Play/Components/JavaScript/Other.js",
- "type": "text/javascript",
- "language": "JavaScript"
- },
- "tag": "script",
- "end": 1582,
- "tag_type": 1,
- "start": 1453
- },
- {
- "attributes": {},
- "tag": "script",
- "end": 1591,
- "tag_type": 2,
- "start": 1582
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteScript/Play/Components/JavaScript/Reloaded.js",
- "type": "text/javascript",
- "language": "JavaScript"
- },
- "tag": "script",
- "end": 1723,
- "tag_type": 1,
- "start": 1591
- },
- {
- "attributes": {},
- "tag": "script",
- "end": 1732,
- "tag_type": 2,
- "start": 1723
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteScript/Play/Components/JavaScript/cookieTools.js",
- "type": "text/javascript",
- "language": "JavaScript"
- },
- "tag": "script",
- "end": 1867,
- "tag_type": 1,
- "start": 1732
- },
- {
- "attributes": {},
- "tag": "script",
- "end": 1876,
- "tag_type": 2,
- "start": 1867
- },
- {
- "attributes": {
- "content": "6hM6+2zExVEjvWx8GYWXLAXLBAOfYdLvkK8mzEZLy6o=",
- "name": "verify-v1"
- },
- "tag": "meta",
- "end": 1954,
- "tag_type": 1,
- "start": 1876
- },
- {
- "start": 1954,
- "end": 1956
- },
- {
- "start": 1956,
- "end": 1979
- },
- {
- "start": 1979,
- "end": 1980
- },
- {
- "attributes": {
- "src": "http://images.play.com/sitetrak/cmdatatagutilsA.js",
- "type": "text/javascript",
- "language": "javascript1.1"
- },
- "tag": "script",
- "end": 2093,
- "tag_type": 1,
- "start": 1980
- },
- {
- "attributes": {},
- "tag": "script",
- "end": 2102,
- "tag_type": 2,
- "start": 2093
- },
- {
- "start": 2102,
- "end": 2103
- },
- {
- "attributes": {
- "src": "http://images.play.com/sitetrak/v40/eluminateA.js",
- "type": "text/javascript",
- "language": "javascript1.1"
- },
- "tag": "script",
- "end": 2215,
- "tag_type": 1,
- "start": 2103
- },
- {
- "attributes": {},
- "tag": "script",
- "end": 2224,
- "tag_type": 2,
- "start": 2215
- },
- {
- "start": 2224,
- "end": 2226
- },
- {
- "attributes": {
- "type": "text/javascript",
- "language": "javascript1.1"
- },
- "tag": "script",
- "end": 2282,
- "tag_type": 1,
- "start": 2226
- },
- {
- "start": 2282,
- "end": 2283
- },
- {
- "start": 2283,
- "end": 2437
- },
- {
- "start": 2437,
- "end": 2438
- },
- {
- "attributes": {},
- "tag": "script",
- "end": 2447,
- "tag_type": 2,
- "start": 2438
- },
- {
- "start": 2447,
- "end": 2451
- },
- {
- "attributes": {
- "type": "text/javascript"
- },
- "tag": "script",
- "end": 2482,
- "tag_type": 1,
- "start": 2451
- },
- {
- "start": 2482,
- "end": 2702
- },
- {
- "attributes": {},
- "tag": "script",
- "end": 2711,
- "tag_type": 2,
- "start": 2702
- },
- {
- "start": 2711,
- "end": 2712
- },
- {
- "attributes": {
- "type": "text/javascript"
- },
- "tag": "script",
- "end": 2743,
- "tag_type": 1,
- "start": 2712
- },
- {
- "start": 2743,
- "end": 2851
- },
- {
- "attributes": {},
- "tag": "script",
- "end": 2860,
- "tag_type": 2,
- "start": 2851
- },
- {
- "start": 2860,
- "end": 2861
- },
- {
- "start": 2861,
- "end": 2882
- },
- {
- "start": 2882,
- "end": 2884
- },
- {
- "attributes": {
- "type": "text/css",
- "id": "mydeco-style"
- },
- "tag": "style",
- "end": 2925,
- "tag_type": 1,
- "start": 2884
- },
- {
- "start": 2925,
- "end": 2985
- },
- {
- "attributes": {},
- "tag": "style",
- "end": 2993,
- "tag_type": 2,
- "start": 2985
- },
- {
- "attributes": {},
- "tag": "head",
- "end": 3000,
- "tag_type": 2,
- "start": 2993
- },
- {
- "attributes": {
- "id": "goto-top",
- "name": "goto-top",
- "class": "region-ELEC-404 greyBg goto-top"
- },
- "tag": "body",
- "end": 3076,
- "tag_type": 1,
- "start": 3000
- },
- {
- "start": 3076,
- "end": 3080
- },
- {
- "attributes": {
- "class": null,
- "id": "mainContainer"
- },
- "tag": "div",
- "end": 3113,
- "tag_type": 1,
- "start": 3080
- },
- {
- "start": 3113,
- "end": 3117
- },
- {
- "attributes": {
- "class": "header"
- },
- "tag": "div",
- "end": 3137,
- "tag_type": 1,
- "start": 3117
- },
- {
- "start": 3137,
- "end": 3141
- },
- {
- "attributes": {
- "class": "new_menu"
- },
- "tag": "div",
- "end": 3163,
- "tag_type": 1,
- "start": 3141
- },
- {
- "attributes": {
- "action": "https://www.play.com/OrdersPost.aspx",
- "class": "nomargin",
- "method": "post"
- },
- "tag": "form",
- "end": 3246,
- "tag_type": 1,
- "start": 3163
- },
- {
- "attributes": {
- "type": "hidden",
- "name": "transfer",
- "value": "transfer"
- },
- "tag": "input",
- "end": 3300,
- "tag_type": 1,
- "start": 3246
- },
- {
- "attributes": {
- "type": "hidden",
- "name": "returnURL",
- "value": "http://www.play.com/Product.aspx?searchtype=genre&r=ELEC&p=318&g=404&title=8986420&PRODUCT_TITLE=Samsung-Series-5-550-37-LE37B550-HD-1080p-Freeview-LCD-TV"
- },
- "tag": "input",
- "end": 3521,
- "tag_type": 1,
- "start": 3300
- },
- {
- "attributes": {
- "type": "hidden",
- "name": "hpcode",
- "value": null
- },
- "tag": "input",
- "end": 3565,
- "tag_type": 1,
- "start": 3521
- },
- {
- "attributes": {
- "type": "hidden",
- "name": "hpCardMessage",
- "value": "no"
- },
- "tag": "input",
- "end": 3618,
- "tag_type": 1,
- "start": 3565
- },
- {
- "attributes": {
- "type": "hidden",
- "name": "basketPromotionId",
- "value": null
- },
- "tag": "input",
- "end": 3673,
- "tag_type": 1,
- "start": 3618
- },
- {
- "attributes": {
- "type": "hidden",
- "name": "products",
- "value": null
- },
- "tag": "input",
- "end": 3719,
- "tag_type": 1,
- "start": 3673
- },
- {
- "attributes": {
- "type": "hidden",
- "name": "quantity",
- "value": null
- },
- "tag": "input",
- "end": 3765,
- "tag_type": 1,
- "start": 3719
- },
- {
- "attributes": {
- "type": "hidden",
- "name": "promoid",
- "value": null
- },
- "tag": "input",
- "end": 3810,
- "tag_type": 1,
- "start": 3765
- },
- {
- "attributes": {
- "type": "hidden",
- "name": "source",
- "value": "0"
- },
- "tag": "input",
- "end": 3855,
- "tag_type": 1,
- "start": 3810
- },
- {
- "attributes": {
- "type": "hidden",
- "name": "currency",
- "value": "257"
- },
- "tag": "input",
- "end": 3904,
- "tag_type": 1,
- "start": 3855
- },
- {
- "attributes": {
- "type": "hidden",
- "name": "regions",
- "value": null
- },
- "tag": "input",
- "end": 3949,
- "tag_type": 1,
- "start": 3904
- },
- {
- "attributes": {
- "type": "hidden",
- "name": "mpListings",
- "value": null
- },
- "tag": "input",
- "end": 3997,
- "tag_type": 1,
- "start": 3949
- },
- {
- "attributes": {
- "type": "hidden",
- "name": "sitecurrencies",
- "value": null
- },
- "tag": "input",
- "end": 4049,
- "tag_type": 1,
- "start": 3997
- },
- {
- "attributes": {
- "type": "hidden",
- "name": "applyPromotions",
- "value": null
- },
- "tag": "input",
- "end": 4102,
- "tag_type": 1,
- "start": 4049
- },
- {
- "attributes": {
- "type": "hidden",
- "name": "lispTypes",
- "value": null
- },
- "tag": "input",
- "end": 4149,
- "tag_type": 1,
- "start": 4102
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteCSS/Play/Live1/img/menu/my_account.gif",
- "name": "My Account",
- "type": "image",
- "alt": "My Account",
- "border": "0",
- "class": "my_account"
- },
- "tag": "input",
- "end": 4306,
- "tag_type": 1,
- "start": 4149
- },
- {
- "attributes": {},
- "tag": "form",
- "end": 4313,
- "tag_type": 2,
- "start": 4306
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 4319,
- "tag_type": 1,
- "start": 4313
- },
- {
- "start": 4319,
- "end": 4322
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 4329,
- "tag_type": 2,
- "start": 4322
- },
- {
- "attributes": {
- "href": "/HOME/HOME/6-/Help.html?page=helpdesk"
- },
- "tag": "a",
- "end": 4377,
- "tag_type": 1,
- "start": 4329
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteCSS/Play/Live1/img/menu/help_r.gif",
- "alt": "Help"
- },
- "tag": "img",
- "end": 4461,
- "tag_type": 1,
- "start": 4377
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 4465,
- "tag_type": 2,
- "start": 4461
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 4471,
- "tag_type": 2,
- "start": 4465
- },
- {
- "attributes": {
- "class": "currency_flags"
- },
- "tag": "div",
- "end": 4499,
- "tag_type": 1,
- "start": 4471
- },
- {
- "attributes": {
- "class": "gbp"
- },
- "tag": "div",
- "end": 4516,
- "tag_type": 1,
- "start": 4499
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 4519,
- "tag_type": 1,
- "start": 4516
- },
- {
- "start": 4519,
- "end": 4520
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 4524,
- "tag_type": 2,
- "start": 4520
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 4530,
- "tag_type": 2,
- "start": 4524
- },
- {
- "attributes": {
- "class": "gbp_active"
- },
- "tag": "div",
- "end": 4554,
- "tag_type": 1,
- "start": 4530
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/-/8986420/Samsung-Series-5-550-37-LE37B550-HD-1080p-Freeview-LCD-TV/Product.html?searchtype=genre&cur=257"
- },
- "tag": "a",
- "end": 4709,
- "tag_type": 1,
- "start": 4554
- },
- {
- "start": 4709,
- "end": 4715
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 4719,
- "tag_type": 2,
- "start": 4715
- },
- {
- "start": 4719,
- "end": 4720
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 4726,
- "tag_type": 2,
- "start": 4720
- },
- {
- "attributes": {
- "class": "euro"
- },
- "tag": "div",
- "end": 4744,
- "tag_type": 1,
- "start": 4726
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 4747,
- "tag_type": 1,
- "start": 4744
- },
- {
- "start": 4747,
- "end": 4748
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 4752,
- "tag_type": 2,
- "start": 4748
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 4758,
- "tag_type": 2,
- "start": 4752
- },
- {
- "attributes": {
- "class": "euro_inactive"
- },
- "tag": "div",
- "end": 4785,
- "tag_type": 1,
- "start": 4758
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/-/8986420/Samsung-Series-5-550-37-LE37B550-HD-1080p-Freeview-LCD-TV/Product.html?searchtype=genre&cur=258"
- },
- "tag": "a",
- "end": 4940,
- "tag_type": 1,
- "start": 4785
- },
- {
- "start": 4940,
- "end": 4945
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 4949,
- "tag_type": 2,
- "start": 4945
- },
- {
- "start": 4949,
- "end": 4950
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 4956,
- "tag_type": 2,
- "start": 4950
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 4962,
- "tag_type": 2,
- "start": 4956
- },
- {
- "attributes": {
- "class": "wide"
- },
- "tag": "div",
- "end": 4980,
- "tag_type": 1,
- "start": 4962
- },
- {
- "attributes": {
- "cellpadding": "0",
- "cellspacing": "0"
- },
- "tag": "table",
- "end": 5019,
- "tag_type": 1,
- "start": 4980
- },
- {
- "start": 5019,
- "end": 5023
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 5030,
- "tag_type": 1,
- "start": 5023
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 5034,
- "tag_type": 1,
- "start": 5030
- },
- {
- "start": 5034,
- "end": 5038
- },
- {
- "attributes": {
- "class": "head_l"
- },
- "tag": "td",
- "end": 5057,
- "tag_type": 1,
- "start": 5038
- },
- {
- "attributes": {
- "class": "newlogo"
- },
- "tag": "div",
- "end": 5078,
- "tag_type": 1,
- "start": 5057
- },
- {
- "start": 5078,
- "end": 5082
- },
- {
- "attributes": {},
- "tag": "h1",
- "end": 5086,
- "tag_type": 1,
- "start": 5082
- },
- {
- "start": 5086,
- "end": 5090
- },
- {
- "attributes": {
- "href": "/"
- },
- "tag": "a",
- "end": 5102,
- "tag_type": 1,
- "start": 5090
- },
- {
- "start": 5102,
- "end": 5106
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteCSS/Play/Live1/img/brand/logo.gif",
- "alt": "play.com",
- "style": "border-width: 0px; height: 38px; width: 194px;"
- },
- "tag": "img",
- "end": 5248,
- "tag_type": 1,
- "start": 5106
- },
- {
- "start": 5248,
- "end": 5252
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 5256,
- "tag_type": 2,
- "start": 5252
- },
- {
- "attributes": {},
- "tag": "h1",
- "end": 5261,
- "tag_type": 2,
- "start": 5256
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 5267,
- "tag_type": 2,
- "start": 5261
- },
- {
- "attributes": {
- "class": "freedelivery"
- },
- "tag": "div",
- "end": 5293,
- "tag_type": 1,
- "start": 5267
- },
- {
- "attributes": {
- "type": "text/javascript",
- "language": "JavaScript"
- },
- "tag": "script",
- "end": 5346,
- "tag_type": 1,
- "start": 5293
- },
- {
- "start": 5346,
- "end": 5537
- },
- {
- "attributes": {},
- "tag": "script",
- "end": 5546,
- "tag_type": 2,
- "start": 5537
- },
- {
- "attributes": {},
- "tag": "noscript",
- "end": 5556,
- "tag_type": 1,
- "start": 5546
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 5561,
- "tag_type": 1,
- "start": 5556
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteCSS/Play/Live1/img/brand/freedelivery.gif",
- "alt": "Free delivery on everything!",
- "height": "28",
- "width": "200"
- },
- "tag": "img",
- "end": 5700,
- "tag_type": 1,
- "start": 5561
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 5706,
- "tag_type": 2,
- "start": 5700
- },
- {
- "attributes": {},
- "tag": "noscript",
- "end": 5717,
- "tag_type": 2,
- "start": 5706
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 5723,
- "tag_type": 2,
- "start": 5717
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 5728,
- "tag_type": 2,
- "start": 5723
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 5732,
- "tag_type": 1,
- "start": 5728
- },
- {
- "attributes": {
- "class": "sc"
- },
- "tag": "div",
- "end": 5748,
- "tag_type": 1,
- "start": 5732
- },
- {
- "start": 5748,
- "end": 5752
- },
- {
- "attributes": {
- "class": "sback_r"
- },
- "tag": "div",
- "end": 5773,
- "tag_type": 1,
- "start": 5752
- },
- {
- "start": 5773,
- "end": 5777
- },
- {
- "attributes": {
- "class": "searchbox"
- },
- "tag": "div",
- "end": 5800,
- "tag_type": 1,
- "start": 5777
- },
- {
- "start": 5800,
- "end": 5804
- },
- {
- "attributes": {
- "action": "/Search.aspx",
- "method": "get",
- "name": "search",
- "class": "nomargin"
- },
- "tag": "form",
- "end": 5876,
- "tag_type": 1,
- "start": 5804
- },
- {
- "attributes": {
- "cellpadding": "0",
- "cellspacing": "0"
- },
- "tag": "table",
- "end": 5915,
- "tag_type": 1,
- "start": 5876
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 5922,
- "tag_type": 1,
- "start": 5915
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 5926,
- "tag_type": 1,
- "start": 5922
- },
- {
- "attributes": {
- "class": "region_td"
- },
- "tag": "td",
- "end": 5948,
- "tag_type": 1,
- "start": 5926
- },
- {
- "attributes": {
- "class": "region"
- },
- "tag": "div",
- "end": 5968,
- "tag_type": 1,
- "start": 5948
- },
- {
- "attributes": {
- "class": "searchtype",
- "name": "searchtype"
- },
- "tag": "select",
- "end": 6013,
- "tag_type": 1,
- "start": 5968
- },
- {
- "attributes": {
- "value": "allproducts"
- },
- "tag": "option",
- "end": 6041,
- "tag_type": 1,
- "start": 6013
- },
- {
- "start": 6041,
- "end": 6053
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 6062,
- "tag_type": 2,
- "start": 6053
- },
- {
- "attributes": {
- "value": "-----------------------"
- },
- "tag": "option",
- "end": 6102,
- "tag_type": 1,
- "start": 6062
- },
- {
- "start": 6102,
- "end": 6125
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 6134,
- "tag_type": 2,
- "start": 6125
- },
- {
- "attributes": {
- "value": "r2alldvd"
- },
- "tag": "option",
- "end": 6159,
- "tag_type": 1,
- "start": 6134
- },
- {
- "start": 6159,
- "end": 6162
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 6171,
- "tag_type": 2,
- "start": 6162
- },
- {
- "attributes": {
- "value": "musicall"
- },
- "tag": "option",
- "end": 6196,
- "tag_type": 1,
- "start": 6171
- },
- {
- "start": 6196,
- "end": 6201
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 6210,
- "tag_type": 2,
- "start": 6201
- },
- {
- "attributes": {
- "value": "gameall"
- },
- "tag": "option",
- "end": 6234,
- "tag_type": 1,
- "start": 6210
- },
- {
- "start": 6234,
- "end": 6239
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 6248,
- "tag_type": 2,
- "start": 6239
- },
- {
- "attributes": {
- "value": "bookall"
- },
- "tag": "option",
- "end": 6272,
- "tag_type": 1,
- "start": 6248
- },
- {
- "start": 6272,
- "end": 6277
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 6286,
- "tag_type": 2,
- "start": 6277
- },
- {
- "attributes": {
- "value": "abcdall"
- },
- "tag": "option",
- "end": 6310,
- "tag_type": 1,
- "start": 6286
- },
- {
- "start": 6310,
- "end": 6320
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 6329,
- "tag_type": 2,
- "start": 6320
- },
- {
- "attributes": {
- "value": "CAL"
- },
- "tag": "option",
- "end": 6349,
- "tag_type": 1,
- "start": 6329
- },
- {
- "start": 6349,
- "end": 6358
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 6367,
- "tag_type": 2,
- "start": 6358
- },
- {
- "attributes": {
- "selected": "selected",
- "value": "ELEC"
- },
- "tag": "option",
- "end": 6408,
- "tag_type": 1,
- "start": 6367
- },
- {
- "start": 6408,
- "end": 6419
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 6428,
- "tag_type": 2,
- "start": 6419
- },
- {
- "attributes": {
- "value": "PCSH"
- },
- "tag": "option",
- "end": 6449,
- "tag_type": 1,
- "start": 6428
- },
- {
- "start": 6449,
- "end": 6458
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 6467,
- "tag_type": 2,
- "start": 6458
- },
- {
- "attributes": {
- "value": "GADG"
- },
- "tag": "option",
- "end": 6488,
- "tag_type": 1,
- "start": 6467
- },
- {
- "start": 6488,
- "end": 6495
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 6504,
- "tag_type": 2,
- "start": 6495
- },
- {
- "attributes": {
- "value": "MBLS"
- },
- "tag": "option",
- "end": 6525,
- "tag_type": 1,
- "start": 6504
- },
- {
- "start": 6525,
- "end": 6538
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 6547,
- "tag_type": 2,
- "start": 6538
- },
- {
- "attributes": {
- "value": "mobileall"
- },
- "tag": "option",
- "end": 6573,
- "tag_type": 1,
- "start": 6547
- },
- {
- "start": 6573,
- "end": 6587
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 6596,
- "tag_type": 2,
- "start": 6587
- },
- {
- "attributes": {
- "value": "clothingall"
- },
- "tag": "option",
- "end": 6624,
- "tag_type": 1,
- "start": 6596
- },
- {
- "start": 6624,
- "end": 6632
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 6641,
- "tag_type": 2,
- "start": 6632
- },
- {
- "attributes": {
- "value": "TICKETS_ALL"
- },
- "tag": "option",
- "end": 6669,
- "tag_type": 1,
- "start": 6641
- },
- {
- "start": 6669,
- "end": 6676
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 6685,
- "tag_type": 2,
- "start": 6676
- },
- {
- "attributes": {
- "value": "-----------------------"
- },
- "tag": "option",
- "end": 6725,
- "tag_type": 1,
- "start": 6685
- },
- {
- "start": 6725,
- "end": 6748
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 6757,
- "tag_type": 2,
- "start": 6748
- },
- {
- "attributes": {
- "value": "r2alldvd"
- },
- "tag": "option",
- "end": 6782,
- "tag_type": 1,
- "start": 6757
- },
- {
- "start": 6782,
- "end": 6785
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 6794,
- "tag_type": 2,
- "start": 6785
- },
- {
- "attributes": {
- "value": "R2"
- },
- "tag": "option",
- "end": 6813,
- "tag_type": 1,
- "start": 6794
- },
- {
- "start": 6813,
- "end": 6825
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 6834,
- "tag_type": 2,
- "start": 6825
- },
- {
- "attributes": {
- "value": "r2title"
- },
- "tag": "option",
- "end": 6858,
- "tag_type": 1,
- "start": 6834
- },
- {
- "start": 6858,
- "end": 6876
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 6885,
- "tag_type": 2,
- "start": 6876
- },
- {
- "attributes": {
- "value": "r2actor"
- },
- "tag": "option",
- "end": 6909,
- "tag_type": 1,
- "start": 6885
- },
- {
- "start": 6909,
- "end": 6927
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 6936,
- "tag_type": 2,
- "start": 6927
- },
- {
- "attributes": {
- "value": "r2director"
- },
- "tag": "option",
- "end": 6963,
- "tag_type": 1,
- "start": 6936
- },
- {
- "start": 6963,
- "end": 6984
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 6993,
- "tag_type": 2,
- "start": 6984
- },
- {
- "attributes": {
- "value": "r2language"
- },
- "tag": "option",
- "end": 7020,
- "tag_type": 1,
- "start": 6993
- },
- {
- "start": 7020,
- "end": 7041
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7050,
- "tag_type": 2,
- "start": 7041
- },
- {
- "attributes": {
- "value": "r2subtitles"
- },
- "tag": "option",
- "end": 7078,
- "tag_type": 1,
- "start": 7050
- },
- {
- "start": 7078,
- "end": 7099
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7108,
- "tag_type": 2,
- "start": 7099
- },
- {
- "attributes": {
- "value": "BLU"
- },
- "tag": "option",
- "end": 7128,
- "tag_type": 1,
- "start": 7108
- },
- {
- "start": 7128,
- "end": 7144
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7153,
- "tag_type": 2,
- "start": 7144
- },
- {
- "attributes": {
- "value": "HD"
- },
- "tag": "option",
- "end": 7172,
- "tag_type": 1,
- "start": 7153
- },
- {
- "start": 7172,
- "end": 7187
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7196,
- "tag_type": 2,
- "start": 7187
- },
- {
- "attributes": {
- "value": "-----------------------"
- },
- "tag": "option",
- "end": 7236,
- "tag_type": 1,
- "start": 7196
- },
- {
- "start": 7236,
- "end": 7259
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7268,
- "tag_type": 2,
- "start": 7259
- },
- {
- "attributes": {
- "value": "musicall"
- },
- "tag": "option",
- "end": 7293,
- "tag_type": 1,
- "start": 7268
- },
- {
- "start": 7293,
- "end": 7298
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7307,
- "tag_type": 2,
- "start": 7298
- },
- {
- "attributes": {
- "value": "cdall"
- },
- "tag": "option",
- "end": 7329,
- "tag_type": 1,
- "start": 7307
- },
- {
- "start": 7329,
- "end": 7340
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7349,
- "tag_type": 2,
- "start": 7340
- },
- {
- "attributes": {
- "value": "downloadall"
- },
- "tag": "option",
- "end": 7377,
- "tag_type": 1,
- "start": 7349
- },
- {
- "start": 7377,
- "end": 7395
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7404,
- "tag_type": 2,
- "start": 7395
- },
- {
- "attributes": {
- "value": "rmtitle"
- },
- "tag": "option",
- "end": 7428,
- "tag_type": 1,
- "start": 7404
- },
- {
- "start": 7428,
- "end": 7446
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7455,
- "tag_type": 2,
- "start": 7446
- },
- {
- "attributes": {
- "value": "musicartist"
- },
- "tag": "option",
- "end": 7483,
- "tag_type": 1,
- "start": 7455
- },
- {
- "start": 7483,
- "end": 7498
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7507,
- "tag_type": 2,
- "start": 7498
- },
- {
- "attributes": {
- "value": "-----------------------"
- },
- "tag": "option",
- "end": 7547,
- "tag_type": 1,
- "start": 7507
- },
- {
- "start": 7547,
- "end": 7570
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7579,
- "tag_type": 2,
- "start": 7570
- },
- {
- "attributes": {
- "value": "gameall"
- },
- "tag": "option",
- "end": 7603,
- "tag_type": 1,
- "start": 7579
- },
- {
- "start": 7603,
- "end": 7608
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7617,
- "tag_type": 2,
- "start": 7608
- },
- {
- "attributes": {
- "value": "PC"
- },
- "tag": "option",
- "end": 7636,
- "tag_type": 1,
- "start": 7617
- },
- {
- "start": 7636,
- "end": 7647
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7656,
- "tag_type": 2,
- "start": 7647
- },
- {
- "attributes": {
- "value": "PS2"
- },
- "tag": "option",
- "end": 7676,
- "tag_type": 1,
- "start": 7656
- },
- {
- "start": 7676,
- "end": 7688
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7697,
- "tag_type": 2,
- "start": 7688
- },
- {
- "attributes": {
- "value": "PS3"
- },
- "tag": "option",
- "end": 7717,
- "tag_type": 1,
- "start": 7697
- },
- {
- "start": 7717,
- "end": 7729
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7738,
- "tag_type": 2,
- "start": 7729
- },
- {
- "attributes": {
- "value": "PSP"
- },
- "tag": "option",
- "end": 7758,
- "tag_type": 1,
- "start": 7738
- },
- {
- "start": 7758,
- "end": 7770
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7779,
- "tag_type": 2,
- "start": 7770
- },
- {
- "attributes": {
- "value": "XBOX"
- },
- "tag": "option",
- "end": 7800,
- "tag_type": 1,
- "start": 7779
- },
- {
- "start": 7800,
- "end": 7813
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7822,
- "tag_type": 2,
- "start": 7813
- },
- {
- "attributes": {
- "value": "X360"
- },
- "tag": "option",
- "end": 7843,
- "tag_type": 1,
- "start": 7822
- },
- {
- "start": 7843,
- "end": 7860
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7869,
- "tag_type": 2,
- "start": 7860
- },
- {
- "attributes": {
- "value": "DS"
- },
- "tag": "option",
- "end": 7888,
- "tag_type": 1,
- "start": 7869
- },
- {
- "start": 7888,
- "end": 7899
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7908,
- "tag_type": 2,
- "start": 7899
- },
- {
- "attributes": {
- "value": "GBA"
- },
- "tag": "option",
- "end": 7928,
- "tag_type": 1,
- "start": 7908
- },
- {
- "start": 7928,
- "end": 7940
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7949,
- "tag_type": 2,
- "start": 7940
- },
- {
- "attributes": {
- "value": "GC"
- },
- "tag": "option",
- "end": 7968,
- "tag_type": 1,
- "start": 7949
- },
- {
- "start": 7968,
- "end": 7985
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7994,
- "tag_type": 2,
- "start": 7985
- },
- {
- "attributes": {
- "value": "WII"
- },
- "tag": "option",
- "end": 8014,
- "tag_type": 1,
- "start": 7994
- },
- {
- "start": 8014,
- "end": 8026
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 8035,
- "tag_type": 2,
- "start": 8026
- },
- {
- "attributes": {
- "value": "-----------------------"
- },
- "tag": "option",
- "end": 8075,
- "tag_type": 1,
- "start": 8035
- },
- {
- "start": 8075,
- "end": 8098
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 8107,
- "tag_type": 2,
- "start": 8098
- },
- {
- "attributes": {
- "value": "bookall"
- },
- "tag": "option",
- "end": 8131,
- "tag_type": 1,
- "start": 8107
- },
- {
- "start": 8131,
- "end": 8136
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 8145,
- "tag_type": 2,
- "start": 8136
- },
- {
- "attributes": {
- "value": "booktitle"
- },
- "tag": "option",
- "end": 8171,
- "tag_type": 1,
- "start": 8145
- },
- {
- "start": 8171,
- "end": 8185
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 8194,
- "tag_type": 2,
- "start": 8185
- },
- {
- "attributes": {
- "value": "bookauthor"
- },
- "tag": "option",
- "end": 8221,
- "tag_type": 1,
- "start": 8194
- },
- {
- "start": 8221,
- "end": 8236
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 8245,
- "tag_type": 2,
- "start": 8236
- },
- {
- "attributes": {
- "value": "bookisbn"
- },
- "tag": "option",
- "end": 8270,
- "tag_type": 1,
- "start": 8245
- },
- {
- "start": 8270,
- "end": 8283
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 8292,
- "tag_type": 2,
- "start": 8283
- },
- {
- "attributes": {
- "value": "-----------------------"
- },
- "tag": "option",
- "end": 8332,
- "tag_type": 1,
- "start": 8292
- },
- {
- "start": 8332,
- "end": 8355
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 8364,
- "tag_type": 2,
- "start": 8355
- },
- {
- "attributes": {
- "value": "abcdall"
- },
- "tag": "option",
- "end": 8388,
- "tag_type": 1,
- "start": 8364
- },
- {
- "start": 8388,
- "end": 8398
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 8407,
- "tag_type": 2,
- "start": 8398
- },
- {
- "attributes": {
- "value": "abcdtitle"
- },
- "tag": "option",
- "end": 8433,
- "tag_type": 1,
- "start": 8407
- },
- {
- "start": 8433,
- "end": 8447
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 8456,
- "tag_type": 2,
- "start": 8447
- },
- {
- "attributes": {
- "value": "abcdauthor"
- },
- "tag": "option",
- "end": 8483,
- "tag_type": 1,
- "start": 8456
- },
- {
- "start": 8483,
- "end": 8498
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 8507,
- "tag_type": 2,
- "start": 8498
- },
- {
- "attributes": {},
- "tag": "select",
- "end": 8516,
- "tag_type": 2,
- "start": 8507
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 8522,
- "tag_type": 2,
- "start": 8516
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 8527,
- "tag_type": 2,
- "start": 8522
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 8531,
- "tag_type": 1,
- "start": 8527
- },
- {
- "attributes": {
- "class": "data"
- },
- "tag": "div",
- "end": 8549,
- "tag_type": 1,
- "start": 8531
- },
- {
- "attributes": {
- "type": "text",
- "name": "searchstring",
- "value": null
- },
- "tag": "input",
- "end": 8597,
- "tag_type": 1,
- "start": 8549
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 8603,
- "tag_type": 2,
- "start": 8597
- },
- {
- "attributes": {
- "type": "hidden",
- "name": "page",
- "value": "search"
- },
- "tag": "input",
- "end": 8651,
- "tag_type": 1,
- "start": 8603
- },
- {
- "attributes": {
- "type": "hidden",
- "name": "pa",
- "value": "search"
- },
- "tag": "input",
- "end": 8697,
- "tag_type": 1,
- "start": 8651
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 8702,
- "tag_type": 2,
- "start": 8697
- },
- {
- "attributes": {
- "class": "action_td"
- },
- "tag": "td",
- "end": 8724,
- "tag_type": 1,
- "start": 8702
- },
- {
- "attributes": {
- "class": "action"
- },
- "tag": "div",
- "end": 8744,
- "tag_type": 1,
- "start": 8724
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteCSS/Play/Live1/img/button/search.gif",
- "name": "go",
- "type": "image",
- "alt": "Search",
- "border": "0",
- "id": "go"
- },
- "tag": "input",
- "end": 8876,
- "tag_type": 1,
- "start": 8744
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 8882,
- "tag_type": 2,
- "start": 8876
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 8887,
- "tag_type": 2,
- "start": 8882
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 8892,
- "tag_type": 2,
- "start": 8887
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 8900,
- "tag_type": 2,
- "start": 8892
- },
- {
- "attributes": {},
- "tag": "table",
- "end": 8908,
- "tag_type": 2,
- "start": 8900
- },
- {
- "attributes": {},
- "tag": "form",
- "end": 8915,
- "tag_type": 2,
- "start": 8908
- },
- {
- "start": 8915,
- "end": 8919
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 8925,
- "tag_type": 2,
- "start": 8919
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 8931,
- "tag_type": 2,
- "start": 8925
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 8937,
- "tag_type": 2,
- "start": 8931
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 8942,
- "tag_type": 2,
- "start": 8937
- },
- {
- "attributes": {
- "class": "head_r"
- },
- "tag": "td",
- "end": 8961,
- "tag_type": 1,
- "start": 8942
- },
- {
- "attributes": {
- "class": "sbasket"
- },
- "tag": "div",
- "end": 8982,
- "tag_type": 1,
- "start": 8961
- },
- {
- "attributes": {},
- "tag": "h3",
- "end": 8986,
- "tag_type": 1,
- "start": 8982
- },
- {
- "attributes": {
- "href": "/HOME/HOME/6-/ShoppingBasket.html"
- },
- "tag": "a",
- "end": 9030,
- "tag_type": 1,
- "start": 8986
- },
- {
- "start": 9030,
- "end": 9048
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 9052,
- "tag_type": 2,
- "start": 9048
- },
- {
- "attributes": {},
- "tag": "h3",
- "end": 9057,
- "tag_type": 2,
- "start": 9052
- },
- {
- "attributes": {
- "class": "text_empty"
- },
- "tag": "div",
- "end": 9081,
- "tag_type": 1,
- "start": 9057
- },
- {
- "start": 9081,
- "end": 9088
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 9091,
- "tag_type": 1,
- "start": 9088
- },
- {
- "start": 9091,
- "end": 9111
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 9115,
- "tag_type": 2,
- "start": 9111
- },
- {
- "start": 9115,
- "end": 9119
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 9125,
- "tag_type": 2,
- "start": 9119
- },
- {
- "start": 9125,
- "end": 9129
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 9135,
- "tag_type": 2,
- "start": 9129
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 9140,
- "tag_type": 2,
- "start": 9135
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 9145,
- "tag_type": 2,
- "start": 9140
- },
- {
- "start": 9145,
- "end": 9149
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 9157,
- "tag_type": 2,
- "start": 9149
- },
- {
- "attributes": {},
- "tag": "table",
- "end": 9165,
- "tag_type": 2,
- "start": 9157
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 9171,
- "tag_type": 2,
- "start": 9165
- },
- {
- "start": 9171,
- "end": 9183
- },
- {
- "attributes": {
- "id": "navbar_contain"
- },
- "tag": "div",
- "end": 9208,
- "tag_type": 1,
- "start": 9183
- },
- {
- "start": 9208,
- "end": 9220
- },
- {
- "attributes": {
- "id": "navbar"
- },
- "tag": "ul",
- "end": 9236,
- "tag_type": 1,
- "start": 9220
- },
- {
- "start": 9236,
- "end": 9248
- },
- {
- "attributes": {
- "id": "nav_home"
- },
- "tag": "li",
- "end": 9266,
- "tag_type": 1,
- "start": 9248
- },
- {
- "start": 9266,
- "end": 9278
- },
- {
- "attributes": {
- "href": "/"
- },
- "tag": "a",
- "end": 9290,
- "tag_type": 1,
- "start": 9278
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 9296,
- "tag_type": 1,
- "start": 9290
- },
- {
- "start": 9296,
- "end": 9300
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 9307,
- "tag_type": 2,
- "start": 9300
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 9311,
- "tag_type": 2,
- "start": 9307
- },
- {
- "start": 9311,
- "end": 9335
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 9340,
- "tag_type": 2,
- "start": 9335
- },
- {
- "start": 9340,
- "end": 9352
- },
- {
- "attributes": {
- "id": "nav_dvd"
- },
- "tag": "li",
- "end": 9369,
- "tag_type": 1,
- "start": 9352
- },
- {
- "start": 9369,
- "end": 9381
- },
- {
- "attributes": {
- "href": "/DVD/DVD/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 9419,
- "tag_type": 1,
- "start": 9381
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 9425,
- "tag_type": 1,
- "start": 9419
- },
- {
- "start": 9425,
- "end": 9428
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 9435,
- "tag_type": 2,
- "start": 9428
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 9439,
- "tag_type": 2,
- "start": 9435
- },
- {
- "start": 9439,
- "end": 9479
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 9483,
- "tag_type": 1,
- "start": 9479
- },
- {
- "start": 9483,
- "end": 9527
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 9531,
- "tag_type": 1,
- "start": 9527
- },
- {
- "attributes": {
- "href": "/DVD/DVD/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 9569,
- "tag_type": 1,
- "start": 9531
- },
- {
- "start": 9569,
- "end": 9572
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 9576,
- "tag_type": 2,
- "start": 9572
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 9581,
- "tag_type": 2,
- "start": 9576
- },
- {
- "start": 9581,
- "end": 9625
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 9629,
- "tag_type": 1,
- "start": 9625
- },
- {
- "attributes": {
- "href": "/DVD/DVD/-/55/70/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 9692,
- "tag_type": 1,
- "start": 9629
- },
- {
- "start": 9692,
- "end": 9701
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 9705,
- "tag_type": 2,
- "start": 9701
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 9710,
- "tag_type": 2,
- "start": 9705
- },
- {
- "start": 9710,
- "end": 9754
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 9758,
- "tag_type": 1,
- "start": 9754
- },
- {
- "attributes": {
- "href": "/DVD/DVD/-/46/61/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 9821,
- "tag_type": 1,
- "start": 9758
- },
- {
- "start": 9821,
- "end": 9838
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 9842,
- "tag_type": 2,
- "start": 9838
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 9847,
- "tag_type": 2,
- "start": 9842
- },
- {
- "start": 9847,
- "end": 9891
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 9895,
- "tag_type": 1,
- "start": 9891
- },
- {
- "attributes": {
- "href": "/Music/MusicDVD/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 9940,
- "tag_type": 1,
- "start": 9895
- },
- {
- "start": 9940,
- "end": 9949
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 9953,
- "tag_type": 2,
- "start": 9949
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 9958,
- "tag_type": 2,
- "start": 9953
- },
- {
- "start": 9958,
- "end": 10002
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 10006,
- "tag_type": 1,
- "start": 10002
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/261/341/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 10087,
- "tag_type": 1,
- "start": 10006
- },
- {
- "start": 10087,
- "end": 10098
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 10102,
- "tag_type": 2,
- "start": 10098
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 10107,
- "tag_type": 2,
- "start": 10102
- },
- {
- "start": 10107,
- "end": 10151
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 10155,
- "tag_type": 1,
- "start": 10151
- },
- {
- "attributes": {
- "href": "/Gadgets/Gadgets/-/392/492/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 10228,
- "tag_type": 1,
- "start": 10155
- },
- {
- "start": 10228,
- "end": 10244
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 10248,
- "tag_type": 2,
- "start": 10244
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 10253,
- "tag_type": 2,
- "start": 10248
- },
- {
- "start": 10253,
- "end": 10297
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 10301,
- "tag_type": 1,
- "start": 10297
- },
- {
- "attributes": {
- "href": "/Clothing/T-Shirts/-/723/931/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 10376,
- "tag_type": 1,
- "start": 10301
- },
- {
- "start": 10376,
- "end": 10398
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 10402,
- "tag_type": 2,
- "start": 10398
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 10407,
- "tag_type": 2,
- "start": 10402
- },
- {
- "start": 10407,
- "end": 10451
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 10455,
- "tag_type": 1,
- "start": 10451
- },
- {
- "attributes": {
- "href": "/Gadgets/Gadgets/-/565/750/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 10528,
- "tag_type": 1,
- "start": 10455
- },
- {
- "start": 10528,
- "end": 10540
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 10544,
- "tag_type": 2,
- "start": 10540
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 10549,
- "tag_type": 2,
- "start": 10544
- },
- {
- "start": 10549,
- "end": 10593
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 10597,
- "tag_type": 1,
- "start": 10593
- },
- {
- "attributes": {
- "href": "/Books/Books/-/184/241/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 10666,
- "tag_type": 1,
- "start": 10597
- },
- {
- "start": 10666,
- "end": 10676
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 10680,
- "tag_type": 2,
- "start": 10676
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 10685,
- "tag_type": 2,
- "start": 10680
- },
- {
- "start": 10685,
- "end": 10729
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 10733,
- "tag_type": 1,
- "start": 10729
- },
- {
- "attributes": {
- "href": "/landingpage.aspx?page=playtrade&dpr=0&dpr=0&dpr=0&product=dvd"
- },
- "tag": "a",
- "end": 10822,
- "tag_type": 1,
- "start": 10733
- },
- {
- "start": 10822,
- "end": 10836
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 10840,
- "tag_type": 2,
- "start": 10836
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 10845,
- "tag_type": 2,
- "start": 10840
- },
- {
- "start": 10845,
- "end": 10889
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 10894,
- "tag_type": 2,
- "start": 10889
- },
- {
- "start": 10894,
- "end": 10922
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 10927,
- "tag_type": 2,
- "start": 10922
- },
- {
- "start": 10927,
- "end": 10939
- },
- {
- "attributes": {
- "id": "nav_blu"
- },
- "tag": "li",
- "end": 10956,
- "tag_type": 1,
- "start": 10939
- },
- {
- "start": 10956,
- "end": 10968
- },
- {
- "attributes": {
- "href": "/DVD/Blu-ray/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 11010,
- "tag_type": 1,
- "start": 10968
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 11016,
- "tag_type": 1,
- "start": 11010
- },
- {
- "start": 11016,
- "end": 11023
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 11030,
- "tag_type": 2,
- "start": 11023
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 11034,
- "tag_type": 2,
- "start": 11030
- },
- {
- "start": 11034,
- "end": 11074
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 11078,
- "tag_type": 1,
- "start": 11074
- },
- {
- "start": 11078,
- "end": 11122
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 11126,
- "tag_type": 1,
- "start": 11122
- },
- {
- "attributes": {
- "href": "/DVD/Blu-ray/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 11168,
- "tag_type": 1,
- "start": 11126
- },
- {
- "start": 11168,
- "end": 11172
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 11176,
- "tag_type": 2,
- "start": 11172
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 11181,
- "tag_type": 2,
- "start": 11176
- },
- {
- "start": 11181,
- "end": 11225
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 11229,
- "tag_type": 1,
- "start": 11225
- },
- {
- "attributes": {
- "href": "/DVD/Blu-ray/6-/TopSellers.html"
- },
- "tag": "a",
- "end": 11271,
- "tag_type": 1,
- "start": 11229
- },
- {
- "start": 11271,
- "end": 11290
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 11294,
- "tag_type": 2,
- "start": 11290
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 11299,
- "tag_type": 2,
- "start": 11294
- },
- {
- "start": 11299,
- "end": 11343
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 11347,
- "tag_type": 1,
- "start": 11343
- },
- {
- "attributes": {
- "href": "/DVD/Blu-ray/6-/PreOrderChart.html"
- },
- "tag": "a",
- "end": 11392,
- "tag_type": 1,
- "start": 11347
- },
- {
- "start": 11392,
- "end": 11409
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 11413,
- "tag_type": 2,
- "start": 11409
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 11418,
- "tag_type": 2,
- "start": 11413
- },
- {
- "start": 11418,
- "end": 11462
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 11466,
- "tag_type": 1,
- "start": 11462
- },
- {
- "attributes": {
- "href": "/DVD/Blu-ray/6-/PromoList.html"
- },
- "tag": "a",
- "end": 11507,
- "tag_type": 1,
- "start": 11466
- },
- {
- "start": 11507,
- "end": 11523
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 11527,
- "tag_type": 2,
- "start": 11523
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 11532,
- "tag_type": 2,
- "start": 11527
- },
- {
- "start": 11532,
- "end": 11576
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 11580,
- "tag_type": 1,
- "start": 11576
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/836/1052/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 11662,
- "tag_type": 1,
- "start": 11580
- },
- {
- "start": 11662,
- "end": 11677
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 11681,
- "tag_type": 2,
- "start": 11677
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 11686,
- "tag_type": 2,
- "start": 11681
- },
- {
- "start": 11686,
- "end": 11730
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 11734,
- "tag_type": 1,
- "start": 11730
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 11815,
- "tag_type": 1,
- "start": 11734
- },
- {
- "start": 11815,
- "end": 11821
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 11825,
- "tag_type": 2,
- "start": 11821
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 11830,
- "tag_type": 2,
- "start": 11825
- },
- {
- "start": 11830,
- "end": 11874
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 11878,
- "tag_type": 1,
- "start": 11874
- },
- {
- "attributes": {
- "href": "/Games/PlayStation3/3-/164637/2-/Promo.html"
- },
- "tag": "a",
- "end": 11932,
- "tag_type": 1,
- "start": 11878
- },
- {
- "start": 11932,
- "end": 11944
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 11948,
- "tag_type": 2,
- "start": 11944
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 11953,
- "tag_type": 2,
- "start": 11948
- },
- {
- "start": 11953,
- "end": 11997
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 12001,
- "tag_type": 1,
- "start": 11997
- },
- {
- "attributes": {
- "href": "/Games/PlayStation3/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 12050,
- "tag_type": 1,
- "start": 12001
- },
- {
- "start": 12050,
- "end": 12059
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 12063,
- "tag_type": 2,
- "start": 12059
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 12068,
- "tag_type": 2,
- "start": 12063
- },
- {
- "start": 12068,
- "end": 12112
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 12116,
- "tag_type": 1,
- "start": 12112
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/281/363/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 12197,
- "tag_type": 1,
- "start": 12116
- },
- {
- "start": 12197,
- "end": 12216
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 12220,
- "tag_type": 2,
- "start": 12216
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 12225,
- "tag_type": 2,
- "start": 12220
- },
- {
- "start": 12225,
- "end": 12269
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 12274,
- "tag_type": 2,
- "start": 12269
- },
- {
- "start": 12274,
- "end": 12302
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 12307,
- "tag_type": 2,
- "start": 12302
- },
- {
- "start": 12307,
- "end": 12319
- },
- {
- "attributes": {
- "id": "nav_music"
- },
- "tag": "li",
- "end": 12338,
- "tag_type": 1,
- "start": 12319
- },
- {
- "start": 12338,
- "end": 12350
- },
- {
- "attributes": {
- "href": "/Music/CD/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 12389,
- "tag_type": 1,
- "start": 12350
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 12395,
- "tag_type": 1,
- "start": 12389
- },
- {
- "start": 12395,
- "end": 12400
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 12407,
- "tag_type": 2,
- "start": 12400
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 12411,
- "tag_type": 2,
- "start": 12407
- },
- {
- "start": 12411,
- "end": 12451
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 12455,
- "tag_type": 1,
- "start": 12451
- },
- {
- "start": 12455,
- "end": 12499
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 12503,
- "tag_type": 1,
- "start": 12499
- },
- {
- "attributes": {
- "href": "/Music/CD/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 12542,
- "tag_type": 1,
- "start": 12503
- },
- {
- "start": 12542,
- "end": 12544
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 12548,
- "tag_type": 2,
- "start": 12544
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 12553,
- "tag_type": 2,
- "start": 12548
- },
- {
- "start": 12553,
- "end": 12597
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 12601,
- "tag_type": 1,
- "start": 12597
- },
- {
- "attributes": {
- "href": "/Music/CD/-/27/30/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 12665,
- "tag_type": 1,
- "start": 12601
- },
- {
- "start": 12665,
- "end": 12677
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 12681,
- "tag_type": 2,
- "start": 12677
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 12686,
- "tag_type": 2,
- "start": 12681
- },
- {
- "start": 12686,
- "end": 12730
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 12734,
- "tag_type": 1,
- "start": 12730
- },
- {
- "attributes": {
- "href": "/Tickets/TicketsEvent/-/959/1208/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 12813,
- "tag_type": 1,
- "start": 12734
- },
- {
- "start": 12813,
- "end": 12828
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 12832,
- "tag_type": 2,
- "start": 12828
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 12837,
- "tag_type": 2,
- "start": 12832
- },
- {
- "start": 12837,
- "end": 12881
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 12885,
- "tag_type": 1,
- "start": 12881
- },
- {
- "attributes": {
- "href": "/Music/MP3-Download/6-/DigitalHome.html"
- },
- "tag": "a",
- "end": 12935,
- "tag_type": 1,
- "start": 12885
- },
- {
- "start": 12935,
- "end": 12948
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 12952,
- "tag_type": 2,
- "start": 12948
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 12957,
- "tag_type": 2,
- "start": 12952
- },
- {
- "start": 12957,
- "end": 13001
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 13005,
- "tag_type": 1,
- "start": 13001
- },
- {
- "attributes": {
- "href": "/Music/MusicDVD/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 13050,
- "tag_type": 1,
- "start": 13005
- },
- {
- "start": 13050,
- "end": 13059
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 13063,
- "tag_type": 2,
- "start": 13059
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 13068,
- "tag_type": 2,
- "start": 13063
- },
- {
- "start": 13068,
- "end": 13112
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 13116,
- "tag_type": 1,
- "start": 13112
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/291/375/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 13197,
- "tag_type": 1,
- "start": 13116
- },
- {
- "start": 13197,
- "end": 13220
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 13224,
- "tag_type": 2,
- "start": 13220
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 13229,
- "tag_type": 2,
- "start": 13224
- },
- {
- "start": 13229,
- "end": 13273
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 13277,
- "tag_type": 1,
- "start": 13273
- },
- {
- "attributes": {
- "href": "/Clothing/Clothing/6-/Campaign.html?campaign=2831&cid=6512018"
- },
- "tag": "a",
- "end": 13353,
- "tag_type": 1,
- "start": 13277
- },
- {
- "start": 13353,
- "end": 13367
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 13371,
- "tag_type": 2,
- "start": 13367
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 13376,
- "tag_type": 2,
- "start": 13371
- },
- {
- "start": 13376,
- "end": 13420
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 13424,
- "tag_type": 1,
- "start": 13420
- },
- {
- "attributes": {
- "href": "/Gadgets/Gadgets/-/570/755/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 13497,
- "tag_type": 1,
- "start": 13424
- },
- {
- "start": 13497,
- "end": 13510
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 13514,
- "tag_type": 2,
- "start": 13510
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 13519,
- "tag_type": 2,
- "start": 13514
- },
- {
- "start": 13519,
- "end": 13563
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 13567,
- "tag_type": 1,
- "start": 13563
- },
- {
- "attributes": {
- "href": "/Books/Books/-/184/241/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 13636,
- "tag_type": 1,
- "start": 13567
- },
- {
- "start": 13636,
- "end": 13647
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 13651,
- "tag_type": 2,
- "start": 13647
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 13656,
- "tag_type": 2,
- "start": 13651
- },
- {
- "start": 13656,
- "end": 13700
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 13704,
- "tag_type": 1,
- "start": 13700
- },
- {
- "attributes": {
- "href": "/landingpage.aspx?page=playtrade&dpr=0&dpr=0&dpr=0&product=cd"
- },
- "tag": "a",
- "end": 13792,
- "tag_type": 1,
- "start": 13704
- },
- {
- "start": 13792,
- "end": 13805
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 13809,
- "tag_type": 2,
- "start": 13805
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 13814,
- "tag_type": 2,
- "start": 13809
- },
- {
- "start": 13814,
- "end": 13858
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 13863,
- "tag_type": 2,
- "start": 13858
- },
- {
- "start": 13863,
- "end": 13891
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 13896,
- "tag_type": 2,
- "start": 13891
- },
- {
- "start": 13896,
- "end": 13908
- },
- {
- "attributes": {
- "id": "nav_tickets"
- },
- "tag": "li",
- "end": 13929,
- "tag_type": 1,
- "start": 13908
- },
- {
- "start": 13929,
- "end": 13941
- },
- {
- "attributes": {
- "href": "/Tickets/TicketsEvent/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 13992,
- "tag_type": 1,
- "start": 13941
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 13998,
- "tag_type": 1,
- "start": 13992
- },
- {
- "start": 13998,
- "end": 14005
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 14012,
- "tag_type": 2,
- "start": 14005
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 14016,
- "tag_type": 2,
- "start": 14012
- },
- {
- "start": 14016,
- "end": 14056
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 14060,
- "tag_type": 1,
- "start": 14056
- },
- {
- "start": 14060,
- "end": 14104
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 14108,
- "tag_type": 1,
- "start": 14104
- },
- {
- "attributes": {
- "href": "/Tickets/TicketsEvent/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 14159,
- "tag_type": 1,
- "start": 14108
- },
- {
- "start": 14159,
- "end": 14163
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 14167,
- "tag_type": 2,
- "start": 14163
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 14172,
- "tag_type": 2,
- "start": 14167
- },
- {
- "start": 14172,
- "end": 14216
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 14220,
- "tag_type": 1,
- "start": 14216
- },
- {
- "attributes": {
- "href": "/Tickets/TicketsEvent/-/959/1208/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 14299,
- "tag_type": 1,
- "start": 14220
- },
- {
- "start": 14299,
- "end": 14314
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 14318,
- "tag_type": 2,
- "start": 14314
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 14323,
- "tag_type": 2,
- "start": 14318
- },
- {
- "start": 14323,
- "end": 14367
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 14371,
- "tag_type": 1,
- "start": 14367
- },
- {
- "attributes": {
- "href": "/Tickets/TicketsEvent/-/968/1217/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 14450,
- "tag_type": 1,
- "start": 14371
- },
- {
- "start": 14450,
- "end": 14468
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 14472,
- "tag_type": 2,
- "start": 14468
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 14477,
- "tag_type": 2,
- "start": 14472
- },
- {
- "start": 14477,
- "end": 14521
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 14525,
- "tag_type": 1,
- "start": 14521
- },
- {
- "attributes": {
- "href": "/GenreBrowse.aspx?r=TICKETS_EVENT&p=969&g=1218"
- },
- "tag": "a",
- "end": 14590,
- "tag_type": 1,
- "start": 14525
- },
- {
- "start": 14590,
- "end": 14596
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 14600,
- "tag_type": 2,
- "start": 14596
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 14605,
- "tag_type": 2,
- "start": 14600
- },
- {
- "start": 14605,
- "end": 14649
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 14653,
- "tag_type": 1,
- "start": 14649
- },
- {
- "attributes": {
- "href": "/Tickets/TicketsEvent/-/975/1224/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 14732,
- "tag_type": 1,
- "start": 14653
- },
- {
- "start": 14732,
- "end": 14738
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 14742,
- "tag_type": 2,
- "start": 14738
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 14747,
- "tag_type": 2,
- "start": 14742
- },
- {
- "start": 14747,
- "end": 14791
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 14795,
- "tag_type": 1,
- "start": 14791
- },
- {
- "attributes": {
- "href": "/Tickets/TicketsEvent/-/1079/1315/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 14875,
- "tag_type": 1,
- "start": 14795
- },
- {
- "start": 14875,
- "end": 14886
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 14890,
- "tag_type": 2,
- "start": 14886
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 14895,
- "tag_type": 2,
- "start": 14890
- },
- {
- "start": 14895,
- "end": 14939
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 14943,
- "tag_type": 1,
- "start": 14939
- },
- {
- "attributes": {
- "href": "/Clothing/Clothing/6-/Campaign.html?campaign=2831&cid=6512018"
- },
- "tag": "a",
- "end": 15019,
- "tag_type": 1,
- "start": 14943
- },
- {
- "start": 15019,
- "end": 15033
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 15037,
- "tag_type": 2,
- "start": 15033
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 15042,
- "tag_type": 2,
- "start": 15037
- },
- {
- "start": 15042,
- "end": 15086
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 15090,
- "tag_type": 1,
- "start": 15086
- },
- {
- "attributes": {
- "href": "/landingpage.aspx?page=playtrade&dpr=0&dpr=0&dpr=0&product=ticket"
- },
- "tag": "a",
- "end": 15182,
- "tag_type": 1,
- "start": 15090
- },
- {
- "start": 15182,
- "end": 15199
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 15203,
- "tag_type": 2,
- "start": 15199
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 15208,
- "tag_type": 2,
- "start": 15203
- },
- {
- "start": 15208,
- "end": 15252
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 15257,
- "tag_type": 2,
- "start": 15252
- },
- {
- "start": 15257,
- "end": 15285
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 15290,
- "tag_type": 2,
- "start": 15285
- },
- {
- "start": 15290,
- "end": 15302
- },
- {
- "attributes": {
- "id": "nav_game"
- },
- "tag": "li",
- "end": 15320,
- "tag_type": 1,
- "start": 15302
- },
- {
- "start": 15320,
- "end": 15332
- },
- {
- "attributes": {
- "href": "/Games/Games/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 15374,
- "tag_type": 1,
- "start": 15332
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 15380,
- "tag_type": 1,
- "start": 15374
- },
- {
- "start": 15380,
- "end": 15385
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 15392,
- "tag_type": 2,
- "start": 15385
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 15396,
- "tag_type": 2,
- "start": 15392
- },
- {
- "start": 15396,
- "end": 15436
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 15440,
- "tag_type": 1,
- "start": 15436
- },
- {
- "start": 15440,
- "end": 15484
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 15488,
- "tag_type": 1,
- "start": 15484
- },
- {
- "attributes": {
- "href": "/Games/Games/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 15530,
- "tag_type": 1,
- "start": 15488
- },
- {
- "start": 15530,
- "end": 15534
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 15538,
- "tag_type": 2,
- "start": 15534
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 15543,
- "tag_type": 2,
- "start": 15538
- },
- {
- "start": 15543,
- "end": 15587
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 15591,
- "tag_type": 1,
- "start": 15587
- },
- {
- "attributes": {
- "href": "/Games/Games/6-/Campaign.html?campaign=5371&cid=2061705"
- },
- "tag": "a",
- "end": 15661,
- "tag_type": 1,
- "start": 15591
- },
- {
- "start": 15661,
- "end": 15675
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 15679,
- "tag_type": 2,
- "start": 15675
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 15684,
- "tag_type": 2,
- "start": 15679
- },
- {
- "start": 15684,
- "end": 15728
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 15732,
- "tag_type": 1,
- "start": 15728
- },
- {
- "attributes": {
- "href": "/Games/PlayStation3/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 15781,
- "tag_type": 1,
- "start": 15732
- },
- {
- "start": 15781,
- "end": 15789
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 15793,
- "tag_type": 2,
- "start": 15789
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 15798,
- "tag_type": 2,
- "start": 15793
- },
- {
- "start": 15798,
- "end": 15842
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 15846,
- "tag_type": 1,
- "start": 15842
- },
- {
- "attributes": {
- "href": "/Games/PlayStation2/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 15895,
- "tag_type": 1,
- "start": 15846
- },
- {
- "start": 15895,
- "end": 15903
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 15907,
- "tag_type": 2,
- "start": 15903
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 15912,
- "tag_type": 2,
- "start": 15907
- },
- {
- "start": 15912,
- "end": 15956
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 15960,
- "tag_type": 1,
- "start": 15956
- },
- {
- "attributes": {
- "href": "/Games/PSP/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 16000,
- "tag_type": 1,
- "start": 15960
- },
- {
- "start": 16000,
- "end": 16008
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 16012,
- "tag_type": 2,
- "start": 16008
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 16017,
- "tag_type": 2,
- "start": 16012
- },
- {
- "start": 16017,
- "end": 16061
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 16065,
- "tag_type": 1,
- "start": 16061
- },
- {
- "attributes": {
- "href": "/Games/Wii/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 16105,
- "tag_type": 1,
- "start": 16065
- },
- {
- "start": 16105,
- "end": 16117
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 16121,
- "tag_type": 2,
- "start": 16117
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 16126,
- "tag_type": 2,
- "start": 16121
- },
- {
- "start": 16126,
- "end": 16170
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 16174,
- "tag_type": 1,
- "start": 16170
- },
- {
- "attributes": {
- "href": "/Games/DS/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 16213,
- "tag_type": 1,
- "start": 16174
- },
- {
- "start": 16213,
- "end": 16234
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 16238,
- "tag_type": 2,
- "start": 16234
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 16243,
- "tag_type": 2,
- "start": 16238
- },
- {
- "start": 16243,
- "end": 16287
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 16291,
- "tag_type": 1,
- "start": 16287
- },
- {
- "attributes": {
- "href": "/Games/Xbox360/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 16335,
- "tag_type": 1,
- "start": 16291
- },
- {
- "start": 16335,
- "end": 16343
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 16347,
- "tag_type": 2,
- "start": 16343
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 16352,
- "tag_type": 2,
- "start": 16347
- },
- {
- "start": 16352,
- "end": 16396
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 16400,
- "tag_type": 1,
- "start": 16396
- },
- {
- "attributes": {
- "href": "/Games/PC/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 16439,
- "tag_type": 1,
- "start": 16400
- },
- {
- "start": 16439,
- "end": 16447
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 16451,
- "tag_type": 2,
- "start": 16447
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 16456,
- "tag_type": 2,
- "start": 16451
- },
- {
- "start": 16456,
- "end": 16500
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 16504,
- "tag_type": 1,
- "start": 16500
- },
- {
- "attributes": {
- "href": "/Games/PC/3-/4047/2-/Promo.html?dpr=4047"
- },
- "tag": "a",
- "end": 16555,
- "tag_type": 1,
- "start": 16504
- },
- {
- "start": 16555,
- "end": 16564
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 16568,
- "tag_type": 2,
- "start": 16564
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 16573,
- "tag_type": 2,
- "start": 16568
- },
- {
- "start": 16573,
- "end": 16617
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 16621,
- "tag_type": 1,
- "start": 16617
- },
- {
- "attributes": {
- "href": "/Books/Books/-/128/185/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 16690,
- "tag_type": 1,
- "start": 16621
- },
- {
- "start": 16690,
- "end": 16702
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 16706,
- "tag_type": 2,
- "start": 16702
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 16711,
- "tag_type": 2,
- "start": 16706
- },
- {
- "start": 16711,
- "end": 16755
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 16759,
- "tag_type": 1,
- "start": 16755
- },
- {
- "attributes": {
- "href": "/Clothing/T-Shirts/-/837/1053/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 16835,
- "tag_type": 1,
- "start": 16759
- },
- {
- "start": 16835,
- "end": 16849
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 16853,
- "tag_type": 2,
- "start": 16849
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 16858,
- "tag_type": 2,
- "start": 16853
- },
- {
- "start": 16858,
- "end": 16902
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 16906,
- "tag_type": 1,
- "start": 16902
- },
- {
- "attributes": {
- "href": "/Gadgets/Gadgets/-/835/1051/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 16980,
- "tag_type": 1,
- "start": 16906
- },
- {
- "start": 16980,
- "end": 16997
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 17001,
- "tag_type": 2,
- "start": 16997
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 17006,
- "tag_type": 2,
- "start": 17001
- },
- {
- "start": 17006,
- "end": 17050
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 17054,
- "tag_type": 1,
- "start": 17050
- },
- {
- "attributes": {
- "href": "/landingpage.aspx?page=playtrade&dpr=0&dpr=0&dpr=0&product=game"
- },
- "tag": "a",
- "end": 17144,
- "tag_type": 1,
- "start": 17054
- },
- {
- "start": 17144,
- "end": 17159
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 17163,
- "tag_type": 2,
- "start": 17159
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 17168,
- "tag_type": 2,
- "start": 17163
- },
- {
- "start": 17168,
- "end": 17212
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 17217,
- "tag_type": 2,
- "start": 17212
- },
- {
- "start": 17217,
- "end": 17245
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 17250,
- "tag_type": 2,
- "start": 17245
- },
- {
- "start": 17250,
- "end": 17262
- },
- {
- "attributes": {
- "id": "nav_book"
- },
- "tag": "li",
- "end": 17280,
- "tag_type": 1,
- "start": 17262
- },
- {
- "start": 17280,
- "end": 17292
- },
- {
- "attributes": {
- "href": "/Books/Books/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 17334,
- "tag_type": 1,
- "start": 17292
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 17340,
- "tag_type": 1,
- "start": 17334
- },
- {
- "start": 17340,
- "end": 17345
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 17352,
- "tag_type": 2,
- "start": 17345
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 17356,
- "tag_type": 2,
- "start": 17352
- },
- {
- "start": 17356,
- "end": 17396
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 17400,
- "tag_type": 1,
- "start": 17396
- },
- {
- "start": 17400,
- "end": 17444
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 17448,
- "tag_type": 1,
- "start": 17444
- },
- {
- "attributes": {
- "href": "/Books/Books/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 17490,
- "tag_type": 1,
- "start": 17448
- },
- {
- "start": 17490,
- "end": 17494
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 17498,
- "tag_type": 2,
- "start": 17494
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 17503,
- "tag_type": 2,
- "start": 17498
- },
- {
- "start": 17503,
- "end": 17547
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 17551,
- "tag_type": 1,
- "start": 17547
- },
- {
- "attributes": {
- "href": "/Books/Books/-/104/161/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 17620,
- "tag_type": 1,
- "start": 17551
- },
- {
- "start": 17620,
- "end": 17630
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 17634,
- "tag_type": 2,
- "start": 17630
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 17639,
- "tag_type": 2,
- "start": 17634
- },
- {
- "start": 17639,
- "end": 17683
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 17687,
- "tag_type": 1,
- "start": 17683
- },
- {
- "attributes": {
- "href": "/Books/Books/-/100/157/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 17756,
- "tag_type": 1,
- "start": 17687
- },
- {
- "start": 17756,
- "end": 17765
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 17769,
- "tag_type": 2,
- "start": 17765
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 17774,
- "tag_type": 2,
- "start": 17769
- },
- {
- "start": 17774,
- "end": 17818
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 17822,
- "tag_type": 1,
- "start": 17818
- },
- {
- "attributes": {
- "href": "/Books/Books/-/203/260/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 17891,
- "tag_type": 1,
- "start": 17822
- },
- {
- "start": 17891,
- "end": 17905
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 17909,
- "tag_type": 2,
- "start": 17905
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 17914,
- "tag_type": 2,
- "start": 17909
- },
- {
- "start": 17914,
- "end": 17958
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 17962,
- "tag_type": 1,
- "start": 17958
- },
- {
- "attributes": {
- "href": "/Books/Books/-/200/257/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 18031,
- "tag_type": 1,
- "start": 17962
- },
- {
- "start": 18031,
- "end": 18051
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 18055,
- "tag_type": 2,
- "start": 18051
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 18060,
- "tag_type": 2,
- "start": 18055
- },
- {
- "start": 18060,
- "end": 18104
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 18108,
- "tag_type": 1,
- "start": 18104
- },
- {
- "attributes": {
- "href": "/Books/Books/-/142/199/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 18177,
- "tag_type": 1,
- "start": 18108
- },
- {
- "start": 18177,
- "end": 18195
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 18199,
- "tag_type": 2,
- "start": 18195
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 18204,
- "tag_type": 2,
- "start": 18199
- },
- {
- "start": 18204,
- "end": 18248
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 18252,
- "tag_type": 1,
- "start": 18248
- },
- {
- "attributes": {
- "href": "/Books/Books/-/159/216/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 18321,
- "tag_type": 1,
- "start": 18252
- },
- {
- "start": 18321,
- "end": 18337
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 18341,
- "tag_type": 2,
- "start": 18337
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 18346,
- "tag_type": 2,
- "start": 18341
- },
- {
- "start": 18346,
- "end": 18390
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 18394,
- "tag_type": 1,
- "start": 18390
- },
- {
- "attributes": {
- "href": "/Books/Books/-/151/208/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 18463,
- "tag_type": 1,
- "start": 18394
- },
- {
- "start": 18463,
- "end": 18470
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 18474,
- "tag_type": 2,
- "start": 18470
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 18479,
- "tag_type": 2,
- "start": 18474
- },
- {
- "start": 18479,
- "end": 18523
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 18527,
- "tag_type": 1,
- "start": 18523
- },
- {
- "attributes": {
- "href": "/Books/AudioBooks/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 18574,
- "tag_type": 1,
- "start": 18527
- },
- {
- "start": 18574,
- "end": 18584
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 18588,
- "tag_type": 2,
- "start": 18584
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 18593,
- "tag_type": 2,
- "start": 18588
- },
- {
- "start": 18593,
- "end": 18637
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 18641,
- "tag_type": 1,
- "start": 18637
- },
- {
- "attributes": {
- "href": "/landingpage.aspx?page=playtrade&dpr=0&dpr=0&dpr=0&product=book"
- },
- "tag": "a",
- "end": 18731,
- "tag_type": 1,
- "start": 18641
- },
- {
- "start": 18731,
- "end": 18746
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 18750,
- "tag_type": 2,
- "start": 18746
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 18755,
- "tag_type": 2,
- "start": 18750
- },
- {
- "start": 18755,
- "end": 18799
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 18804,
- "tag_type": 2,
- "start": 18799
- },
- {
- "start": 18804,
- "end": 18832
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 18837,
- "tag_type": 2,
- "start": 18832
- },
- {
- "start": 18837,
- "end": 18849
- },
- {
- "attributes": {
- "id": "nav_clth"
- },
- "tag": "li",
- "end": 18867,
- "tag_type": 1,
- "start": 18849
- },
- {
- "start": 18867,
- "end": 18879
- },
- {
- "attributes": {
- "href": "/Clothing/Clothing/6-/ClothingHome.html"
- },
- "tag": "a",
- "end": 18929,
- "tag_type": 1,
- "start": 18879
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 18935,
- "tag_type": 1,
- "start": 18929
- },
- {
- "start": 18935,
- "end": 18943
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 18950,
- "tag_type": 2,
- "start": 18943
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 18954,
- "tag_type": 2,
- "start": 18950
- },
- {
- "start": 18954,
- "end": 18994
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 18998,
- "tag_type": 1,
- "start": 18994
- },
- {
- "start": 18998,
- "end": 19042
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 19046,
- "tag_type": 1,
- "start": 19042
- },
- {
- "attributes": {
- "href": "/Clothing/Clothing/6-/ClothingHome.html"
- },
- "tag": "a",
- "end": 19096,
- "tag_type": 1,
- "start": 19046
- },
- {
- "start": 19096,
- "end": 19100
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 19104,
- "tag_type": 2,
- "start": 19100
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 19109,
- "tag_type": 2,
- "start": 19104
- },
- {
- "start": 19109,
- "end": 19153
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 19157,
- "tag_type": 1,
- "start": 19153
- },
- {
- "attributes": {
- "href": "/Clothing/T-Shirts/-/720/928/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 19232,
- "tag_type": 1,
- "start": 19157
- },
- {
- "start": 19232,
- "end": 19245
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 19249,
- "tag_type": 2,
- "start": 19245
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 19254,
- "tag_type": 2,
- "start": 19249
- },
- {
- "start": 19254,
- "end": 19298
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 19302,
- "tag_type": 1,
- "start": 19298
- },
- {
- "attributes": {
- "href": "/Clothing/T-Shirts/-/721/929/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 19377,
- "tag_type": 1,
- "start": 19302
- },
- {
- "start": 19377,
- "end": 19392
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 19396,
- "tag_type": 2,
- "start": 19392
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 19401,
- "tag_type": 2,
- "start": 19396
- },
- {
- "start": 19401,
- "end": 19445
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 19449,
- "tag_type": 1,
- "start": 19445
- },
- {
- "attributes": {
- "href": "/Clothing/Clothing/6-/Campaign.html?campaign=2825&cid=1354516"
- },
- "tag": "a",
- "end": 19525,
- "tag_type": 1,
- "start": 19449
- },
- {
- "start": 19525,
- "end": 19538
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 19542,
- "tag_type": 2,
- "start": 19538
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 19547,
- "tag_type": 2,
- "start": 19542
- },
- {
- "start": 19547,
- "end": 19591
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 19595,
- "tag_type": 1,
- "start": 19591
- },
- {
- "attributes": {
- "href": "/Clothing/Clothing/6-/Campaign.html?campaign=2831&cid=6512018"
- },
- "tag": "a",
- "end": 19671,
- "tag_type": 1,
- "start": 19595
- },
- {
- "start": 19671,
- "end": 19685
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 19689,
- "tag_type": 2,
- "start": 19685
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 19694,
- "tag_type": 2,
- "start": 19689
- },
- {
- "start": 19694,
- "end": 19738
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 19742,
- "tag_type": 1,
- "start": 19738
- },
- {
- "attributes": {
- "href": "/Clothing/T-Shirts/-/723/931/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 19817,
- "tag_type": 1,
- "start": 19742
- },
- {
- "start": 19817,
- "end": 19839
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 19843,
- "tag_type": 2,
- "start": 19839
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 19848,
- "tag_type": 2,
- "start": 19843
- },
- {
- "start": 19848,
- "end": 19892
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 19896,
- "tag_type": 1,
- "start": 19892
- },
- {
- "attributes": {
- "href": "/Clothing/Accessories/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 19947,
- "tag_type": 1,
- "start": 19896
- },
- {
- "start": 19947,
- "end": 19958
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 19962,
- "tag_type": 2,
- "start": 19958
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 19967,
- "tag_type": 2,
- "start": 19962
- },
- {
- "start": 19967,
- "end": 20011
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 20015,
- "tag_type": 1,
- "start": 20011
- },
- {
- "attributes": {
- "href": "/Clothing/Accessories/-/2026/1276/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 20095,
- "tag_type": 1,
- "start": 20015
- },
- {
- "start": 20095,
- "end": 20105
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 20109,
- "tag_type": 2,
- "start": 20105
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 20114,
- "tag_type": 2,
- "start": 20109
- },
- {
- "start": 20114,
- "end": 20158
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 20163,
- "tag_type": 2,
- "start": 20158
- },
- {
- "start": 20163,
- "end": 20191
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 20196,
- "tag_type": 2,
- "start": 20191
- },
- {
- "start": 20196,
- "end": 20208
- },
- {
- "attributes": {
- "id": "nav_elec"
- },
- "tag": "li",
- "end": 20226,
- "tag_type": 1,
- "start": 20208
- },
- {
- "start": 20226,
- "end": 20238
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/6-/RegionHome.html",
- "class": "this"
- },
- "tag": "a",
- "end": 20305,
- "tag_type": 1,
- "start": 20238
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 20311,
- "tag_type": 1,
- "start": 20305
- },
- {
- "start": 20311,
- "end": 20322
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 20329,
- "tag_type": 2,
- "start": 20322
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 20333,
- "tag_type": 2,
- "start": 20329
- },
- {
- "start": 20333,
- "end": 20373
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 20377,
- "tag_type": 1,
- "start": 20373
- },
- {
- "start": 20377,
- "end": 20421
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 20425,
- "tag_type": 1,
- "start": 20421
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 20479,
- "tag_type": 1,
- "start": 20425
- },
- {
- "start": 20479,
- "end": 20483
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 20487,
- "tag_type": 2,
- "start": 20483
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 20492,
- "tag_type": 2,
- "start": 20487
- },
- {
- "start": 20492,
- "end": 20536
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 20540,
- "tag_type": 1,
- "start": 20536
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 20621,
- "tag_type": 1,
- "start": 20540
- },
- {
- "start": 20621,
- "end": 20632
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 20636,
- "tag_type": 2,
- "start": 20632
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 20641,
- "tag_type": 2,
- "start": 20636
- },
- {
- "start": 20641,
- "end": 20685
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 20689,
- "tag_type": 1,
- "start": 20685
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/291/375/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 20770,
- "tag_type": 1,
- "start": 20689
- },
- {
- "start": 20770,
- "end": 20793
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 20797,
- "tag_type": 2,
- "start": 20793
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 20802,
- "tag_type": 2,
- "start": 20797
- },
- {
- "start": 20802,
- "end": 20846
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 20850,
- "tag_type": 1,
- "start": 20846
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/2168/1435/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 20933,
- "tag_type": 1,
- "start": 20850
- },
- {
- "start": 20933,
- "end": 20941
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 20945,
- "tag_type": 2,
- "start": 20941
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 20950,
- "tag_type": 2,
- "start": 20945
- },
- {
- "start": 20950,
- "end": 20994
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 20998,
- "tag_type": 1,
- "start": 20994
- },
- {
- "attributes": {
- "href": "/Games/Games/6-/Campaign.html?campaign=5371&cid=2061705"
- },
- "tag": "a",
- "end": 21068,
- "tag_type": 1,
- "start": 20998
- },
- {
- "start": 21068,
- "end": 21082
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 21086,
- "tag_type": 2,
- "start": 21082
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 21091,
- "tag_type": 2,
- "start": 21086
- },
- {
- "start": 21091,
- "end": 21135
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 21139,
- "tag_type": 1,
- "start": 21135
- },
- {
- "attributes": {
- "href": "/PC/PCs/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 21176,
- "tag_type": 1,
- "start": 21139
- },
- {
- "start": 21176,
- "end": 21185
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 21189,
- "tag_type": 2,
- "start": 21185
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 21194,
- "tag_type": 2,
- "start": 21189
- },
- {
- "start": 21194,
- "end": 21238
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 21242,
- "tag_type": 1,
- "start": 21238
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/261/341/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 21323,
- "tag_type": 1,
- "start": 21242
- },
- {
- "start": 21323,
- "end": 21348
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 21352,
- "tag_type": 2,
- "start": 21348
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 21357,
- "tag_type": 2,
- "start": 21352
- },
- {
- "start": 21357,
- "end": 21401
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 21405,
- "tag_type": 1,
- "start": 21401
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/256/336/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 21486,
- "tag_type": 1,
- "start": 21405
- },
- {
- "start": 21486,
- "end": 21501
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 21505,
- "tag_type": 2,
- "start": 21501
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 21510,
- "tag_type": 2,
- "start": 21505
- },
- {
- "start": 21510,
- "end": 21554
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 21558,
- "tag_type": 1,
- "start": 21554
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/253/333/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 21639,
- "tag_type": 1,
- "start": 21558
- },
- {
- "start": 21639,
- "end": 21649
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 21653,
- "tag_type": 2,
- "start": 21649
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 21658,
- "tag_type": 2,
- "start": 21653
- },
- {
- "start": 21658,
- "end": 21702
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 21706,
- "tag_type": 1,
- "start": 21702
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/281/363/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 21787,
- "tag_type": 1,
- "start": 21706
- },
- {
- "start": 21787,
- "end": 21798
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 21802,
- "tag_type": 2,
- "start": 21798
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 21807,
- "tag_type": 2,
- "start": 21802
- },
- {
- "start": 21807,
- "end": 21851
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 21855,
- "tag_type": 1,
- "start": 21851
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/275/355/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 21936,
- "tag_type": 1,
- "start": 21855
- },
- {
- "start": 21936,
- "end": 21949
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 21953,
- "tag_type": 2,
- "start": 21949
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 21958,
- "tag_type": 2,
- "start": 21953
- },
- {
- "start": 21958,
- "end": 22002
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 22006,
- "tag_type": 1,
- "start": 22002
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/316/402/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 22087,
- "tag_type": 1,
- "start": 22006
- },
- {
- "start": 22087,
- "end": 22094
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 22098,
- "tag_type": 2,
- "start": 22094
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 22103,
- "tag_type": 2,
- "start": 22098
- },
- {
- "start": 22103,
- "end": 22147
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 22151,
- "tag_type": 1,
- "start": 22147
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/267/347/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 22232,
- "tag_type": 1,
- "start": 22151
- },
- {
- "start": 22232,
- "end": 22244
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 22248,
- "tag_type": 2,
- "start": 22244
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 22253,
- "tag_type": 2,
- "start": 22248
- },
- {
- "start": 22253,
- "end": 22297
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 22301,
- "tag_type": 1,
- "start": 22297
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/996/1241/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 22383,
- "tag_type": 1,
- "start": 22301
- },
- {
- "start": 22383,
- "end": 22389
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 22393,
- "tag_type": 2,
- "start": 22389
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 22398,
- "tag_type": 2,
- "start": 22393
- },
- {
- "start": 22398,
- "end": 22442
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 22446,
- "tag_type": 1,
- "start": 22442
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/271/351/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 22527,
- "tag_type": 1,
- "start": 22446
- },
- {
- "start": 22527,
- "end": 22537
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 22541,
- "tag_type": 2,
- "start": 22537
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 22546,
- "tag_type": 2,
- "start": 22541
- },
- {
- "start": 22546,
- "end": 22590
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 22594,
- "tag_type": 1,
- "start": 22590
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/988/1236/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 22676,
- "tag_type": 1,
- "start": 22594
- },
- {
- "start": 22676,
- "end": 22696
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 22700,
- "tag_type": 2,
- "start": 22696
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 22705,
- "tag_type": 2,
- "start": 22700
- },
- {
- "start": 22705,
- "end": 22749
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 22754,
- "tag_type": 2,
- "start": 22749
- },
- {
- "start": 22754,
- "end": 22782
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 22787,
- "tag_type": 2,
- "start": 22782
- },
- {
- "start": 22787,
- "end": 22799
- },
- {
- "attributes": {
- "id": "nav_pcsh"
- },
- "tag": "li",
- "end": 22817,
- "tag_type": 1,
- "start": 22799
- },
- {
- "start": 22817,
- "end": 22829
- },
- {
- "attributes": {
- "href": "/PC/PCs/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 22866,
- "tag_type": 1,
- "start": 22829
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 22872,
- "tag_type": 1,
- "start": 22866
- },
- {
- "start": 22872,
- "end": 22881
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 22888,
- "tag_type": 2,
- "start": 22881
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 22892,
- "tag_type": 2,
- "start": 22888
- },
- {
- "start": 22892,
- "end": 22932
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 22936,
- "tag_type": 1,
- "start": 22932
- },
- {
- "start": 22936,
- "end": 22980
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 22984,
- "tag_type": 1,
- "start": 22980
- },
- {
- "attributes": {
- "href": "/PC/PCs/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 23021,
- "tag_type": 1,
- "start": 22984
- },
- {
- "start": 23021,
- "end": 23025
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 23029,
- "tag_type": 2,
- "start": 23025
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 23034,
- "tag_type": 2,
- "start": 23029
- },
- {
- "start": 23034,
- "end": 23078
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 23082,
- "tag_type": 1,
- "start": 23078
- },
- {
- "attributes": {
- "href": "/PC/PCs/-/653/860/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 23146,
- "tag_type": 1,
- "start": 23082
- },
- {
- "start": 23146,
- "end": 23155
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 23159,
- "tag_type": 2,
- "start": 23155
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 23164,
- "tag_type": 2,
- "start": 23159
- },
- {
- "start": 23164,
- "end": 23208
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 23212,
- "tag_type": 1,
- "start": 23208
- },
- {
- "attributes": {
- "href": "/PC/PCs/-/654/861/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 23276,
- "tag_type": 1,
- "start": 23212
- },
- {
- "start": 23276,
- "end": 23283
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 23287,
- "tag_type": 2,
- "start": 23283
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 23292,
- "tag_type": 2,
- "start": 23287
- },
- {
- "start": 23292,
- "end": 23336
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 23340,
- "tag_type": 1,
- "start": 23336
- },
- {
- "attributes": {
- "href": "/PC/PCs/-/707/915/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 23404,
- "tag_type": 1,
- "start": 23340
- },
- {
- "start": 23404,
- "end": 23407
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 23411,
- "tag_type": 2,
- "start": 23407
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 23416,
- "tag_type": 2,
- "start": 23411
- },
- {
- "start": 23416,
- "end": 23460
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 23464,
- "tag_type": 1,
- "start": 23460
- },
- {
- "attributes": {
- "href": "/PC/PCs/-/684/891/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 23528,
- "tag_type": 1,
- "start": 23464
- },
- {
- "start": 23528,
- "end": 23536
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 23540,
- "tag_type": 2,
- "start": 23536
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 23545,
- "tag_type": 2,
- "start": 23540
- },
- {
- "start": 23545,
- "end": 23589
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 23593,
- "tag_type": 1,
- "start": 23589
- },
- {
- "attributes": {
- "href": "/PC/PCs/-/713/921/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 23657,
- "tag_type": 1,
- "start": 23593
- },
- {
- "start": 23657,
- "end": 23668
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 23672,
- "tag_type": 2,
- "start": 23668
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 23677,
- "tag_type": 2,
- "start": 23672
- },
- {
- "start": 23677,
- "end": 23721
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 23725,
- "tag_type": 1,
- "start": 23721
- },
- {
- "attributes": {
- "href": "/PC/PCs/-/667/874/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 23789,
- "tag_type": 1,
- "start": 23725
- },
- {
- "start": 23789,
- "end": 23799
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 23803,
- "tag_type": 2,
- "start": 23799
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 23808,
- "tag_type": 2,
- "start": 23803
- },
- {
- "start": 23808,
- "end": 23852
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 23856,
- "tag_type": 1,
- "start": 23852
- },
- {
- "attributes": {
- "href": "/PC/PCs/-/2144/1411/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 23922,
- "tag_type": 1,
- "start": 23856
- },
- {
- "start": 23922,
- "end": 23947
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 23951,
- "tag_type": 2,
- "start": 23947
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 23956,
- "tag_type": 2,
- "start": 23951
- },
- {
- "start": 23956,
- "end": 24000
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 24004,
- "tag_type": 1,
- "start": 24000
- },
- {
- "attributes": {
- "href": "/PC/PCs/-/660/867/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 24068,
- "tag_type": 1,
- "start": 24004
- },
- {
- "start": 24068,
- "end": 24078
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 24082,
- "tag_type": 2,
- "start": 24078
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 24087,
- "tag_type": 2,
- "start": 24082
- },
- {
- "start": 24087,
- "end": 24131
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 24135,
- "tag_type": 1,
- "start": 24131
- },
- {
- "attributes": {
- "href": "/PC/PCs/-/2159/1426/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 24201,
- "tag_type": 1,
- "start": 24135
- },
- {
- "start": 24201,
- "end": 24207
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 24211,
- "tag_type": 2,
- "start": 24207
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 24216,
- "tag_type": 2,
- "start": 24211
- },
- {
- "start": 24216,
- "end": 24260
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 24264,
- "tag_type": 1,
- "start": 24260
- },
- {
- "attributes": {
- "href": "/PC/PCs/-/677/884/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 24328,
- "tag_type": 1,
- "start": 24264
- },
- {
- "start": 24328,
- "end": 24336
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 24340,
- "tag_type": 2,
- "start": 24336
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 24345,
- "tag_type": 2,
- "start": 24340
- },
- {
- "start": 24345,
- "end": 24389
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 24393,
- "tag_type": 1,
- "start": 24389
- },
- {
- "attributes": {
- "href": "/PC/PCs/6-/Campaign.html?campaign=4661&cid=4083104"
- },
- "tag": "a",
- "end": 24458,
- "tag_type": 1,
- "start": 24393
- },
- {
- "start": 24458,
- "end": 24476
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 24480,
- "tag_type": 2,
- "start": 24476
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 24485,
- "tag_type": 2,
- "start": 24480
- },
- {
- "start": 24485,
- "end": 24529
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 24533,
- "tag_type": 1,
- "start": 24529
- },
- {
- "attributes": {
- "href": "/PC/PCs/-/989/1237/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 24598,
- "tag_type": 1,
- "start": 24533
- },
- {
- "start": 24598,
- "end": 24609
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 24613,
- "tag_type": 2,
- "start": 24609
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 24618,
- "tag_type": 2,
- "start": 24613
- },
- {
- "start": 24618,
- "end": 24662
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 24666,
- "tag_type": 1,
- "start": 24662
- },
- {
- "attributes": {
- "href": "/PC/PCs/-/694/901/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 24730,
- "tag_type": 1,
- "start": 24666
- },
- {
- "start": 24730,
- "end": 24741
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 24745,
- "tag_type": 2,
- "start": 24741
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 24750,
- "tag_type": 2,
- "start": 24745
- },
- {
- "start": 24750,
- "end": 24794
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 24799,
- "tag_type": 2,
- "start": 24794
- },
- {
- "start": 24799,
- "end": 24827
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 24832,
- "tag_type": 2,
- "start": 24827
- },
- {
- "start": 24832,
- "end": 24844
- },
- {
- "attributes": {
- "id": "nav_gadg"
- },
- "tag": "li",
- "end": 24862,
- "tag_type": 1,
- "start": 24844
- },
- {
- "start": 24862,
- "end": 24874
- },
- {
- "attributes": {
- "href": "/Gadgets/Gadgets/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 24920,
- "tag_type": 1,
- "start": 24874
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 24926,
- "tag_type": 1,
- "start": 24920
- },
- {
- "start": 24926,
- "end": 24933
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 24940,
- "tag_type": 2,
- "start": 24933
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 24944,
- "tag_type": 2,
- "start": 24940
- },
- {
- "start": 24944,
- "end": 24984
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 24988,
- "tag_type": 1,
- "start": 24984
- },
- {
- "start": 24988,
- "end": 25032
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 25036,
- "tag_type": 1,
- "start": 25032
- },
- {
- "attributes": {
- "href": "/Gadgets/Gadgets/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 25082,
- "tag_type": 1,
- "start": 25036
- },
- {
- "start": 25082,
- "end": 25086
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 25090,
- "tag_type": 2,
- "start": 25086
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 25095,
- "tag_type": 2,
- "start": 25090
- },
- {
- "start": 25095,
- "end": 25139
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 25143,
- "tag_type": 1,
- "start": 25139
- },
- {
- "attributes": {
- "href": "/Gadgets/Gadgets/-/392/492/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 25216,
- "tag_type": 1,
- "start": 25143
- },
- {
- "start": 25216,
- "end": 25232
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 25236,
- "tag_type": 2,
- "start": 25232
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 25241,
- "tag_type": 2,
- "start": 25236
- },
- {
- "start": 25241,
- "end": 25285
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 25289,
- "tag_type": 1,
- "start": 25285
- },
- {
- "attributes": {
- "href": "/Gadgets/Gadgets/-/558/743/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 25362,
- "tag_type": 1,
- "start": 25289
- },
- {
- "start": 25362,
- "end": 25369
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 25373,
- "tag_type": 2,
- "start": 25369
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 25378,
- "tag_type": 2,
- "start": 25373
- },
- {
- "start": 25378,
- "end": 25422
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 25426,
- "tag_type": 1,
- "start": 25422
- },
- {
- "attributes": {
- "href": "/Gadgets/Gadgets/-/434/534/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 25499,
- "tag_type": 1,
- "start": 25426
- },
- {
- "start": 25499,
- "end": 25520
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 25524,
- "tag_type": 2,
- "start": 25520
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 25529,
- "tag_type": 2,
- "start": 25524
- },
- {
- "start": 25529,
- "end": 25573
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 25577,
- "tag_type": 1,
- "start": 25573
- },
- {
- "attributes": {
- "href": "/Gadgets/Gadgets/-/382/482/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 25650,
- "tag_type": 1,
- "start": 25577
- },
- {
- "start": 25650,
- "end": 25660
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 25664,
- "tag_type": 2,
- "start": 25660
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 25669,
- "tag_type": 2,
- "start": 25664
- },
- {
- "start": 25669,
- "end": 25713
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 25717,
- "tag_type": 1,
- "start": 25713
- },
- {
- "attributes": {
- "href": "/Gadgets/Gadgets/-/372/472/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 25790,
- "tag_type": 1,
- "start": 25717
- },
- {
- "start": 25790,
- "end": 25803
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 25807,
- "tag_type": 2,
- "start": 25803
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 25812,
- "tag_type": 2,
- "start": 25807
- },
- {
- "start": 25812,
- "end": 25856
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 25860,
- "tag_type": 1,
- "start": 25856
- },
- {
- "attributes": {
- "href": "/Gadgets/Gadgets/-/440/540/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 25933,
- "tag_type": 1,
- "start": 25860
- },
- {
- "start": 25933,
- "end": 25944
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 25948,
- "tag_type": 2,
- "start": 25944
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 25953,
- "tag_type": 2,
- "start": 25948
- },
- {
- "start": 25953,
- "end": 25997
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 26001,
- "tag_type": 1,
- "start": 25997
- },
- {
- "attributes": {
- "href": "/Gadgets/Gadgets/-/415/515/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 26074,
- "tag_type": 1,
- "start": 26001
- },
- {
- "start": 26074,
- "end": 26091
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 26095,
- "tag_type": 2,
- "start": 26091
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 26100,
- "tag_type": 2,
- "start": 26095
- },
- {
- "start": 26100,
- "end": 26144
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 26148,
- "tag_type": 1,
- "start": 26144
- },
- {
- "attributes": {
- "href": "/Gadgets/Gadgets/-/411/511/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 26221,
- "tag_type": 1,
- "start": 26148
- },
- {
- "start": 26221,
- "end": 26241
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 26245,
- "tag_type": 2,
- "start": 26241
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 26250,
- "tag_type": 2,
- "start": 26245
- },
- {
- "start": 26250,
- "end": 26294
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 26298,
- "tag_type": 1,
- "start": 26294
- },
- {
- "attributes": {
- "href": "/Gadgets/Gadgets/-/401/501/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 26371,
- "tag_type": 1,
- "start": 26298
- },
- {
- "start": 26371,
- "end": 26376
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 26380,
- "tag_type": 2,
- "start": 26376
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 26385,
- "tag_type": 2,
- "start": 26380
- },
- {
- "start": 26385,
- "end": 26429
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 26433,
- "tag_type": 1,
- "start": 26429
- },
- {
- "attributes": {
- "href": "/Gadgets/Gadgets/-/426/526/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 26506,
- "tag_type": 1,
- "start": 26433
- },
- {
- "start": 26506,
- "end": 26510
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 26514,
- "tag_type": 2,
- "start": 26510
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 26519,
- "tag_type": 2,
- "start": 26514
- },
- {
- "start": 26519,
- "end": 26563
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 26568,
- "tag_type": 2,
- "start": 26563
- },
- {
- "start": 26568,
- "end": 26596
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 26601,
- "tag_type": 2,
- "start": 26596
- },
- {
- "start": 26601,
- "end": 26613
- },
- {
- "attributes": {
- "id": "nav_mbls"
- },
- "tag": "li",
- "end": 26631,
- "tag_type": 1,
- "start": 26613
- },
- {
- "start": 26631,
- "end": 26643
- },
- {
- "attributes": {
- "href": "/Mobiles/Mobile/6-/MobileHome.html"
- },
- "tag": "a",
- "end": 26688,
- "tag_type": 1,
- "start": 26643
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 26694,
- "tag_type": 1,
- "start": 26688
- },
- {
- "start": 26694,
- "end": 26700
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 26707,
- "tag_type": 2,
- "start": 26700
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 26711,
- "tag_type": 2,
- "start": 26707
- },
- {
- "start": 26711,
- "end": 26751
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 26755,
- "tag_type": 1,
- "start": 26751
- },
- {
- "start": 26755,
- "end": 26799
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 26803,
- "tag_type": 1,
- "start": 26799
- },
- {
- "attributes": {
- "href": "/Mobiles/Mobile/6-/MobileHome.html"
- },
- "tag": "a",
- "end": 26848,
- "tag_type": 1,
- "start": 26803
- },
- {
- "start": 26848,
- "end": 26852
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 26856,
- "tag_type": 2,
- "start": 26852
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 26861,
- "tag_type": 2,
- "start": 26856
- },
- {
- "start": 26861,
- "end": 26905
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 26909,
- "tag_type": 1,
- "start": 26905
- },
- {
- "attributes": {
- "href": "/Mobiles/Mobile/-/529/686/3-/HardwareHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 26983,
- "tag_type": 1,
- "start": 26909
- },
- {
- "start": 26983,
- "end": 26997
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 27001,
- "tag_type": 2,
- "start": 26997
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 27006,
- "tag_type": 2,
- "start": 27001
- },
- {
- "start": 27006,
- "end": 27050
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 27054,
- "tag_type": 1,
- "start": 27050
- },
- {
- "attributes": {
- "href": "/Mobiles/Mobile/-/530/687/3-/HardwareHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 27128,
- "tag_type": 1,
- "start": 27054
- },
- {
- "start": 27128,
- "end": 27143
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 27147,
- "tag_type": 2,
- "start": 27143
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 27152,
- "tag_type": 2,
- "start": 27147
- },
- {
- "start": 27152,
- "end": 27196
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 27200,
- "tag_type": 1,
- "start": 27196
- },
- {
- "attributes": {
- "href": "/Mobiles/Mobile/-/1020/1265/3-/HardwareBrowse.html?searchtype=genre"
- },
- "tag": "a",
- "end": 27278,
- "tag_type": 1,
- "start": 27200
- },
- {
- "start": 27278,
- "end": 27288
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 27292,
- "tag_type": 2,
- "start": 27288
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 27297,
- "tag_type": 2,
- "start": 27292
- },
- {
- "start": 27297,
- "end": 27341
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 27345,
- "tag_type": 1,
- "start": 27341
- },
- {
- "attributes": {
- "href": "/Mobiles/Mobile/-/531/688/3-/HardwareHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 27419,
- "tag_type": 1,
- "start": 27345
- },
- {
- "start": 27419,
- "end": 27430
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 27434,
- "tag_type": 2,
- "start": 27430
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 27439,
- "tag_type": 2,
- "start": 27434
- },
- {
- "start": 27439,
- "end": 27483
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 27487,
- "tag_type": 1,
- "start": 27483
- },
- {
- "attributes": {
- "href": "/Mobiles/Mobile/-/526/683/3-/MobileContent.html?searchtype=genre"
- },
- "tag": "a",
- "end": 27562,
- "tag_type": 1,
- "start": 27487
- },
- {
- "start": 27562,
- "end": 27576
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 27580,
- "tag_type": 2,
- "start": 27576
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 27585,
- "tag_type": 2,
- "start": 27580
- },
- {
- "start": 27585,
- "end": 27629
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 27634,
- "tag_type": 2,
- "start": 27629
- },
- {
- "start": 27634,
- "end": 27662
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 27667,
- "tag_type": 2,
- "start": 27662
- },
- {
- "start": 27667,
- "end": 27679
- },
- {
- "attributes": {
- "id": "Li2"
- },
- "tag": "li",
- "end": 27692,
- "tag_type": 1,
- "start": 27679
- },
- {
- "start": 27692,
- "end": 27704
- },
- {
- "attributes": {
- "href": "/HOME/HOME/6-/LandingPage.html?page=playtrade"
- },
- "tag": "a",
- "end": 27760,
- "tag_type": 1,
- "start": 27704
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 27766,
- "tag_type": 1,
- "start": 27760
- },
- {
- "start": 27766,
- "end": 27781
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 27788,
- "tag_type": 2,
- "start": 27781
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 27792,
- "tag_type": 2,
- "start": 27788
- },
- {
- "start": 27792,
- "end": 27832
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 27836,
- "tag_type": 1,
- "start": 27832
- },
- {
- "start": 27836,
- "end": 27880
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 27884,
- "tag_type": 1,
- "start": 27880
- },
- {
- "attributes": {
- "href": "/landingpage.aspx?page=playtrade&dpr=0&dpr=0&dpr=0&product=dvd"
- },
- "tag": "a",
- "end": 27973,
- "tag_type": 1,
- "start": 27884
- },
- {
- "start": 27973,
- "end": 27987
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 27991,
- "tag_type": 2,
- "start": 27987
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 27996,
- "tag_type": 2,
- "start": 27991
- },
- {
- "start": 27996,
- "end": 28040
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 28044,
- "tag_type": 1,
- "start": 28040
- },
- {
- "attributes": {
- "href": "/landingpage.aspx?page=playtrade&dpr=0&dpr=0&dpr=0&product=cd"
- },
- "tag": "a",
- "end": 28132,
- "tag_type": 1,
- "start": 28044
- },
- {
- "start": 28132,
- "end": 28145
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 28149,
- "tag_type": 2,
- "start": 28145
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 28154,
- "tag_type": 2,
- "start": 28149
- },
- {
- "start": 28154,
- "end": 28198
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 28202,
- "tag_type": 1,
- "start": 28198
- },
- {
- "attributes": {
- "href": "/landingpage.aspx?page=playtrade&dpr=0&dpr=0&dpr=0&product=game"
- },
- "tag": "a",
- "end": 28292,
- "tag_type": 1,
- "start": 28202
- },
- {
- "start": 28292,
- "end": 28307
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 28311,
- "tag_type": 2,
- "start": 28307
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 28316,
- "tag_type": 2,
- "start": 28311
- },
- {
- "start": 28316,
- "end": 28360
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 28364,
- "tag_type": 1,
- "start": 28360
- },
- {
- "attributes": {
- "href": "/landingpage.aspx?page=playtrade&dpr=0&dpr=0&dpr=0&product=book"
- },
- "tag": "a",
- "end": 28454,
- "tag_type": 1,
- "start": 28364
- },
- {
- "start": 28454,
- "end": 28469
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 28473,
- "tag_type": 2,
- "start": 28469
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 28478,
- "tag_type": 2,
- "start": 28473
- },
- {
- "start": 28478,
- "end": 28522
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 28526,
- "tag_type": 1,
- "start": 28522
- },
- {
- "attributes": {
- "href": "/landingpage.aspx?page=playtrade&dpr=0&dpr=0&dpr=0&product=ticket"
- },
- "tag": "a",
- "end": 28618,
- "tag_type": 1,
- "start": 28526
- },
- {
- "start": 28618,
- "end": 28635
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 28639,
- "tag_type": 2,
- "start": 28635
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 28644,
- "tag_type": 2,
- "start": 28639
- },
- {
- "start": 28644,
- "end": 28688
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 28692,
- "tag_type": 1,
- "start": 28688
- },
- {
- "attributes": {
- "href": "/landingpage.aspx?page=playtrade&dpr=0&dpr=0&dpr=0&product=console"
- },
- "tag": "a",
- "end": 28785,
- "tag_type": 1,
- "start": 28692
- },
- {
- "start": 28785,
- "end": 28803
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 28807,
- "tag_type": 2,
- "start": 28803
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 28812,
- "tag_type": 2,
- "start": 28807
- },
- {
- "start": 28812,
- "end": 28856
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 28861,
- "tag_type": 2,
- "start": 28856
- },
- {
- "start": 28861,
- "end": 28889
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 28894,
- "tag_type": 2,
- "start": 28889
- },
- {
- "start": 28894,
- "end": 28910
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 28915,
- "tag_type": 2,
- "start": 28910
- },
- {
- "start": 28915,
- "end": 28924
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 28930,
- "tag_type": 2,
- "start": 28924
- },
- {
- "start": 28930,
- "end": 28934
- },
- {
- "attributes": {
- "id": "nav_submenu_contain"
- },
- "tag": "div",
- "end": 28964,
- "tag_type": 1,
- "start": 28934
- },
- {
- "start": 28964,
- "end": 28980
- },
- {
- "attributes": {
- "id": "nav_submenu"
- },
- "tag": "ul",
- "end": 29001,
- "tag_type": 1,
- "start": 28980
- },
- {
- "start": 29001,
- "end": 29021
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 29025,
- "tag_type": 1,
- "start": 29021
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 29079,
- "tag_type": 1,
- "start": 29025
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 29085,
- "tag_type": 1,
- "start": 29079
- },
- {
- "start": 29085,
- "end": 29089
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 29096,
- "tag_type": 2,
- "start": 29089
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 29100,
- "tag_type": 2,
- "start": 29096
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 29105,
- "tag_type": 2,
- "start": 29100
- },
- {
- "start": 29105,
- "end": 29125
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 29129,
- "tag_type": 1,
- "start": 29125
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/3-/RegionHome.html?searchtype=genre",
- "class": "this"
- },
- "tag": "a",
- "end": 29223,
- "tag_type": 1,
- "start": 29129
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 29229,
- "tag_type": 1,
- "start": 29223
- },
- {
- "start": 29229,
- "end": 29240
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 29247,
- "tag_type": 2,
- "start": 29240
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 29251,
- "tag_type": 2,
- "start": 29247
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 29256,
- "tag_type": 2,
- "start": 29251
- },
- {
- "start": 29256,
- "end": 29276
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 29280,
- "tag_type": 1,
- "start": 29276
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/291/375/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 29361,
- "tag_type": 1,
- "start": 29280
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 29367,
- "tag_type": 1,
- "start": 29361
- },
- {
- "start": 29367,
- "end": 29390
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 29397,
- "tag_type": 2,
- "start": 29390
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 29401,
- "tag_type": 2,
- "start": 29397
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 29406,
- "tag_type": 2,
- "start": 29401
- },
- {
- "start": 29406,
- "end": 29426
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 29430,
- "tag_type": 1,
- "start": 29426
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/2168/1435/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 29513,
- "tag_type": 1,
- "start": 29430
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 29519,
- "tag_type": 1,
- "start": 29513
- },
- {
- "start": 29519,
- "end": 29527
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 29534,
- "tag_type": 2,
- "start": 29527
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 29538,
- "tag_type": 2,
- "start": 29534
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 29543,
- "tag_type": 2,
- "start": 29538
- },
- {
- "start": 29543,
- "end": 29563
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 29567,
- "tag_type": 1,
- "start": 29563
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/261/341/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 29648,
- "tag_type": 1,
- "start": 29567
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 29654,
- "tag_type": 1,
- "start": 29648
- },
- {
- "start": 29654,
- "end": 29679
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 29686,
- "tag_type": 2,
- "start": 29679
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 29690,
- "tag_type": 2,
- "start": 29686
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 29695,
- "tag_type": 2,
- "start": 29690
- },
- {
- "start": 29695,
- "end": 29715
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 29719,
- "tag_type": 1,
- "start": 29715
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/256/336/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 29800,
- "tag_type": 1,
- "start": 29719
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 29806,
- "tag_type": 1,
- "start": 29800
- },
- {
- "start": 29806,
- "end": 29821
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 29828,
- "tag_type": 2,
- "start": 29821
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 29832,
- "tag_type": 2,
- "start": 29828
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 29837,
- "tag_type": 2,
- "start": 29832
- },
- {
- "start": 29837,
- "end": 29857
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 29861,
- "tag_type": 1,
- "start": 29857
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/281/363/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 29942,
- "tag_type": 1,
- "start": 29861
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 29948,
- "tag_type": 1,
- "start": 29942
- },
- {
- "start": 29948,
- "end": 29959
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 29966,
- "tag_type": 2,
- "start": 29959
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 29970,
- "tag_type": 2,
- "start": 29966
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 29975,
- "tag_type": 2,
- "start": 29970
- },
- {
- "start": 29975,
- "end": 29995
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 29999,
- "tag_type": 1,
- "start": 29995
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/267/347/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 30080,
- "tag_type": 1,
- "start": 29999
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 30086,
- "tag_type": 1,
- "start": 30080
- },
- {
- "start": 30086,
- "end": 30098
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 30105,
- "tag_type": 2,
- "start": 30098
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 30109,
- "tag_type": 2,
- "start": 30105
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 30114,
- "tag_type": 2,
- "start": 30109
- },
- {
- "start": 30114,
- "end": 30134
- },
- {
- "attributes": {
- "class": "endlink"
- },
- "tag": "li",
- "end": 30154,
- "tag_type": 1,
- "start": 30134
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/271/351/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 30235,
- "tag_type": 1,
- "start": 30154
- },
- {
- "attributes": {
- "class": "mydeco-selected"
- },
- "tag": "span",
- "end": 30265,
- "tag_type": 1,
- "start": 30235
- },
- {
- "start": 30265,
- "end": 30275
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 30282,
- "tag_type": 2,
- "start": 30275
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 30286,
- "tag_type": 2,
- "start": 30282
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 30291,
- "tag_type": 2,
- "start": 30286
- },
- {
- "start": 30291,
- "end": 30311
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 30316,
- "tag_type": 2,
- "start": 30311
- },
- {
- "start": 30316,
- "end": 30324
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 30330,
- "tag_type": 2,
- "start": 30324
- },
- {
- "attributes": {},
- "tag": "cite",
- "end": 30336,
- "tag_type": 1,
- "start": 30330
- },
- {
- "attributes": {},
- "tag": "cite",
- "end": 30343,
- "tag_type": 2,
- "start": 30336
- },
- {
- "start": 30343,
- "end": 30347
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 30353,
- "tag_type": 2,
- "start": 30347
- },
- {
- "start": 30353,
- "end": 30357
- },
- {
- "attributes": {
- "type": "text/javascript",
- "language": "JavaScript"
- },
- "tag": "script",
- "end": 30410,
- "tag_type": 1,
- "start": 30357
- },
- {
- "start": 30410,
- "end": 30920
- },
- {
- "attributes": {},
- "tag": "script",
- "end": 30929,
- "tag_type": 2,
- "start": 30920
- },
- {
- "start": 30929,
- "end": 30933
- },
- {
- "attributes": {
- "id": "contentContainer"
- },
- "tag": "div",
- "end": 30960,
- "tag_type": 1,
- "start": 30933
- },
- {
- "start": 30960,
- "end": 30968
- },
- {
- "attributes": {
- "class": "outer"
- },
- "tag": "div",
- "end": 30987,
- "tag_type": 1,
- "start": 30968
- },
- {
- "start": 30987,
- "end": 30999
- },
- {
- "attributes": {
- "class": "inner"
- },
- "tag": "div",
- "end": 31018,
- "tag_type": 1,
- "start": 30999
- },
- {
- "start": 31018,
- "end": 31034
- },
- {
- "attributes": {
- "class": "floatWrap"
- },
- "tag": "div",
- "end": 31057,
- "tag_type": 1,
- "start": 31034
- },
- {
- "start": 31057,
- "end": 31077
- },
- {
- "attributes": {
- "id": "middleCol"
- },
- "tag": "div",
- "end": 31097,
- "tag_type": 1,
- "start": 31077
- },
- {
- "start": 31097,
- "end": 31145
- },
- {
- "attributes": {
- "class": "content"
- },
- "tag": "div",
- "end": 31166,
- "tag_type": 1,
- "start": 31145
- },
- {
- "start": 31166,
- "end": 31198
- },
- {
- "attributes": {
- "class": "electronics wrap"
- },
- "tag": "div",
- "end": 31228,
- "tag_type": 1,
- "start": 31198
- },
- {
- "attributes": {
- "class": "boxhead"
- },
- "tag": "div",
- "end": 31249,
- "tag_type": 1,
- "start": 31228
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 31254,
- "tag_type": 1,
- "start": 31249
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 31259,
- "tag_type": 1,
- "start": 31254
- },
- {
- "attributes": {
- "class": "pagehead"
- },
- "tag": "h2",
- "end": 31280,
- "tag_type": 1,
- "start": 31259
- },
- {
- "start": 31280,
- "end": 31291
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 31296,
- "tag_type": 2,
- "start": 31291
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 31302,
- "tag_type": 2,
- "start": 31296
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 31308,
- "tag_type": 2,
- "start": 31302
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 31314,
- "tag_type": 2,
- "start": 31308
- },
- {
- "attributes": {
- "class": "box"
- },
- "tag": "div",
- "end": 31331,
- "tag_type": 1,
- "start": 31314
- },
- {
- "attributes": {
- "class": "product-2 slice top"
- },
- "tag": "div",
- "end": 31364,
- "tag_type": 1,
- "start": 31331
- },
- {
- "attributes": {
- "cellspacing": "0"
- },
- "tag": "table",
- "end": 31387,
- "tag_type": 1,
- "start": 31364
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 31394,
- "tag_type": 1,
- "start": 31387
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 31398,
- "tag_type": 1,
- "start": 31394
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 31402,
- "tag_type": 1,
- "start": 31398
- },
- {
- "attributes": {
- "class": "image"
- },
- "tag": "div",
- "end": 31421,
- "tag_type": 1,
- "start": 31402
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 31424,
- "tag_type": 1,
- "start": 31421
- },
- {
- "attributes": {
- "src": "http://images.play.com/covers/8986420m.jpg",
- "style": "border-width: 0px; height: 170px; width: 170px;",
- "onerror": null,
- "data-scrapy-annotate": "{"variant": 0, "annotations": {"src": "image_urls"}}",
- "alt": "Samsung Series 5 550 37" LE37B550 / HD 1080p / Freeview / LCD TV (Black)",
- "id": "anonymous_element_1"
- },
- "tag": "img",
- "end": 31770,
- "tag_type": 1,
- "start": 31424
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 31774,
- "tag_type": 2,
- "start": 31770
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 31780,
- "tag_type": 2,
- "start": 31774
- },
- {
- "attributes": {
- "class": "action"
- },
- "tag": "div",
- "end": 31800,
- "tag_type": 1,
- "start": 31780
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 31806,
- "tag_type": 2,
- "start": 31800
- },
- {
- "attributes": {
- "class": "action"
- },
- "tag": "div",
- "end": 31826,
- "tag_type": 1,
- "start": 31806
- },
- {
- "start": 31826,
- "end": 31830
- },
- {
- "attributes": {
- "href": "#",
- "onclick": null
- },
- "tag": "a",
- "end": 31853,
- "tag_type": 1,
- "start": 31830
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteCSS/Play/Live1/img/button/enlargeimage.gif",
- "alt": "Enlarge Image",
- "style": "border-width: 0px; height: 17px; width: 99px;"
- },
- "tag": "img",
- "end": 32008,
- "tag_type": 1,
- "start": 31853
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 32012,
- "tag_type": 2,
- "start": 32008
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 32018,
- "tag_type": 2,
- "start": 32012
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 32023,
- "tag_type": 2,
- "start": 32018
- },
- {
- "attributes": {
- "class": "wide"
- },
- "tag": "td",
- "end": 32040,
- "tag_type": 1,
- "start": 32023
- },
- {
- "attributes": {
- "class": "info"
- },
- "tag": "div",
- "end": 32058,
- "tag_type": 1,
- "start": 32040
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 32063,
- "tag_type": 1,
- "start": 32058
- },
- {
- "attributes": {
- "data-scrapy-annotate": "{"variant": 0, "annotations": {"content": "name"}}",
- "id": "anonymous_element_2"
- },
- "tag": "h1",
- "end": 32206,
- "tag_type": 1,
- "start": 32063
- },
- {
- "start": 32206,
- "end": 32278
- },
- {
- "attributes": {},
- "tag": "h1",
- "end": 32283,
- "tag_type": 2,
- "start": 32278
- },
- {
- "attributes": {
- "class": "artist"
- },
- "tag": "p",
- "end": 32301,
- "tag_type": 1,
- "start": 32283
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 32305,
- "tag_type": 2,
- "start": 32301
- },
- {
- "attributes": {
- "alt": "Customer rating on Samsung Series 5 550 37" LE37B550 / HD 1080p / Freeview / LCD TV (Black): 5 out of 5 stars",
- "class": "rating"
- },
- "tag": "p",
- "end": 32444,
- "tag_type": 1,
- "start": 32305
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteCSS/Play/Live1/img/spaces/stars50.gif",
- "style": "border-width: 0px; height: 14px; width: 71px;",
- "class": null
- },
- "tag": "img",
- "end": 32583,
- "tag_type": 1,
- "start": 32444
- },
- {
- "start": 32583,
- "end": 32586
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/8986420/Samsung-Series-5-550-37-LE37B550-HD-1080p-Freeview-LCD-TV/ProductReviews.html",
- "title": "See all Samsung Series 5 550 37" LE37B550 / HD 1080p / Freeview / LCD TV (Black) reviews"
- },
- "tag": "a",
- "end": 32812,
- "tag_type": 1,
- "start": 32586
- },
- {
- "attributes": {
- "class": null
- },
- "tag": "strong",
- "end": 32829,
- "tag_type": 1,
- "start": 32812
- },
- {
- "start": 32829,
- "end": 32830
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 32839,
- "tag_type": 2,
- "start": 32830
- },
- {
- "start": 32839,
- "end": 32855
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 32859,
- "tag_type": 2,
- "start": 32855
- },
- {
- "start": 32859,
- "end": 32862
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 32866,
- "tag_type": 2,
- "start": 32862
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 32872,
- "tag_type": 2,
- "start": 32866
- },
- {
- "attributes": {
- "class": null
- },
- "tag": "div",
- "end": 32886,
- "tag_type": 1,
- "start": 32872
- },
- {
- "attributes": {
- "id": "_pageTemplate__product_ctl00__overview_ctl00__dataControl__price__headerSix"
- },
- "tag": "h6",
- "end": 32971,
- "tag_type": 1,
- "start": 32886
- },
- {
- "attributes": {
- "data-scrapy-annotate": "{"variant": 0, "annotations": {"content": "price"}}",
- "id": "anonymous_element_3",
- "class": null
- },
- "tag": "span",
- "end": 33126,
- "tag_type": 1,
- "start": 32971
- },
- {
- "start": 33126,
- "end": 33133
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 33140,
- "tag_type": 2,
- "start": 33133
- },
- {
- "start": 33140,
- "end": 33154
- },
- {
- "attributes": {},
- "tag": "h6",
- "end": 33159,
- "tag_type": 2,
- "start": 33154
- },
- {
- "attributes": {
- "class": "saving"
- },
- "tag": "p",
- "end": 33177,
- "tag_type": 1,
- "start": 33159
- },
- {
- "attributes": {
- "class": null
- },
- "tag": "span",
- "end": 33192,
- "tag_type": 1,
- "start": 33177
- },
- {
- "start": 33192,
- "end": 33197
- },
- {
- "attributes": {
- "class": null
- },
- "tag": "strong",
- "end": 33214,
- "tag_type": 1,
- "start": 33197
- },
- {
- "start": 33214,
- "end": 33221
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 33230,
- "tag_type": 2,
- "start": 33221
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 33237,
- "tag_type": 2,
- "start": 33230
- },
- {
- "start": 33237,
- "end": 33240
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 33246,
- "tag_type": 1,
- "start": 33240
- },
- {
- "start": 33246,
- "end": 33256
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 33264,
- "tag_type": 1,
- "start": 33256
- },
- {
- "start": 33264,
- "end": 33277
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 33286,
- "tag_type": 2,
- "start": 33277
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 33293,
- "tag_type": 2,
- "start": 33286
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 33297,
- "tag_type": 2,
- "start": 33293
- },
- {
- "attributes": {
- "class": "stock"
- },
- "tag": "p",
- "end": 33314,
- "tag_type": 1,
- "start": 33297
- },
- {
- "start": 33314,
- "end": 33318
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 33326,
- "tag_type": 1,
- "start": 33318
- },
- {
- "start": 33326,
- "end": 33334
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 33343,
- "tag_type": 2,
- "start": 33334
- },
- {
- "start": 33343,
- "end": 33347
- },
- {
- "attributes": {
- "class": null
- },
- "tag": "span",
- "end": 33362,
- "tag_type": 1,
- "start": 33347
- },
- {
- "start": 33362,
- "end": 33399
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 33406,
- "tag_type": 2,
- "start": 33399
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 33410,
- "tag_type": 2,
- "start": 33406
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 33416,
- "tag_type": 2,
- "start": 33410
- },
- {
- "attributes": {
- "class": "buy"
- },
- "tag": "div",
- "end": 33433,
- "tag_type": 1,
- "start": 33416
- },
- {
- "start": 33433,
- "end": 33454
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/-/8986420/Samsung-Series-5-550-37-LE37B550-HD-1080p-Freeview-LCD-TV/Product.html?searchtype=genre&add=8986420&pid=275282&dpr=275282",
- "class": "buy_button"
- },
- "tag": "a",
- "end": 33662,
- "tag_type": 1,
- "start": 33454
- },
- {
- "start": 33662,
- "end": 33665
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 33669,
- "tag_type": 2,
- "start": 33665
- },
- {
- "start": 33669,
- "end": 33689
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 33695,
- "tag_type": 2,
- "start": 33689
- },
- {
- "attributes": {
- "class": "badges"
- },
- "tag": "div",
- "end": 33715,
- "tag_type": 1,
- "start": 33695
- },
- {
- "attributes": {
- "class": null
- },
- "tag": "div",
- "end": 33729,
- "tag_type": 1,
- "start": 33715
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 33735,
- "tag_type": 2,
- "start": 33729
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 33741,
- "tag_type": 2,
- "start": 33735
- },
- {
- "attributes": {
- "class": "note-alt"
- },
- "tag": "p",
- "end": 33761,
- "tag_type": 1,
- "start": 33741
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 33765,
- "tag_type": 2,
- "start": 33761
- },
- {
- "attributes": {
- "class": "bogof"
- },
- "tag": "div",
- "end": 33784,
- "tag_type": 1,
- "start": 33765
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 33790,
- "tag_type": 2,
- "start": 33784
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 33796,
- "tag_type": 2,
- "start": 33790
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 33801,
- "tag_type": 2,
- "start": 33796
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 33806,
- "tag_type": 2,
- "start": 33801
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 33814,
- "tag_type": 2,
- "start": 33806
- },
- {
- "attributes": {},
- "tag": "table",
- "end": 33822,
- "tag_type": 2,
- "start": 33814
- },
- {
- "attributes": {
- "class": "trade-link-wrap"
- },
- "tag": "div",
- "end": 33851,
- "tag_type": 1,
- "start": 33822
- },
- {
- "attributes": {
- "class": "trade-link"
- },
- "tag": "div",
- "end": 33875,
- "tag_type": 1,
- "start": 33851
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 33880,
- "tag_type": 1,
- "start": 33875
- },
- {
- "attributes": {},
- "tag": "table",
- "end": 33887,
- "tag_type": 1,
- "start": 33880
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 33894,
- "tag_type": 1,
- "start": 33887
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 33898,
- "tag_type": 1,
- "start": 33894
- },
- {
- "attributes": {
- "class": "wide"
- },
- "tag": "td",
- "end": 33915,
- "tag_type": 1,
- "start": 33898
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 33918,
- "tag_type": 1,
- "start": 33915
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/8986420/Samsung-Series-5-550-37-LE37B550-HD-1080p-Freeview-LCD-TV/Product.html?ptsl=1&ob=Price&fb=0"
- },
- "tag": "a",
- "end": 34064,
- "tag_type": 1,
- "start": 33918
- },
- {
- "start": 34064,
- "end": 34088
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 34094,
- "tag_type": 1,
- "start": 34088
- },
- {
- "start": 34094,
- "end": 34108
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 34115,
- "tag_type": 2,
- "start": 34108
- },
- {
- "start": 34115,
- "end": 34121
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 34129,
- "tag_type": 1,
- "start": 34121
- },
- {
- "start": 34129,
- "end": 34136
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 34145,
- "tag_type": 2,
- "start": 34136
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 34149,
- "tag_type": 2,
- "start": 34145
- },
- {
- "attributes": {
- "href": "/HOME/HOME/6-/Help.html?page=TradeGeneralq",
- "class": "huh"
- },
- "tag": "a",
- "end": 34214,
- "tag_type": 1,
- "start": 34149
- },
- {
- "start": 34214,
- "end": 34235
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 34239,
- "tag_type": 2,
- "start": 34235
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 34243,
- "tag_type": 2,
- "start": 34239
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 34247,
- "tag_type": 1,
- "start": 34243
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 34251,
- "tag_type": 1,
- "start": 34247
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/8986420/Samsung-Series-5-550-37-LE37B550-HD-1080p-Freeview-LCD-TV/Product.html?ptsl=1&ob=Price&fb=1"
- },
- "tag": "a",
- "end": 34397,
- "tag_type": 1,
- "start": 34251
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 34403,
- "tag_type": 1,
- "start": 34397
- },
- {
- "start": 34403,
- "end": 34408
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 34415,
- "tag_type": 2,
- "start": 34408
- },
- {
- "start": 34415,
- "end": 34421
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 34429,
- "tag_type": 1,
- "start": 34421
- },
- {
- "start": 34429,
- "end": 34438
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 34447,
- "tag_type": 2,
- "start": 34438
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 34451,
- "tag_type": 2,
- "start": 34447
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 34456,
- "tag_type": 2,
- "start": 34451
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 34461,
- "tag_type": 2,
- "start": 34456
- },
- {
- "attributes": {
- "class": "more"
- },
- "tag": "div",
- "end": 34479,
- "tag_type": 1,
- "start": 34461
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 34485,
- "tag_type": 2,
- "start": 34479
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 34490,
- "tag_type": 2,
- "start": 34485
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 34495,
- "tag_type": 2,
- "start": 34490
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 34503,
- "tag_type": 2,
- "start": 34495
- },
- {
- "attributes": {},
- "tag": "table",
- "end": 34511,
- "tag_type": 2,
- "start": 34503
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 34517,
- "tag_type": 2,
- "start": 34511
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 34523,
- "tag_type": 2,
- "start": 34517
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 34529,
- "tag_type": 2,
- "start": 34523
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 34535,
- "tag_type": 2,
- "start": 34529
- },
- {
- "attributes": {
- "class": "linksave"
- },
- "tag": "div",
- "end": 34557,
- "tag_type": 1,
- "start": 34535
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 34562,
- "tag_type": 1,
- "start": 34557
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 34567,
- "tag_type": 1,
- "start": 34562
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 34572,
- "tag_type": 1,
- "start": 34567
- },
- {
- "attributes": {
- "class": "title"
- },
- "tag": "div",
- "end": 34591,
- "tag_type": 1,
- "start": 34572
- },
- {
- "attributes": {
- "cellspacing": "0"
- },
- "tag": "table",
- "end": 34614,
- "tag_type": 1,
- "start": 34591
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 34621,
- "tag_type": 1,
- "start": 34614
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 34625,
- "tag_type": 1,
- "start": 34621
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 34629,
- "tag_type": 1,
- "start": 34625
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 34634,
- "tag_type": 1,
- "start": 34629
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteCSS/Play/Live1/img/brand/promo_plus.gif",
- "style": "border-width: 0px;"
- },
- "tag": "img",
- "end": 34739,
- "tag_type": 1,
- "start": 34634
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 34745,
- "tag_type": 2,
- "start": 34739
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 34750,
- "tag_type": 2,
- "start": 34745
- },
- {
- "attributes": {
- "class": "wide"
- },
- "tag": "td",
- "end": 34767,
- "tag_type": 1,
- "start": 34750
- },
- {
- "attributes": {},
- "tag": "h1",
- "end": 34771,
- "tag_type": 1,
- "start": 34767
- },
- {
- "start": 34771,
- "end": 34790
- },
- {
- "attributes": {},
- "tag": "h1",
- "end": 34795,
- "tag_type": 2,
- "start": 34790
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 34798,
- "tag_type": 1,
- "start": 34795
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 34806,
- "tag_type": 1,
- "start": 34798
- },
- {
- "start": 34806,
- "end": 34859
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 34868,
- "tag_type": 2,
- "start": 34859
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 34872,
- "tag_type": 2,
- "start": 34868
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 34877,
- "tag_type": 2,
- "start": 34872
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 34881,
- "tag_type": 1,
- "start": 34877
- },
- {
- "attributes": {
- "class": "button"
- },
- "tag": "div",
- "end": 34901,
- "tag_type": 1,
- "start": 34881
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 34906,
- "tag_type": 1,
- "start": 34901
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 34911,
- "tag_type": 1,
- "start": 34906
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 34914,
- "tag_type": 1,
- "start": 34911
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/8986420/-/Product.html?sp=1&dpr=275282",
- "title": "Save 50% On This TV Stand When Purchased With This TV"
- },
- "tag": "a",
- "end": 35057,
- "tag_type": 1,
- "start": 34914
- },
- {
- "start": 35057,
- "end": 35067
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 35071,
- "tag_type": 2,
- "start": 35067
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 35075,
- "tag_type": 2,
- "start": 35071
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 35081,
- "tag_type": 2,
- "start": 35075
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 35087,
- "tag_type": 2,
- "start": 35081
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 35093,
- "tag_type": 2,
- "start": 35087
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 35098,
- "tag_type": 2,
- "start": 35093
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 35103,
- "tag_type": 2,
- "start": 35098
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 35111,
- "tag_type": 2,
- "start": 35103
- },
- {
- "attributes": {},
- "tag": "table",
- "end": 35119,
- "tag_type": 2,
- "start": 35111
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 35125,
- "tag_type": 2,
- "start": 35119
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 35131,
- "tag_type": 2,
- "start": 35125
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 35137,
- "tag_type": 2,
- "start": 35131
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 35143,
- "tag_type": 2,
- "start": 35137
- },
- {
- "attributes": {
- "class": "linknote"
- },
- "tag": "p",
- "end": 35163,
- "tag_type": 1,
- "start": 35143
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 35167,
- "tag_type": 2,
- "start": 35163
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 35173,
- "tag_type": 2,
- "start": 35167
- },
- {
- "start": 35173,
- "end": 35177
- },
- {
- "attributes": {
- "class": "subhead"
- },
- "tag": "div",
- "end": 35198,
- "tag_type": 1,
- "start": 35177
- },
- {
- "start": 35198,
- "end": 35206
- },
- {
- "attributes": {},
- "tag": "h3",
- "end": 35210,
- "tag_type": 1,
- "start": 35206
- },
- {
- "attributes": {
- "cellpadding": "0",
- "cellspacing": "0"
- },
- "tag": "table",
- "end": 35249,
- "tag_type": 1,
- "start": 35210
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 35256,
- "tag_type": 1,
- "start": 35249
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 35260,
- "tag_type": 1,
- "start": 35256
- },
- {
- "attributes": {
- "class": "text"
- },
- "tag": "td",
- "end": 35277,
- "tag_type": 1,
- "start": 35260
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 35283,
- "tag_type": 1,
- "start": 35277
- },
- {
- "start": 35283,
- "end": 35301
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 35308,
- "tag_type": 2,
- "start": 35301
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 35313,
- "tag_type": 2,
- "start": 35308
- },
- {
- "attributes": {
- "class": "tabend"
- },
- "tag": "td",
- "end": 35332,
- "tag_type": 1,
- "start": 35313
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 35337,
- "tag_type": 2,
- "start": 35332
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 35342,
- "tag_type": 2,
- "start": 35337
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 35350,
- "tag_type": 2,
- "start": 35342
- },
- {
- "start": 35350,
- "end": 35362
- },
- {
- "attributes": {},
- "tag": "table",
- "end": 35370,
- "tag_type": 2,
- "start": 35362
- },
- {
- "start": 35370,
- "end": 35378
- },
- {
- "attributes": {},
- "tag": "h3",
- "end": 35383,
- "tag_type": 2,
- "start": 35378
- },
- {
- "start": 35383,
- "end": 35399
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 35402,
- "tag_type": 1,
- "start": 35399
- },
- {
- "start": 35402,
- "end": 35414
- },
- {
- "attributes": {
- "href": "#"
- },
- "tag": "a",
- "end": 35426,
- "tag_type": 1,
- "start": 35414
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 35430,
- "tag_type": 2,
- "start": 35426
- },
- {
- "start": 35430,
- "end": 35444
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 35448,
- "tag_type": 2,
- "start": 35444
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 35454,
- "tag_type": 2,
- "start": 35448
- },
- {
- "attributes": {
- "class": "relatedpromos slice"
- },
- "tag": "div",
- "end": 35487,
- "tag_type": 1,
- "start": 35454
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 35491,
- "tag_type": 1,
- "start": 35487
- },
- {
- "attributes": {
- "class": "textbig"
- },
- "tag": "li",
- "end": 35511,
- "tag_type": 1,
- "start": 35491
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/3-/275282/2-/Promo.html"
- },
- "tag": "a",
- "end": 35570,
- "tag_type": 1,
- "start": 35511
- },
- {
- "start": 35570,
- "end": 35589
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 35593,
- "tag_type": 2,
- "start": 35589
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 35598,
- "tag_type": 2,
- "start": 35593
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 35603,
- "tag_type": 2,
- "start": 35598
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 35609,
- "tag_type": 2,
- "start": 35603
- },
- {
- "start": 35609,
- "end": 35613
- },
- {
- "attributes": {
- "class": "subhead"
- },
- "tag": "div",
- "end": 35634,
- "tag_type": 1,
- "start": 35613
- },
- {
- "start": 35634,
- "end": 35642
- },
- {
- "attributes": {
- "cellpadding": "0",
- "cellspacing": "0",
- "id": "jump-features",
- "name": "jump-features"
- },
- "tag": "h3",
- "end": 35718,
- "tag_type": 1,
- "start": 35642
- },
- {
- "attributes": {},
- "tag": "table",
- "end": 35725,
- "tag_type": 1,
- "start": 35718
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 35732,
- "tag_type": 1,
- "start": 35725
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 35736,
- "tag_type": 1,
- "start": 35732
- },
- {
- "attributes": {
- "class": "text"
- },
- "tag": "td",
- "end": 35753,
- "tag_type": 1,
- "start": 35736
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 35759,
- "tag_type": 1,
- "start": 35753
- },
- {
- "start": 35759,
- "end": 35773
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 35780,
- "tag_type": 2,
- "start": 35773
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 35785,
- "tag_type": 2,
- "start": 35780
- },
- {
- "attributes": {
- "class": "tabend"
- },
- "tag": "td",
- "end": 35804,
- "tag_type": 1,
- "start": 35785
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 35809,
- "tag_type": 2,
- "start": 35804
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 35814,
- "tag_type": 2,
- "start": 35809
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 35822,
- "tag_type": 2,
- "start": 35814
- },
- {
- "start": 35822,
- "end": 35834
- },
- {
- "attributes": {},
- "tag": "table",
- "end": 35842,
- "tag_type": 2,
- "start": 35834
- },
- {
- "start": 35842,
- "end": 35850
- },
- {
- "attributes": {},
- "tag": "h3",
- "end": 35855,
- "tag_type": 2,
- "start": 35850
- },
- {
- "start": 35855,
- "end": 35871
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 35874,
- "tag_type": 1,
- "start": 35871
- },
- {
- "start": 35874,
- "end": 35886
- },
- {
- "attributes": {
- "href": "#goto-top"
- },
- "tag": "a",
- "end": 35906,
- "tag_type": 1,
- "start": 35886
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 35910,
- "tag_type": 2,
- "start": 35906
- },
- {
- "start": 35910,
- "end": 35924
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 35928,
- "tag_type": 2,
- "start": 35924
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 35934,
- "tag_type": 2,
- "start": 35928
- },
- {
- "attributes": {
- "class": "special slice"
- },
- "tag": "div",
- "end": 35961,
- "tag_type": 1,
- "start": 35934
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 35965,
- "tag_type": 1,
- "start": 35961
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 35969,
- "tag_type": 1,
- "start": 35965
- },
- {
- "attributes": {},
- "tag": "center",
- "end": 35977,
- "tag_type": 1,
- "start": 35969
- },
- {
- "attributes": {
- "src": "http://images.play.com/banners/SAM550ban.jpg",
- "alt": "diagram"
- },
- "tag": "img",
- "end": 36047,
- "tag_type": 1,
- "start": 35977
- },
- {
- "attributes": {},
- "tag": "center",
- "end": 36056,
- "tag_type": 2,
- "start": 36047
- },
- {
- "start": 36056,
- "end": 36057
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36062,
- "tag_type": 2,
- "start": 36057
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36066,
- "tag_type": 1,
- "start": 36062
- },
- {
- "start": 36066,
- "end": 36067
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 36075,
- "tag_type": 1,
- "start": 36067
- },
- {
- "start": 36075,
- "end": 36235
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 36244,
- "tag_type": 2,
- "start": 36235
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36249,
- "tag_type": 2,
- "start": 36244
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36253,
- "tag_type": 1,
- "start": 36249
- },
- {
- "start": 36253,
- "end": 36270
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36275,
- "tag_type": 2,
- "start": 36270
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36279,
- "tag_type": 1,
- "start": 36275
- },
- {
- "start": 36279,
- "end": 36303
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36308,
- "tag_type": 2,
- "start": 36303
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36312,
- "tag_type": 1,
- "start": 36308
- },
- {
- "start": 36312,
- "end": 36329
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36334,
- "tag_type": 2,
- "start": 36329
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36338,
- "tag_type": 1,
- "start": 36334
- },
- {
- "start": 36338,
- "end": 36360
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36365,
- "tag_type": 2,
- "start": 36360
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36369,
- "tag_type": 1,
- "start": 36365
- },
- {
- "start": 36369,
- "end": 36407
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36412,
- "tag_type": 2,
- "start": 36407
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36416,
- "tag_type": 1,
- "start": 36412
- },
- {
- "start": 36416,
- "end": 36443
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36448,
- "tag_type": 2,
- "start": 36443
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36452,
- "tag_type": 1,
- "start": 36448
- },
- {
- "start": 36452,
- "end": 36472
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36477,
- "tag_type": 2,
- "start": 36472
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36481,
- "tag_type": 1,
- "start": 36477
- },
- {
- "start": 36481,
- "end": 36482
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 36490,
- "tag_type": 1,
- "start": 36482
- },
- {
- "start": 36490,
- "end": 36495
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 36504,
- "tag_type": 2,
- "start": 36495
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36509,
- "tag_type": 2,
- "start": 36504
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36513,
- "tag_type": 1,
- "start": 36509
- },
- {
- "start": 36513,
- "end": 36578
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36583,
- "tag_type": 2,
- "start": 36578
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36587,
- "tag_type": 1,
- "start": 36583
- },
- {
- "start": 36587,
- "end": 36613
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36618,
- "tag_type": 2,
- "start": 36613
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36622,
- "tag_type": 1,
- "start": 36618
- },
- {
- "start": 36622,
- "end": 36649
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36654,
- "tag_type": 2,
- "start": 36649
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36658,
- "tag_type": 1,
- "start": 36654
- },
- {
- "start": 36658,
- "end": 36659
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 36667,
- "tag_type": 1,
- "start": 36659
- },
- {
- "start": 36667,
- "end": 36675
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 36684,
- "tag_type": 2,
- "start": 36675
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36689,
- "tag_type": 2,
- "start": 36684
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36693,
- "tag_type": 1,
- "start": 36689
- },
- {
- "start": 36693,
- "end": 36701
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36706,
- "tag_type": 2,
- "start": 36701
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36710,
- "tag_type": 1,
- "start": 36706
- },
- {
- "start": 36710,
- "end": 36725
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36730,
- "tag_type": 2,
- "start": 36725
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36734,
- "tag_type": 1,
- "start": 36730
- },
- {
- "start": 36734,
- "end": 36753
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36758,
- "tag_type": 2,
- "start": 36753
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36762,
- "tag_type": 1,
- "start": 36758
- },
- {
- "start": 36762,
- "end": 36772
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36777,
- "tag_type": 2,
- "start": 36772
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36781,
- "tag_type": 1,
- "start": 36777
- },
- {
- "start": 36781,
- "end": 36796
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36801,
- "tag_type": 2,
- "start": 36796
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36805,
- "tag_type": 1,
- "start": 36801
- },
- {
- "start": 36805,
- "end": 36818
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36823,
- "tag_type": 2,
- "start": 36818
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36827,
- "tag_type": 1,
- "start": 36823
- },
- {
- "start": 36827,
- "end": 36839
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36844,
- "tag_type": 2,
- "start": 36839
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36848,
- "tag_type": 1,
- "start": 36844
- },
- {
- "start": 36848,
- "end": 36873
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36878,
- "tag_type": 2,
- "start": 36873
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36882,
- "tag_type": 1,
- "start": 36878
- },
- {
- "start": 36882,
- "end": 36902
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36907,
- "tag_type": 2,
- "start": 36902
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36911,
- "tag_type": 1,
- "start": 36907
- },
- {
- "start": 36911,
- "end": 36926
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36931,
- "tag_type": 2,
- "start": 36926
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36935,
- "tag_type": 1,
- "start": 36931
- },
- {
- "start": 36935,
- "end": 36939
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36944,
- "tag_type": 2,
- "start": 36939
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36948,
- "tag_type": 1,
- "start": 36944
- },
- {
- "start": 36948,
- "end": 36969
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36974,
- "tag_type": 2,
- "start": 36969
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36978,
- "tag_type": 1,
- "start": 36974
- },
- {
- "start": 36978,
- "end": 36994
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36999,
- "tag_type": 2,
- "start": 36994
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37003,
- "tag_type": 1,
- "start": 36999
- },
- {
- "start": 37003,
- "end": 37004
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 37012,
- "tag_type": 1,
- "start": 37004
- },
- {
- "start": 37012,
- "end": 37018
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 37027,
- "tag_type": 2,
- "start": 37018
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37032,
- "tag_type": 2,
- "start": 37027
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37036,
- "tag_type": 1,
- "start": 37032
- },
- {
- "start": 37036,
- "end": 37045
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37050,
- "tag_type": 2,
- "start": 37045
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37054,
- "tag_type": 1,
- "start": 37050
- },
- {
- "start": 37054,
- "end": 37073
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37078,
- "tag_type": 2,
- "start": 37073
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37082,
- "tag_type": 1,
- "start": 37078
- },
- {
- "start": 37082,
- "end": 37083
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 37091,
- "tag_type": 1,
- "start": 37083
- },
- {
- "start": 37091,
- "end": 37107
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 37116,
- "tag_type": 2,
- "start": 37107
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37121,
- "tag_type": 2,
- "start": 37116
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37125,
- "tag_type": 1,
- "start": 37121
- },
- {
- "start": 37125,
- "end": 37143
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37148,
- "tag_type": 2,
- "start": 37143
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37152,
- "tag_type": 1,
- "start": 37148
- },
- {
- "start": 37152,
- "end": 37162
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37167,
- "tag_type": 2,
- "start": 37162
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37171,
- "tag_type": 1,
- "start": 37167
- },
- {
- "start": 37171,
- "end": 37185
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37190,
- "tag_type": 2,
- "start": 37185
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37194,
- "tag_type": 1,
- "start": 37190
- },
- {
- "start": 37194,
- "end": 37214
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37219,
- "tag_type": 2,
- "start": 37214
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37223,
- "tag_type": 1,
- "start": 37219
- },
- {
- "start": 37223,
- "end": 37237
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37242,
- "tag_type": 2,
- "start": 37237
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37246,
- "tag_type": 1,
- "start": 37242
- },
- {
- "start": 37246,
- "end": 37269
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37274,
- "tag_type": 2,
- "start": 37269
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37278,
- "tag_type": 1,
- "start": 37274
- },
- {
- "start": 37278,
- "end": 37311
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37316,
- "tag_type": 2,
- "start": 37311
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37320,
- "tag_type": 1,
- "start": 37316
- },
- {
- "start": 37320,
- "end": 37354
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37359,
- "tag_type": 2,
- "start": 37354
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37363,
- "tag_type": 1,
- "start": 37359
- },
- {
- "start": 37363,
- "end": 37388
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37393,
- "tag_type": 2,
- "start": 37388
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37397,
- "tag_type": 1,
- "start": 37393
- },
- {
- "start": 37397,
- "end": 37427
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37432,
- "tag_type": 2,
- "start": 37427
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37436,
- "tag_type": 1,
- "start": 37432
- },
- {
- "start": 37436,
- "end": 37452
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37457,
- "tag_type": 2,
- "start": 37452
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37461,
- "tag_type": 1,
- "start": 37457
- },
- {
- "start": 37461,
- "end": 37476
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37481,
- "tag_type": 2,
- "start": 37476
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37485,
- "tag_type": 1,
- "start": 37481
- },
- {
- "start": 37485,
- "end": 37506
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37511,
- "tag_type": 2,
- "start": 37506
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37515,
- "tag_type": 1,
- "start": 37511
- },
- {
- "start": 37515,
- "end": 37528
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37533,
- "tag_type": 2,
- "start": 37528
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37537,
- "tag_type": 1,
- "start": 37533
- },
- {
- "start": 37537,
- "end": 37549
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37554,
- "tag_type": 2,
- "start": 37549
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37558,
- "tag_type": 1,
- "start": 37554
- },
- {
- "start": 37558,
- "end": 37559
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 37567,
- "tag_type": 1,
- "start": 37559
- },
- {
- "start": 37567,
- "end": 37573
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 37582,
- "tag_type": 2,
- "start": 37573
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37587,
- "tag_type": 2,
- "start": 37582
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37591,
- "tag_type": 1,
- "start": 37587
- },
- {
- "start": 37591,
- "end": 37616
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37621,
- "tag_type": 2,
- "start": 37616
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37625,
- "tag_type": 1,
- "start": 37621
- },
- {
- "start": 37625,
- "end": 37648
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37653,
- "tag_type": 2,
- "start": 37648
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37657,
- "tag_type": 1,
- "start": 37653
- },
- {
- "start": 37657,
- "end": 37677
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37682,
- "tag_type": 2,
- "start": 37677
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37686,
- "tag_type": 1,
- "start": 37682
- },
- {
- "start": 37686,
- "end": 37687
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 37695,
- "tag_type": 1,
- "start": 37687
- },
- {
- "start": 37695,
- "end": 37706
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 37715,
- "tag_type": 2,
- "start": 37706
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37720,
- "tag_type": 2,
- "start": 37715
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37724,
- "tag_type": 1,
- "start": 37720
- },
- {
- "start": 37724,
- "end": 37770
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37775,
- "tag_type": 2,
- "start": 37770
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37779,
- "tag_type": 1,
- "start": 37775
- },
- {
- "start": 37779,
- "end": 37827
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37832,
- "tag_type": 2,
- "start": 37827
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37836,
- "tag_type": 1,
- "start": 37832
- },
- {
- "start": 37836,
- "end": 37837
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 37845,
- "tag_type": 1,
- "start": 37837
- },
- {
- "start": 37845,
- "end": 37851
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 37860,
- "tag_type": 2,
- "start": 37851
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37865,
- "tag_type": 2,
- "start": 37860
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37869,
- "tag_type": 1,
- "start": 37865
- },
- {
- "start": 37869,
- "end": 37897
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37902,
- "tag_type": 2,
- "start": 37897
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37906,
- "tag_type": 1,
- "start": 37902
- },
- {
- "start": 37906,
- "end": 37937
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37942,
- "tag_type": 2,
- "start": 37937
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37946,
- "tag_type": 1,
- "start": 37942
- },
- {
- "start": 37946,
- "end": 37947
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 37955,
- "tag_type": 1,
- "start": 37947
- },
- {
- "start": 37955,
- "end": 37964
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 37973,
- "tag_type": 2,
- "start": 37964
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37978,
- "tag_type": 2,
- "start": 37973
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37982,
- "tag_type": 1,
- "start": 37978
- },
- {
- "start": 37982,
- "end": 38026
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 38031,
- "tag_type": 2,
- "start": 38026
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 38035,
- "tag_type": 1,
- "start": 38031
- },
- {
- "start": 38035,
- "end": 38053
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 38058,
- "tag_type": 2,
- "start": 38053
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 38062,
- "tag_type": 1,
- "start": 38058
- },
- {
- "start": 38062,
- "end": 38072
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 38077,
- "tag_type": 2,
- "start": 38072
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 38081,
- "tag_type": 1,
- "start": 38077
- },
- {
- "start": 38081,
- "end": 38093
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 38098,
- "tag_type": 2,
- "start": 38093
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 38103,
- "tag_type": 2,
- "start": 38098
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 38109,
- "tag_type": 2,
- "start": 38103
- },
- {
- "start": 38109,
- "end": 38113
- },
- {
- "attributes": {
- "class": "subhead"
- },
- "tag": "div",
- "end": 38134,
- "tag_type": 1,
- "start": 38113
- },
- {
- "start": 38134,
- "end": 38142
- },
- {
- "attributes": {
- "cellpadding": "0",
- "cellspacing": "0",
- "id": "jump-review",
- "name": "jump-review"
- },
- "tag": "h3",
- "end": 38214,
- "tag_type": 1,
- "start": 38142
- },
- {
- "attributes": {},
- "tag": "table",
- "end": 38221,
- "tag_type": 1,
- "start": 38214
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 38228,
- "tag_type": 1,
- "start": 38221
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 38232,
- "tag_type": 1,
- "start": 38228
- },
- {
- "attributes": {
- "class": "text"
- },
- "tag": "td",
- "end": 38249,
- "tag_type": 1,
- "start": 38232
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 38255,
- "tag_type": 1,
- "start": 38249
- },
- {
- "start": 38255,
- "end": 38266
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 38273,
- "tag_type": 2,
- "start": 38266
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 38278,
- "tag_type": 2,
- "start": 38273
- },
- {
- "attributes": {
- "class": "tabend"
- },
- "tag": "td",
- "end": 38297,
- "tag_type": 1,
- "start": 38278
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 38302,
- "tag_type": 2,
- "start": 38297
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 38307,
- "tag_type": 2,
- "start": 38302
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 38315,
- "tag_type": 2,
- "start": 38307
- },
- {
- "start": 38315,
- "end": 38327
- },
- {
- "attributes": {},
- "tag": "table",
- "end": 38335,
- "tag_type": 2,
- "start": 38327
- },
- {
- "start": 38335,
- "end": 38343
- },
- {
- "attributes": {},
- "tag": "h3",
- "end": 38348,
- "tag_type": 2,
- "start": 38343
- },
- {
- "start": 38348,
- "end": 38364
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 38367,
- "tag_type": 1,
- "start": 38364
- },
- {
- "start": 38367,
- "end": 38379
- },
- {
- "attributes": {
- "href": "#goto-top"
- },
- "tag": "a",
- "end": 38399,
- "tag_type": 1,
- "start": 38379
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 38403,
- "tag_type": 2,
- "start": 38399
- },
- {
- "start": 38403,
- "end": 38417
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 38421,
- "tag_type": 2,
- "start": 38417
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 38427,
- "tag_type": 2,
- "start": 38421
- },
- {
- "attributes": {
- "class": "review slice"
- },
- "tag": "div",
- "end": 38453,
- "tag_type": 1,
- "start": 38427
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 38456,
- "tag_type": 1,
- "start": 38453
- },
- {
- "start": 38456,
- "end": 38593
- },
- {
- "attributes": {},
- "tag": "br",
- "end": 38597,
- "tag_type": 1,
- "start": 38593
- },
- {
- "attributes": {},
- "tag": "br",
- "end": 38601,
- "tag_type": 1,
- "start": 38597
- },
- {
- "attributes": {
- "src": "http://images.play.com/banners/SAM550a.jpg",
- "align": "left",
- "hspace": "5"
- },
- "tag": "img",
- "end": 38679,
- "tag_type": 1,
- "start": 38601
- },
- {
- "attributes": {},
- "tag": "br",
- "end": 38683,
- "tag_type": 1,
- "start": 38679
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 38691,
- "tag_type": 1,
- "start": 38683
- },
- {
- "start": 38691,
- "end": 38699
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 38708,
- "tag_type": 2,
- "start": 38699
- },
- {
- "attributes": {},
- "tag": "br",
- "end": 38712,
- "tag_type": 1,
- "start": 38708
- },
- {
- "start": 38712,
- "end": 38983
- },
- {
- "attributes": {},
- "tag": "br",
- "end": 38987,
- "tag_type": 1,
- "start": 38983
- },
- {
- "attributes": {
- "clear": "all"
- },
- "tag": "br",
- "end": 39003,
- "tag_type": 1,
- "start": 38987
- },
- {
- "attributes": {},
- "tag": "br",
- "end": 39007,
- "tag_type": 1,
- "start": 39003
- },
- {
- "attributes": {
- "src": "http://images.play.com/banners/SAM550b.jpg",
- "align": "left",
- "hspace": "5"
- },
- "tag": "img",
- "end": 39085,
- "tag_type": 1,
- "start": 39007
- },
- {
- "attributes": {},
- "tag": "br",
- "end": 39089,
- "tag_type": 1,
- "start": 39085
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 39097,
- "tag_type": 1,
- "start": 39089
- },
- {
- "start": 39097,
- "end": 39117
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 39126,
- "tag_type": 2,
- "start": 39117
- },
- {
- "attributes": {},
- "tag": "br",
- "end": 39130,
- "tag_type": 1,
- "start": 39126
- },
- {
- "start": 39130,
- "end": 39271
- },
- {
- "attributes": {},
- "tag": "br",
- "end": 39275,
- "tag_type": 1,
- "start": 39271
- },
- {
- "attributes": {
- "clear": "all"
- },
- "tag": "br",
- "end": 39291,
- "tag_type": 1,
- "start": 39275
- },
- {
- "attributes": {},
- "tag": "br",
- "end": 39295,
- "tag_type": 1,
- "start": 39291
- },
- {
- "attributes": {
- "src": "http://images.play.com/banners/SAM550c.jpg",
- "align": "left",
- "hspace": "5"
- },
- "tag": "img",
- "end": 39373,
- "tag_type": 1,
- "start": 39295
- },
- {
- "attributes": {},
- "tag": "br",
- "end": 39377,
- "tag_type": 1,
- "start": 39373
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 39385,
- "tag_type": 1,
- "start": 39377
- },
- {
- "start": 39385,
- "end": 39403
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 39412,
- "tag_type": 2,
- "start": 39403
- },
- {
- "attributes": {},
- "tag": "br",
- "end": 39416,
- "tag_type": 1,
- "start": 39412
- },
- {
- "start": 39416,
- "end": 39601
- },
- {
- "attributes": {},
- "tag": "br",
- "end": 39605,
- "tag_type": 1,
- "start": 39601
- },
- {
- "attributes": {
- "clear": "all"
- },
- "tag": "br",
- "end": 39621,
- "tag_type": 1,
- "start": 39605
- },
- {
- "attributes": {},
- "tag": "br",
- "end": 39625,
- "tag_type": 1,
- "start": 39621
- },
- {
- "attributes": {
- "src": "http://images.play.com/banners/SAM550d.jpg",
- "align": "left",
- "hspace": "5"
- },
- "tag": "img",
- "end": 39703,
- "tag_type": 1,
- "start": 39625
- },
- {
- "attributes": {},
- "tag": "br",
- "end": 39707,
- "tag_type": 1,
- "start": 39703
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 39715,
- "tag_type": 1,
- "start": 39707
- },
- {
- "start": 39715,
- "end": 39722
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 39731,
- "tag_type": 2,
- "start": 39722
- },
- {
- "attributes": {},
- "tag": "br",
- "end": 39735,
- "tag_type": 1,
- "start": 39731
- },
- {
- "start": 39735,
- "end": 39835
- },
- {
- "attributes": {},
- "tag": "br",
- "end": 39839,
- "tag_type": 1,
- "start": 39835
- },
- {
- "attributes": {
- "clear": "all"
- },
- "tag": "br",
- "end": 39855,
- "tag_type": 1,
- "start": 39839
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 39859,
- "tag_type": 2,
- "start": 39855
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 39865,
- "tag_type": 2,
- "start": 39859
- },
- {
- "start": 39865,
- "end": 39869
- },
- {
- "attributes": {
- "class": "subhead"
- },
- "tag": "div",
- "end": 39890,
- "tag_type": 1,
- "start": 39869
- },
- {
- "start": 39890,
- "end": 39898
- },
- {
- "attributes": {
- "cellpadding": "0",
- "cellspacing": "0",
- "id": "jump-customer-review",
- "name": "jump-customer-review"
- },
- "tag": "h3",
- "end": 39988,
- "tag_type": 1,
- "start": 39898
- },
- {
- "attributes": {},
- "tag": "table",
- "end": 39995,
- "tag_type": 1,
- "start": 39988
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 40002,
- "tag_type": 1,
- "start": 39995
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 40006,
- "tag_type": 1,
- "start": 40002
- },
- {
- "attributes": {
- "class": "text"
- },
- "tag": "td",
- "end": 40023,
- "tag_type": 1,
- "start": 40006
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 40029,
- "tag_type": 1,
- "start": 40023
- },
- {
- "start": 40029,
- "end": 40045
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 40052,
- "tag_type": 2,
- "start": 40045
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 40057,
- "tag_type": 2,
- "start": 40052
- },
- {
- "attributes": {
- "class": "tabend"
- },
- "tag": "td",
- "end": 40076,
- "tag_type": 1,
- "start": 40057
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 40081,
- "tag_type": 2,
- "start": 40076
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 40086,
- "tag_type": 2,
- "start": 40081
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 40094,
- "tag_type": 2,
- "start": 40086
- },
- {
- "start": 40094,
- "end": 40106
- },
- {
- "attributes": {},
- "tag": "table",
- "end": 40114,
- "tag_type": 2,
- "start": 40106
- },
- {
- "start": 40114,
- "end": 40122
- },
- {
- "attributes": {},
- "tag": "h3",
- "end": 40127,
- "tag_type": 2,
- "start": 40122
- },
- {
- "start": 40127,
- "end": 40143
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 40146,
- "tag_type": 1,
- "start": 40143
- },
- {
- "start": 40146,
- "end": 40158
- },
- {
- "attributes": {
- "href": null
- },
- "tag": "a",
- "end": 40169,
- "tag_type": 1,
- "start": 40158
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 40173,
- "tag_type": 2,
- "start": 40169
- },
- {
- "start": 40173,
- "end": 40187
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 40191,
- "tag_type": 2,
- "start": 40187
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 40197,
- "tag_type": 2,
- "start": 40191
- },
- {
- "attributes": {
- "class": "rnr slice"
- },
- "tag": "div",
- "end": 40220,
- "tag_type": 1,
- "start": 40197
- },
- {
- "attributes": {
- "class": "rnr-average",
- "id": "_pageTemplate__product_ctl00__cacheable__customerReviews_ctl00_avarageRating__divAverage"
- },
- "tag": "div",
- "end": 40339,
- "tag_type": 1,
- "start": 40220
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 40344,
- "tag_type": 1,
- "start": 40339
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteCSS/Play/Live1/img/spaces/stars50_x.gif",
- "alt": "Customer rating on Samsung Series 5 550 37" LE37B550 / HD 1080p / Freeview / LCD TV (Black): 5 out of 5 stars",
- "style": "border-width: 0px; height: 21px; width: 106px;"
- },
- "tag": "img",
- "end": 40598,
- "tag_type": 1,
- "start": 40344
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 40604,
- "tag_type": 2,
- "start": 40598
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 40607,
- "tag_type": 1,
- "start": 40604
- },
- {
- "start": 40607,
- "end": 40623
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 40631,
- "tag_type": 1,
- "start": 40623
- },
- {
- "start": 40631,
- "end": 40632
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 40641,
- "tag_type": 2,
- "start": 40632
- },
- {
- "start": 40641,
- "end": 40649
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 40653,
- "tag_type": 2,
- "start": 40649
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 40659,
- "tag_type": 2,
- "start": 40653
- },
- {
- "attributes": {
- "class": "rnr-links",
- "id": "_pageTemplate__product_ctl00__cacheable__customerReviews_ctl00_divHeaderLinks"
- },
- "tag": "div",
- "end": 40765,
- "tag_type": 1,
- "start": 40659
- },
- {
- "start": 40765,
- "end": 40777
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 40780,
- "tag_type": 1,
- "start": 40777
- },
- {
- "attributes": {
- "href": "https://www.play.com/OrdersPost.aspx?&returnURL=http://www.play.com/Product.aspx?searchtype=genre&r=ELEC&p=318&g=404&title=8986420&PRODUCT_TITLE=Samsung-Series-5-550-37-LE37B550-HD-1080p-Freeview-LCD-TV¤cy=257&source=0&action=addreview&subaction=productreviewadd&_productid=8986420&_region=ELEC&_producttitle=Samsung+Series+5+550+37%22+LE37B550+%2f+HD+1080p+%2f+Freeview+%2f+LCD+TV+%28Black%29&_smallimageavailable=1",
- "title": "Write a review of Samsung Series 5 550 37" LE37B550 / HD 1080p / Freeview / LCD TV (Black)"
- },
- "tag": "a",
- "end": 41373,
- "tag_type": 1,
- "start": 40780
- },
- {
- "start": 41373,
- "end": 41387
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 41391,
- "tag_type": 2,
- "start": 41387
- },
- {
- "start": 41391,
- "end": 41394
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/8986420/Samsung-Series-5-550-37-LE37B550-HD-1080p-Freeview-LCD-TV/ProductReviews.html",
- "title": "See all Samsung Series 5 550 37" LE37B550 / HD 1080p / Freeview / LCD TV (Black) reviews"
- },
- "tag": "a",
- "end": 41620,
- "tag_type": 1,
- "start": 41394
- },
- {
- "start": 41620,
- "end": 41641
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 41645,
- "tag_type": 2,
- "start": 41641
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 41649,
- "tag_type": 2,
- "start": 41645
- },
- {
- "start": 41649,
- "end": 41657
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 41663,
- "tag_type": 2,
- "start": 41657
- },
- {
- "start": 41663,
- "end": 41679
- },
- {
- "attributes": {
- "class": "rnr-review"
- },
- "tag": "div",
- "end": 41703,
- "tag_type": 1,
- "start": 41679
- },
- {
- "attributes": {
- "class": "rnr-header"
- },
- "tag": "div",
- "end": 41727,
- "tag_type": 1,
- "start": 41703
- },
- {
- "attributes": {},
- "tag": "h4",
- "end": 41731,
- "tag_type": 1,
- "start": 41727
- },
- {
- "attributes": {
- "name": "346537"
- },
- "tag": "a",
- "end": 41748,
- "tag_type": 1,
- "start": 41731
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 41752,
- "tag_type": 2,
- "start": 41748
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteCSS/Play/Live1/img/spaces/stars50.gif",
- "alt": "Customer rating: 5 out of 5 stars",
- "style": "border-width: 0px; height: 14px; width: 71px;"
- },
- "tag": "img",
- "end": 41922,
- "tag_type": 1,
- "start": 41752
- },
- {
- "start": 41922,
- "end": 41940
- },
- {
- "attributes": {},
- "tag": "h4",
- "end": 41945,
- "tag_type": 2,
- "start": 41940
- },
- {
- "attributes": {
- "class": "rnr-info"
- },
- "tag": "p",
- "end": 41965,
- "tag_type": 1,
- "start": 41945
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 41973,
- "tag_type": 1,
- "start": 41965
- },
- {
- "start": 41973,
- "end": 41980
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 41989,
- "tag_type": 2,
- "start": 41980
- },
- {
- "start": 41989,
- "end": 42002
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 42008,
- "tag_type": 1,
- "start": 42002
- },
- {
- "start": 42008,
- "end": 42018
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 42025,
- "tag_type": 2,
- "start": 42018
- },
- {
- "start": 42025,
- "end": 42038
- },
- {
- "attributes": {
- "href": "/HOME/HOME/6-/UserReviews.html?rn=124580&edtm=0"
- },
- "tag": "a",
- "end": 42100,
- "tag_type": 1,
- "start": 42038
- },
- {
- "start": 42100,
- "end": 42131
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 42135,
- "tag_type": 2,
- "start": 42131
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 42139,
- "tag_type": 2,
- "start": 42135
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 42145,
- "tag_type": 2,
- "start": 42139
- },
- {
- "attributes": {
- "class": "rnr-content"
- },
- "tag": "div",
- "end": 42170,
- "tag_type": 1,
- "start": 42145
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 42173,
- "tag_type": 1,
- "start": 42170
- },
- {
- "start": 42173,
- "end": 42316
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 42320,
- "tag_type": 2,
- "start": 42316
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 42326,
- "tag_type": 2,
- "start": 42320
- },
- {
- "attributes": {
- "class": "rnr-footer"
- },
- "tag": "div",
- "end": 42350,
- "tag_type": 1,
- "start": 42326
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 42353,
- "tag_type": 1,
- "start": 42350
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 42359,
- "tag_type": 1,
- "start": 42353
- },
- {
- "start": 42359,
- "end": 42392
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 42399,
- "tag_type": 2,
- "start": 42392
- },
- {
- "attributes": {
- "href": "https://www.play.com/OrdersPost.aspx?&returnURL=http://www.play.com/Product.aspx?searchtype=genre&r=ELEC&p=318&g=404&title=8986420&PRODUCT_TITLE=Samsung-Series-5-550-37-LE37B550-HD-1080p-Freeview-LCD-TV¤cy=257&source=0&action=addreview&subaction=REVIEW_VOTE&_reviewId=346537&_helpful=y",
- "id": "_pageTemplate__product_ctl00__cacheable__customerReviews_ctl00_listReviews_ctl00_reviewItem__linkYes"
- },
- "tag": "a",
- "end": 42855,
- "tag_type": 1,
- "start": 42399
- },
- {
- "start": 42855,
- "end": 42858
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 42862,
- "tag_type": 2,
- "start": 42858
- },
- {
- "start": 42862,
- "end": 42875
- },
- {
- "attributes": {
- "href": "https://www.play.com/OrdersPost.aspx?&returnURL=http://www.play.com/Product.aspx?searchtype=genre&r=ELEC&p=318&g=404&title=8986420&PRODUCT_TITLE=Samsung-Series-5-550-37-LE37B550-HD-1080p-Freeview-LCD-TV¤cy=257&source=0&action=addreview&subaction=REVIEW_VOTE&_reviewId=346537&_helpful=n",
- "id": "_pageTemplate__product_ctl00__cacheable__customerReviews_ctl00_listReviews_ctl00_reviewItem__linkNo"
- },
- "tag": "a",
- "end": 43330,
- "tag_type": 1,
- "start": 42875
- },
- {
- "start": 43330,
- "end": 43332
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 43336,
- "tag_type": 2,
- "start": 43332
- },
- {
- "start": 43336,
- "end": 43349
- },
- {
- "attributes": {
- "href": "https://www.play.com/OrdersPost.aspx?&returnURL=http://www.play.com/Product.aspx?searchtype=genre&r=ELEC&p=318&g=404&title=8986420&PRODUCT_TITLE=Samsung-Series-5-550-37-LE37B550-HD-1080p-Freeview-LCD-TV¤cy=257&source=0&action=addreview&subaction=report_review&_reviewId=346537",
- "id": "_pageTemplate__product_ctl00__cacheable__customerReviews_ctl00_listReviews_ctl00_reviewItem__ReportReviewLink_lnkReportReview"
- },
- "tag": "a",
- "end": 43817,
- "tag_type": 1,
- "start": 43349
- },
- {
- "start": 43817,
- "end": 43829
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 43833,
- "tag_type": 2,
- "start": 43829
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 43837,
- "tag_type": 2,
- "start": 43833
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 43843,
- "tag_type": 2,
- "start": 43837
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 43849,
- "tag_type": 2,
- "start": 43843
- },
- {
- "start": 43849,
- "end": 43869
- },
- {
- "attributes": {
- "class": "rnr-links"
- },
- "tag": "div",
- "end": 43892,
- "tag_type": 1,
- "start": 43869
- },
- {
- "start": 43892,
- "end": 43904
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 43907,
- "tag_type": 1,
- "start": 43904
- },
- {
- "attributes": {
- "href": "https://www.play.com/OrdersPost.aspx?&returnURL=http://www.play.com/Product.aspx?searchtype=genre&r=ELEC&p=318&g=404&title=8986420&PRODUCT_TITLE=Samsung-Series-5-550-37-LE37B550-HD-1080p-Freeview-LCD-TV¤cy=257&source=0&action=addreview&subaction=productreviewadd&_productid=8986420&_region=ELEC&_producttitle=Samsung+Series+5+550+37%22+LE37B550+%2f+HD+1080p+%2f+Freeview+%2f+LCD+TV+%28Black%29&_smallimageavailable=1",
- "title": "Write a review of Samsung Series 5 550 37" LE37B550 / HD 1080p / Freeview / LCD TV (Black)"
- },
- "tag": "a",
- "end": 44500,
- "tag_type": 1,
- "start": 43907
- },
- {
- "start": 44500,
- "end": 44514
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 44518,
- "tag_type": 2,
- "start": 44514
- },
- {
- "start": 44518,
- "end": 44521
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/8986420/Samsung-Series-5-550-37-LE37B550-HD-1080p-Freeview-LCD-TV/ProductReviews.html",
- "title": "See all Samsung Series 5 550 37" LE37B550 / HD 1080p / Freeview / LCD TV (Black) reviews"
- },
- "tag": "a",
- "end": 44747,
- "tag_type": 1,
- "start": 44521
- },
- {
- "start": 44747,
- "end": 44768
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 44772,
- "tag_type": 2,
- "start": 44768
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 44776,
- "tag_type": 2,
- "start": 44772
- },
- {
- "start": 44776,
- "end": 44784
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 44790,
- "tag_type": 2,
- "start": 44784
- },
- {
- "start": 44790,
- "end": 44794
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 44800,
- "tag_type": 2,
- "start": 44794
- },
- {
- "start": 44800,
- "end": 44804
- },
- {
- "attributes": {
- "class": "subhead"
- },
- "tag": "div",
- "end": 44825,
- "tag_type": 1,
- "start": 44804
- },
- {
- "start": 44825,
- "end": 44833
- },
- {
- "attributes": {},
- "tag": "h3",
- "end": 44837,
- "tag_type": 1,
- "start": 44833
- },
- {
- "attributes": {
- "cellpadding": "0",
- "cellspacing": "0"
- },
- "tag": "table",
- "end": 44876,
- "tag_type": 1,
- "start": 44837
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 44883,
- "tag_type": 1,
- "start": 44876
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 44887,
- "tag_type": 1,
- "start": 44883
- },
- {
- "attributes": {
- "class": "text"
- },
- "tag": "td",
- "end": 44904,
- "tag_type": 1,
- "start": 44887
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 44910,
- "tag_type": 1,
- "start": 44904
- },
- {
- "start": 44910,
- "end": 44937
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 44944,
- "tag_type": 2,
- "start": 44937
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 44949,
- "tag_type": 2,
- "start": 44944
- },
- {
- "attributes": {
- "class": "tabend"
- },
- "tag": "td",
- "end": 44968,
- "tag_type": 1,
- "start": 44949
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 44973,
- "tag_type": 2,
- "start": 44968
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 44978,
- "tag_type": 2,
- "start": 44973
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 44986,
- "tag_type": 2,
- "start": 44978
- },
- {
- "start": 44986,
- "end": 44998
- },
- {
- "attributes": {},
- "tag": "table",
- "end": 45006,
- "tag_type": 2,
- "start": 44998
- },
- {
- "start": 45006,
- "end": 45014
- },
- {
- "attributes": {},
- "tag": "h3",
- "end": 45019,
- "tag_type": 2,
- "start": 45014
- },
- {
- "start": 45019,
- "end": 45035
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 45038,
- "tag_type": 1,
- "start": 45035
- },
- {
- "start": 45038,
- "end": 45050
- },
- {
- "attributes": {
- "href": null
- },
- "tag": "a",
- "end": 45061,
- "tag_type": 1,
- "start": 45050
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 45065,
- "tag_type": 2,
- "start": 45061
- },
- {
- "start": 45065,
- "end": 45079
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 45083,
- "tag_type": 2,
- "start": 45079
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 45089,
- "tag_type": 2,
- "start": 45083
- },
- {
- "attributes": {
- "class": "related slice"
- },
- "tag": "div",
- "end": 45116,
- "tag_type": 1,
- "start": 45089
- },
- {
- "attributes": {
- "cellspacing": "0"
- },
- "tag": "table",
- "end": 45139,
- "tag_type": 1,
- "start": 45116
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 45146,
- "tag_type": 1,
- "start": 45139
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 45150,
- "tag_type": 1,
- "start": 45146
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 45154,
- "tag_type": 1,
- "start": 45150
- },
- {
- "attributes": {
- "class": "image"
- },
- "tag": "div",
- "end": 45173,
- "tag_type": 1,
- "start": 45154
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/8986409/Samsung-Series-5-550-32-LE32B550-HD-1080p-Freeview-LCD-TV/Product.html"
- },
- "tag": "a",
- "end": 45290,
- "tag_type": 1,
- "start": 45173
- },
- {
- "attributes": {
- "onerror": null,
- "src": "http://images.play.com/covers/8986409s.jpg",
- "alt": "Samsung Series 5 550 32" LE32B550 / HD 1080p / Freeview / LCD TV (Black)",
- "style": "border-width: 0px; height: 85px; width: 85px;"
- },
- "tag": "img",
- "end": 45493,
- "tag_type": 1,
- "start": 45290
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 45497,
- "tag_type": 2,
- "start": 45493
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 45503,
- "tag_type": 2,
- "start": 45497
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 45508,
- "tag_type": 2,
- "start": 45503
- },
- {
- "attributes": {
- "class": "wide"
- },
- "tag": "td",
- "end": 45525,
- "tag_type": 1,
- "start": 45508
- },
- {
- "attributes": {
- "class": "info"
- },
- "tag": "div",
- "end": 45543,
- "tag_type": 1,
- "start": 45525
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 45547,
- "tag_type": 1,
- "start": 45543
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 45551,
- "tag_type": 1,
- "start": 45547
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/8986409/Samsung-Series-5-550-32-LE32B550-HD-1080p-Freeview-LCD-TV/Product.html"
- },
- "tag": "a",
- "end": 45668,
- "tag_type": 1,
- "start": 45551
- },
- {
- "start": 45668,
- "end": 45761
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 45765,
- "tag_type": 2,
- "start": 45761
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 45770,
- "tag_type": 2,
- "start": 45765
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 45775,
- "tag_type": 2,
- "start": 45770
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 45781,
- "tag_type": 2,
- "start": 45775
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 45786,
- "tag_type": 2,
- "start": 45781
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 45791,
- "tag_type": 2,
- "start": 45786
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 45799,
- "tag_type": 2,
- "start": 45791
- },
- {
- "attributes": {},
- "tag": "table",
- "end": 45807,
- "tag_type": 2,
- "start": 45799
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 45813,
- "tag_type": 2,
- "start": 45807
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 45819,
- "tag_type": 2,
- "start": 45813
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 45825,
- "tag_type": 2,
- "start": 45819
- },
- {
- "attributes": {
- "class": "footnote wrap"
- },
- "tag": "div",
- "end": 45852,
- "tag_type": 1,
- "start": 45825
- },
- {
- "attributes": {
- "class": "email"
- },
- "tag": "p",
- "end": 45869,
- "tag_type": 1,
- "start": 45852
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/8986420/-/EmailAFriend.html"
- },
- "tag": "a",
- "end": 45935,
- "tag_type": 1,
- "start": 45869
- },
- {
- "start": 45935,
- "end": 45969
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 45973,
- "tag_type": 2,
- "start": 45969
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 45977,
- "tag_type": 2,
- "start": 45973
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 45980,
- "tag_type": 1,
- "start": 45977
- },
- {
- "start": 45980,
- "end": 46009
- },
- {
- "attributes": {
- "style": null,
- "href": "about:blank"
- },
- "tag": "a",
- "end": 46040,
- "tag_type": 1,
- "start": 46009
- },
- {
- "start": 46040,
- "end": 46057
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 46061,
- "tag_type": 2,
- "start": 46057
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 46065,
- "tag_type": 2,
- "start": 46061
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 46068,
- "tag_type": 1,
- "start": 46065
- },
- {
- "attributes": {
- "href": "#goto-top"
- },
- "tag": "a",
- "end": 46088,
- "tag_type": 1,
- "start": 46068
- },
- {
- "start": 46088,
- "end": 46099
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 46103,
- "tag_type": 2,
- "start": 46099
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 46107,
- "tag_type": 2,
- "start": 46103
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 46113,
- "tag_type": 2,
- "start": 46107
- },
- {
- "start": 46113,
- "end": 46137
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 46143,
- "tag_type": 2,
- "start": 46137
- },
- {
- "start": 46143,
- "end": 46163
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 46169,
- "tag_type": 2,
- "start": 46163
- },
- {
- "start": 46169,
- "end": 46189
- },
- {
- "attributes": {
- "id": "leftCol"
- },
- "tag": "div",
- "end": 46207,
- "tag_type": 1,
- "start": 46189
- },
- {
- "start": 46207,
- "end": 46231
- },
- {
- "attributes": {
- "class": "column"
- },
- "tag": "div",
- "end": 46251,
- "tag_type": 1,
- "start": 46231
- },
- {
- "start": 46251,
- "end": 46275
- },
- {
- "attributes": {
- "class": "browse wrap"
- },
- "tag": "div",
- "end": 46300,
- "tag_type": 1,
- "start": 46275
- },
- {
- "attributes": {
- "class": "boxhead"
- },
- "tag": "div",
- "end": 46321,
- "tag_type": 1,
- "start": 46300
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 46326,
- "tag_type": 1,
- "start": 46321
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 46331,
- "tag_type": 1,
- "start": 46326
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 46335,
- "tag_type": 1,
- "start": 46331
- },
- {
- "start": 46335,
- "end": 46353
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 46358,
- "tag_type": 2,
- "start": 46353
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 46364,
- "tag_type": 2,
- "start": 46358
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 46370,
- "tag_type": 2,
- "start": 46364
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 46376,
- "tag_type": 2,
- "start": 46370
- },
- {
- "attributes": {
- "class": "box"
- },
- "tag": "div",
- "end": 46393,
- "tag_type": 1,
- "start": 46376
- },
- {
- "start": 46393,
- "end": 46401
- },
- {
- "attributes": {
- "class": "top"
- },
- "tag": "ul",
- "end": 46417,
- "tag_type": 1,
- "start": 46401
- },
- {
- "start": 46417,
- "end": 46429
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 46433,
- "tag_type": 1,
- "start": 46429
- },
- {
- "start": 46433,
- "end": 46441
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/6-/NewReleases.html"
- },
- "tag": "a",
- "end": 46496,
- "tag_type": 1,
- "start": 46441
- },
- {
- "start": 46496,
- "end": 46508
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 46512,
- "tag_type": 2,
- "start": 46508
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 46517,
- "tag_type": 2,
- "start": 46512
- },
- {
- "start": 46517,
- "end": 46529
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 46533,
- "tag_type": 1,
- "start": 46529
- },
- {
- "start": 46533,
- "end": 46541
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/3-/TopSellers.html?searchtype=genre"
- },
- "tag": "a",
- "end": 46622,
- "tag_type": 1,
- "start": 46541
- },
- {
- "start": 46622,
- "end": 46633
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 46637,
- "tag_type": 2,
- "start": 46633
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 46642,
- "tag_type": 2,
- "start": 46637
- },
- {
- "start": 46642,
- "end": 46654
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 46658,
- "tag_type": 1,
- "start": 46654
- },
- {
- "start": 46658,
- "end": 46666
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/3-/ComingSoon.html?searchtype=genre"
- },
- "tag": "a",
- "end": 46747,
- "tag_type": 1,
- "start": 46666
- },
- {
- "start": 46747,
- "end": 46758
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 46762,
- "tag_type": 2,
- "start": 46758
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 46767,
- "tag_type": 2,
- "start": 46762
- },
- {
- "start": 46767,
- "end": 46779
- },
- {
- "attributes": {
- "class": "bottom"
- },
- "tag": "li",
- "end": 46798,
- "tag_type": 1,
- "start": 46779
- },
- {
- "start": 46798,
- "end": 46806
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/3-/RecentReleases.html?searchtype=genre"
- },
- "tag": "a",
- "end": 46891,
- "tag_type": 1,
- "start": 46806
- },
- {
- "start": 46891,
- "end": 46906
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 46910,
- "tag_type": 2,
- "start": 46906
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 46915,
- "tag_type": 2,
- "start": 46910
- },
- {
- "start": 46915,
- "end": 46927
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 46932,
- "tag_type": 2,
- "start": 46927
- },
- {
- "start": 46932,
- "end": 46944
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 46948,
- "tag_type": 1,
- "start": 46944
- },
- {
- "start": 46948,
- "end": 46960
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 46964,
- "tag_type": 1,
- "start": 46960
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/996/1241/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 47046,
- "tag_type": 1,
- "start": 46964
- },
- {
- "start": 47046,
- "end": 47052
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 47056,
- "tag_type": 2,
- "start": 47052
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 47061,
- "tag_type": 2,
- "start": 47056
- },
- {
- "start": 47061,
- "end": 47073
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 47077,
- "tag_type": 1,
- "start": 47073
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/253/333/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 47158,
- "tag_type": 1,
- "start": 47077
- },
- {
- "start": 47158,
- "end": 47168
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 47172,
- "tag_type": 2,
- "start": 47168
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 47177,
- "tag_type": 2,
- "start": 47172
- },
- {
- "start": 47177,
- "end": 47189
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 47193,
- "tag_type": 1,
- "start": 47189
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/248/328/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 47274,
- "tag_type": 1,
- "start": 47193
- },
- {
- "start": 47274,
- "end": 47298
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 47302,
- "tag_type": 2,
- "start": 47298
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 47307,
- "tag_type": 2,
- "start": 47302
- },
- {
- "start": 47307,
- "end": 47319
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 47323,
- "tag_type": 1,
- "start": 47319
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/256/336/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 47404,
- "tag_type": 1,
- "start": 47323
- },
- {
- "start": 47404,
- "end": 47419
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 47423,
- "tag_type": 2,
- "start": 47419
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 47428,
- "tag_type": 2,
- "start": 47423
- },
- {
- "start": 47428,
- "end": 47440
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 47444,
- "tag_type": 1,
- "start": 47440
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/261/341/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 47525,
- "tag_type": 1,
- "start": 47444
- },
- {
- "start": 47525,
- "end": 47528
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 47532,
- "tag_type": 2,
- "start": 47528
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 47537,
- "tag_type": 2,
- "start": 47532
- },
- {
- "start": 47537,
- "end": 47549
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 47553,
- "tag_type": 1,
- "start": 47549
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/267/347/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 47634,
- "tag_type": 1,
- "start": 47553
- },
- {
- "start": 47634,
- "end": 47646
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 47650,
- "tag_type": 2,
- "start": 47646
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 47655,
- "tag_type": 2,
- "start": 47650
- },
- {
- "start": 47655,
- "end": 47667
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 47671,
- "tag_type": 1,
- "start": 47667
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/271/351/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 47752,
- "tag_type": 1,
- "start": 47671
- },
- {
- "start": 47752,
- "end": 47762
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 47766,
- "tag_type": 2,
- "start": 47762
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 47771,
- "tag_type": 2,
- "start": 47766
- },
- {
- "start": 47771,
- "end": 47783
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 47787,
- "tag_type": 1,
- "start": 47783
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/275/355/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 47868,
- "tag_type": 1,
- "start": 47787
- },
- {
- "start": 47868,
- "end": 47881
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 47885,
- "tag_type": 2,
- "start": 47881
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 47890,
- "tag_type": 2,
- "start": 47885
- },
- {
- "start": 47890,
- "end": 47902
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 47906,
- "tag_type": 1,
- "start": 47902
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/281/363/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 47987,
- "tag_type": 1,
- "start": 47906
- },
- {
- "start": 47987,
- "end": 47998
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 48002,
- "tag_type": 2,
- "start": 47998
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 48007,
- "tag_type": 2,
- "start": 48002
- },
- {
- "start": 48007,
- "end": 48019
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 48023,
- "tag_type": 1,
- "start": 48019
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/291/375/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 48104,
- "tag_type": 1,
- "start": 48023
- },
- {
- "start": 48104,
- "end": 48112
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 48116,
- "tag_type": 2,
- "start": 48112
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 48121,
- "tag_type": 2,
- "start": 48116
- },
- {
- "start": 48121,
- "end": 48133
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 48137,
- "tag_type": 1,
- "start": 48133
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/295/379/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 48218,
- "tag_type": 1,
- "start": 48137
- },
- {
- "start": 48218,
- "end": 48232
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 48236,
- "tag_type": 2,
- "start": 48232
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 48241,
- "tag_type": 2,
- "start": 48236
- },
- {
- "start": 48241,
- "end": 48253
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 48257,
- "tag_type": 1,
- "start": 48253
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/316/402/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 48338,
- "tag_type": 1,
- "start": 48257
- },
- {
- "start": 48338,
- "end": 48345
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 48349,
- "tag_type": 2,
- "start": 48345
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 48354,
- "tag_type": 2,
- "start": 48349
- },
- {
- "start": 48354,
- "end": 48366
- },
- {
- "attributes": {
- "class": "selected"
- },
- "tag": "li",
- "end": 48387,
- "tag_type": 1,
- "start": 48366
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/3-/RegionHome.html?searchtype=genre",
- "class": "this"
- },
- "tag": "a",
- "end": 48481,
- "tag_type": 1,
- "start": 48387
- },
- {
- "start": 48481,
- "end": 48491
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 48495,
- "tag_type": 2,
- "start": 48491
- },
- {
- "start": 48495,
- "end": 48503
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 48507,
- "tag_type": 1,
- "start": 48503
- },
- {
- "start": 48507,
- "end": 48519
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 48523,
- "tag_type": 1,
- "start": 48519
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/319/405/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 48604,
- "tag_type": 1,
- "start": 48523
- },
- {
- "start": 48604,
- "end": 48628
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 48632,
- "tag_type": 2,
- "start": 48628
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 48637,
- "tag_type": 2,
- "start": 48632
- },
- {
- "start": 48637,
- "end": 48649
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 48653,
- "tag_type": 1,
- "start": 48649
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/320/406/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 48734,
- "tag_type": 1,
- "start": 48653
- },
- {
- "start": 48734,
- "end": 48749
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 48753,
- "tag_type": 2,
- "start": 48749
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 48758,
- "tag_type": 2,
- "start": 48753
- },
- {
- "start": 48758,
- "end": 48770
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 48774,
- "tag_type": 1,
- "start": 48770
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/949/1189/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 48856,
- "tag_type": 1,
- "start": 48774
- },
- {
- "start": 48856,
- "end": 48876
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 48880,
- "tag_type": 2,
- "start": 48876
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 48885,
- "tag_type": 2,
- "start": 48880
- },
- {
- "start": 48885,
- "end": 48897
- },
- {
- "attributes": {
- "class": "bottom"
- },
- "tag": "li",
- "end": 48916,
- "tag_type": 1,
- "start": 48897
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/995/407/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 48997,
- "tag_type": 1,
- "start": 48916
- },
- {
- "start": 48997,
- "end": 49008
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 49012,
- "tag_type": 2,
- "start": 49008
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 49017,
- "tag_type": 2,
- "start": 49012
- },
- {
- "start": 49017,
- "end": 49029
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 49034,
- "tag_type": 2,
- "start": 49029
- },
- {
- "start": 49034,
- "end": 49038
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 49043,
- "tag_type": 2,
- "start": 49038
- },
- {
- "start": 49043,
- "end": 49055
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 49059,
- "tag_type": 1,
- "start": 49055
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/2168/1435/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 49142,
- "tag_type": 1,
- "start": 49059
- },
- {
- "start": 49142,
- "end": 49150
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 49154,
- "tag_type": 2,
- "start": 49150
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 49159,
- "tag_type": 2,
- "start": 49154
- },
- {
- "start": 49159,
- "end": 49171
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 49175,
- "tag_type": 1,
- "start": 49171
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/988/1236/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 49257,
- "tag_type": 1,
- "start": 49175
- },
- {
- "start": 49257,
- "end": 49277
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 49281,
- "tag_type": 2,
- "start": 49277
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 49286,
- "tag_type": 2,
- "start": 49281
- },
- {
- "start": 49286,
- "end": 49298
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 49302,
- "tag_type": 1,
- "start": 49298
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/371/471/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 49383,
- "tag_type": 1,
- "start": 49302
- },
- {
- "start": 49383,
- "end": 49391
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 49395,
- "tag_type": 2,
- "start": 49391
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 49400,
- "tag_type": 2,
- "start": 49395
- },
- {
- "start": 49400,
- "end": 49412
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 49417,
- "tag_type": 2,
- "start": 49412
- },
- {
- "start": 49417,
- "end": 49421
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 49425,
- "tag_type": 1,
- "start": 49421
- },
- {
- "start": 49425,
- "end": 49429
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 49433,
- "tag_type": 1,
- "start": 49429
- },
- {
- "start": 49433,
- "end": 49441
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/6-/GenreCategories.html",
- "class": "viewcats"
- },
- "tag": "a",
- "end": 49517,
- "tag_type": 1,
- "start": 49441
- },
- {
- "start": 49517,
- "end": 49538
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 49542,
- "tag_type": 2,
- "start": 49538
- },
- {
- "start": 49542,
- "end": 49546
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 49551,
- "tag_type": 2,
- "start": 49546
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 49556,
- "tag_type": 2,
- "start": 49551
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 49562,
- "tag_type": 2,
- "start": 49556
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 49568,
- "tag_type": 2,
- "start": 49562
- },
- {
- "attributes": {
- "class": "wrap"
- },
- "tag": "div",
- "end": 49586,
- "tag_type": 1,
- "start": 49568
- },
- {
- "attributes": {
- "cellspacing": "0"
- },
- "tag": "table",
- "end": 49609,
- "tag_type": 1,
- "start": 49586
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 49616,
- "tag_type": 1,
- "start": 49609
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 49620,
- "tag_type": 1,
- "start": 49616
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 49624,
- "tag_type": 1,
- "start": 49620
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 49629,
- "tag_type": 1,
- "start": 49624
- },
- {
- "attributes": {
- "href": "/campaign.aspx?campaign=4894&cid=4089054&dpr=0",
- "manual_cm_sp": "digibrick.jpg-_-LeftLandingPageBanner1-_-ELEC",
- "manual_cm_re": "Left-_-LandingPageBanner1-_-digibrick.jpg"
- },
- "tag": "a",
- "end": 49812,
- "tag_type": 1,
- "start": 49629
- },
- {
- "attributes": {
- "src": "http://images.play.com/PROMOTIONAL_IMAGES/LANDING_BANNERS/164402.jpg",
- "alt": "Digital Camera Store brick",
- "style": "border-width: 0px;"
- },
- "tag": "img",
- "end": 49952,
- "tag_type": 1,
- "start": 49812
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 49956,
- "tag_type": 2,
- "start": 49952
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 49962,
- "tag_type": 2,
- "start": 49956
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 49967,
- "tag_type": 2,
- "start": 49962
- },
- {
- "start": 49967,
- "end": 49987
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 49991,
- "tag_type": 1,
- "start": 49987
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 49996,
- "tag_type": 1,
- "start": 49991
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/3-/240913/2-/Promo.html?dpr=240913",
- "manual_cm_sp": "High-Def_35per.jpg-_-LeftLandingPageBanner2-_-ELEC",
- "manual_cm_re": "Left-_-LandingPageBanner2-_-High-Def_35per.jpg"
- },
- "tag": "a",
- "end": 50194,
- "tag_type": 1,
- "start": 49996
- },
- {
- "attributes": {
- "src": "http://images.play.com/PROMOTIONAL_IMAGES/LANDING_BANNERS/31800.jpg",
- "alt": "New Hi Def Technology",
- "style": "border-width: 0px;"
- },
- "tag": "img",
- "end": 50328,
- "tag_type": 1,
- "start": 50194
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 50332,
- "tag_type": 2,
- "start": 50328
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 50338,
- "tag_type": 2,
- "start": 50332
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 50343,
- "tag_type": 2,
- "start": 50338
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 50348,
- "tag_type": 2,
- "start": 50343
- },
- {
- "start": 50348,
- "end": 50356
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 50364,
- "tag_type": 2,
- "start": 50356
- },
- {
- "attributes": {},
- "tag": "table",
- "end": 50372,
- "tag_type": 2,
- "start": 50364
- },
- {
- "start": 50372,
- "end": 50376
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 50382,
- "tag_type": 2,
- "start": 50376
- },
- {
- "attributes": {
- "class": "hotpick wrap"
- },
- "tag": "div",
- "end": 50408,
- "tag_type": 1,
- "start": 50382
- },
- {
- "attributes": {
- "class": "boxhead"
- },
- "tag": "div",
- "end": 50429,
- "tag_type": 1,
- "start": 50408
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 50434,
- "tag_type": 1,
- "start": 50429
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 50439,
- "tag_type": 1,
- "start": 50434
- },
- {
- "start": 50439,
- "end": 50443
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/3-/HotPicksList.html?searchtype=genre"
- },
- "tag": "a",
- "end": 50526,
- "tag_type": 1,
- "start": 50443
- },
- {
- "start": 50526,
- "end": 50534
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 50538,
- "tag_type": 1,
- "start": 50534
- },
- {
- "start": 50538,
- "end": 50560
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 50565,
- "tag_type": 2,
- "start": 50560
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 50569,
- "tag_type": 2,
- "start": 50565
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 50575,
- "tag_type": 2,
- "start": 50569
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 50581,
- "tag_type": 2,
- "start": 50575
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 50587,
- "tag_type": 2,
- "start": 50581
- },
- {
- "attributes": {
- "class": "box"
- },
- "tag": "div",
- "end": 50604,
- "tag_type": 1,
- "start": 50587
- },
- {
- "attributes": {},
- "tag": "h5",
- "end": 50608,
- "tag_type": 1,
- "start": 50604
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/8986397/Samsung-Series-4-450-32-LE32B450-HD-Ready-Freeview-LCD-TV/Product.html"
- },
- "tag": "a",
- "end": 50725,
- "tag_type": 1,
- "start": 50608
- },
- {
- "start": 50725,
- "end": 50797
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 50801,
- "tag_type": 2,
- "start": 50797
- },
- {
- "attributes": {},
- "tag": "h5",
- "end": 50806,
- "tag_type": 2,
- "start": 50801
- },
- {
- "attributes": {
- "cellspacing": "0"
- },
- "tag": "table",
- "end": 50829,
- "tag_type": 1,
- "start": 50806
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 50836,
- "tag_type": 1,
- "start": 50829
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 50840,
- "tag_type": 1,
- "start": 50836
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 50844,
- "tag_type": 1,
- "start": 50840
- },
- {
- "attributes": {
- "class": "image"
- },
- "tag": "div",
- "end": 50863,
- "tag_type": 1,
- "start": 50844
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/8986397/Samsung-Series-4-450-32-LE32B450-HD-Ready-Freeview-LCD-TV/Product.html",
- "cssclass": "sideimagelink"
- },
- "tag": "a",
- "end": 51005,
- "tag_type": 1,
- "start": 50863
- },
- {
- "attributes": {
- "onerror": null,
- "src": "http://images.play.com/covers/8986397s.jpg",
- "alt": "Samsung Series 4 450 32" LE32B450 / HD Ready / Freeview / LCD TV (Black)",
- "style": "border-width: 0px; height: 60px; width: 60px;",
- "class": "sideimageline"
- },
- "tag": "img",
- "end": 51230,
- "tag_type": 1,
- "start": 51005
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 51234,
- "tag_type": 2,
- "start": 51230
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 51240,
- "tag_type": 2,
- "start": 51234
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 51245,
- "tag_type": 2,
- "start": 51240
- },
- {
- "attributes": {
- "class": "wide"
- },
- "tag": "td",
- "end": 51262,
- "tag_type": 1,
- "start": 51245
- },
- {
- "attributes": {},
- "tag": "h6",
- "end": 51266,
- "tag_type": 1,
- "start": 51262
- },
- {
- "start": 51266,
- "end": 51273
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 51279,
- "tag_type": 1,
- "start": 51273
- },
- {
- "start": 51279,
- "end": 51293
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 51300,
- "tag_type": 2,
- "start": 51293
- },
- {
- "attributes": {},
- "tag": "h6",
- "end": 51305,
- "tag_type": 2,
- "start": 51300
- },
- {
- "attributes": {
- "class": "saving"
- },
- "tag": "p",
- "end": 51323,
- "tag_type": 1,
- "start": 51305
- },
- {
- "start": 51323,
- "end": 51327
- },
- {
- "attributes": {},
- "tag": "br",
- "end": 51331,
- "tag_type": 1,
- "start": 51327
- },
- {
- "attributes": {
- "class": "rrp"
- },
- "tag": "span",
- "end": 51349,
- "tag_type": 1,
- "start": 51331
- },
- {
- "start": 51349,
- "end": 51356
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 51363,
- "tag_type": 2,
- "start": 51356
- },
- {
- "attributes": {},
- "tag": "br",
- "end": 51367,
- "tag_type": 1,
- "start": 51363
- },
- {
- "start": 51367,
- "end": 51376
- },
- {
- "attributes": {},
- "tag": "br",
- "end": 51380,
- "tag_type": 1,
- "start": 51376
- },
- {
- "attributes": {
- "class": "drop"
- },
- "tag": "span",
- "end": 51399,
- "tag_type": 1,
- "start": 51380
- },
- {
- "start": 51399,
- "end": 51406
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 51413,
- "tag_type": 2,
- "start": 51406
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 51417,
- "tag_type": 2,
- "start": 51413
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 51422,
- "tag_type": 2,
- "start": 51417
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 51427,
- "tag_type": 2,
- "start": 51422
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 51435,
- "tag_type": 2,
- "start": 51427
- },
- {
- "attributes": {},
- "tag": "table",
- "end": 51443,
- "tag_type": 2,
- "start": 51435
- },
- {
- "attributes": {
- "class": "more"
- },
- "tag": "p",
- "end": 51459,
- "tag_type": 1,
- "start": 51443
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/3-/HotPicksList.html?searchtype=genre"
- },
- "tag": "a",
- "end": 51542,
- "tag_type": 1,
- "start": 51459
- },
- {
- "start": 51542,
- "end": 51551
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 51557,
- "tag_type": 1,
- "start": 51551
- },
- {
- "start": 51557,
- "end": 51558
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 51565,
- "tag_type": 2,
- "start": 51558
- },
- {
- "start": 51565,
- "end": 51566
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 51570,
- "tag_type": 2,
- "start": 51566
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 51574,
- "tag_type": 2,
- "start": 51570
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 51580,
- "tag_type": 2,
- "start": 51574
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 51586,
- "tag_type": 2,
- "start": 51580
- },
- {
- "attributes": {
- "class": "recentlyviewed wrap"
- },
- "tag": "div",
- "end": 51619,
- "tag_type": 1,
- "start": 51586
- },
- {
- "attributes": {
- "class": "boxhead"
- },
- "tag": "div",
- "end": 51640,
- "tag_type": 1,
- "start": 51619
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 51645,
- "tag_type": 1,
- "start": 51640
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 51650,
- "tag_type": 1,
- "start": 51645
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 51654,
- "tag_type": 1,
- "start": 51650
- },
- {
- "start": 51654,
- "end": 51675
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 51680,
- "tag_type": 2,
- "start": 51675
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 51686,
- "tag_type": 2,
- "start": 51680
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 51692,
- "tag_type": 2,
- "start": 51686
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 51698,
- "tag_type": 2,
- "start": 51692
- },
- {
- "attributes": {
- "class": "box"
- },
- "tag": "div",
- "end": 51715,
- "tag_type": 1,
- "start": 51698
- },
- {
- "attributes": {},
- "tag": "h3",
- "end": 51719,
- "tag_type": 1,
- "start": 51715
- },
- {
- "start": 51719,
- "end": 51732
- },
- {
- "attributes": {},
- "tag": "h3",
- "end": 51737,
- "tag_type": 2,
- "start": 51732
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 51741,
- "tag_type": 1,
- "start": 51737
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 51745,
- "tag_type": 1,
- "start": 51741
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/8986420/Samsung-Series-5-550-37-LE37B550-HD-1080p-Freeview-LCD-TV/Product.html"
- },
- "tag": "a",
- "end": 51862,
- "tag_type": 1,
- "start": 51745
- },
- {
- "start": 51862,
- "end": 51934
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 51938,
- "tag_type": 2,
- "start": 51934
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 51943,
- "tag_type": 2,
- "start": 51938
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 51948,
- "tag_type": 2,
- "start": 51943
- },
- {
- "attributes": {
- "class": "more"
- },
- "tag": "p",
- "end": 51964,
- "tag_type": 1,
- "start": 51948
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/8986420/-/Product.html"
- },
- "tag": "a",
- "end": 52025,
- "tag_type": 1,
- "start": 51964
- },
- {
- "start": 52025,
- "end": 52041
- },
- {
- "attributes": {
- "class": "orangepanel"
- },
- "tag": "span",
- "end": 52067,
- "tag_type": 1,
- "start": 52041
- },
- {
- "start": 52067,
- "end": 52068
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 52075,
- "tag_type": 2,
- "start": 52068
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 52079,
- "tag_type": 2,
- "start": 52075
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 52083,
- "tag_type": 2,
- "start": 52079
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 52089,
- "tag_type": 2,
- "start": 52083
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 52095,
- "tag_type": 2,
- "start": 52089
- },
- {
- "attributes": {
- "class": "charts wrap",
- "id": "charts"
- },
- "tag": "div",
- "end": 52132,
- "tag_type": 1,
- "start": 52095
- },
- {
- "attributes": {
- "class": "boxhead"
- },
- "tag": "div",
- "end": 52153,
- "tag_type": 1,
- "start": 52132
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 52158,
- "tag_type": 1,
- "start": 52153
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 52163,
- "tag_type": 1,
- "start": 52158
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 52167,
- "tag_type": 1,
- "start": 52163
- },
- {
- "start": 52167,
- "end": 52173
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 52178,
- "tag_type": 2,
- "start": 52173
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 52184,
- "tag_type": 2,
- "start": 52178
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 52190,
- "tag_type": 2,
- "start": 52184
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 52196,
- "tag_type": 2,
- "start": 52190
- },
- {
- "attributes": {
- "class": "box"
- },
- "tag": "div",
- "end": 52213,
- "tag_type": 1,
- "start": 52196
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 52217,
- "tag_type": 1,
- "start": 52213
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52221,
- "tag_type": 1,
- "start": 52217
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/6-/TopSellers.html"
- },
- "tag": "a",
- "end": 52275,
- "tag_type": 1,
- "start": 52221
- },
- {
- "start": 52275,
- "end": 52286
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 52290,
- "tag_type": 2,
- "start": 52286
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 52294,
- "tag_type": 1,
- "start": 52290
- },
- {
- "attributes": {
- "class": "charts-topsellers"
- },
- "tag": "li",
- "end": 52324,
- "tag_type": 1,
- "start": 52294
- },
- {
- "attributes": {},
- "tag": "h3",
- "end": 52328,
- "tag_type": 1,
- "start": 52324
- },
- {
- "start": 52328,
- "end": 52339
- },
- {
- "attributes": {},
- "tag": "h3",
- "end": 52344,
- "tag_type": 2,
- "start": 52339
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52349,
- "tag_type": 2,
- "start": 52344
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52353,
- "tag_type": 1,
- "start": 52349
- },
- {
- "attributes": {
- "href": "/DVD/DVD/6-/TopSellers.html"
- },
- "tag": "a",
- "end": 52391,
- "tag_type": 1,
- "start": 52353
- },
- {
- "start": 52391,
- "end": 52394
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 52398,
- "tag_type": 2,
- "start": 52394
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52403,
- "tag_type": 2,
- "start": 52398
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52407,
- "tag_type": 1,
- "start": 52403
- },
- {
- "attributes": {
- "href": "/Music/CD/6-/TopSellers.html"
- },
- "tag": "a",
- "end": 52446,
- "tag_type": 1,
- "start": 52407
- },
- {
- "start": 52446,
- "end": 52451
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 52455,
- "tag_type": 2,
- "start": 52451
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52460,
- "tag_type": 2,
- "start": 52455
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52464,
- "tag_type": 1,
- "start": 52460
- },
- {
- "attributes": {
- "href": "/Books/Books/6-/TopSellers.html"
- },
- "tag": "a",
- "end": 52506,
- "tag_type": 1,
- "start": 52464
- },
- {
- "start": 52506,
- "end": 52511
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 52515,
- "tag_type": 2,
- "start": 52511
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52520,
- "tag_type": 2,
- "start": 52515
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52524,
- "tag_type": 1,
- "start": 52520
- },
- {
- "attributes": {
- "href": "/Tickets/TicketsEvent/6-/TopSellers.html"
- },
- "tag": "a",
- "end": 52575,
- "tag_type": 1,
- "start": 52524
- },
- {
- "start": 52575,
- "end": 52582
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 52586,
- "tag_type": 2,
- "start": 52582
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52591,
- "tag_type": 2,
- "start": 52586
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52595,
- "tag_type": 1,
- "start": 52591
- },
- {
- "attributes": {
- "href": "/Books/AudioBooks/6-/TopSellers.html"
- },
- "tag": "a",
- "end": 52642,
- "tag_type": 1,
- "start": 52595
- },
- {
- "start": 52642,
- "end": 52652
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 52656,
- "tag_type": 2,
- "start": 52652
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52661,
- "tag_type": 2,
- "start": 52656
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52665,
- "tag_type": 1,
- "start": 52661
- },
- {
- "attributes": {
- "href": "/Books/Calendars/6-/TopSellers.html"
- },
- "tag": "a",
- "end": 52711,
- "tag_type": 1,
- "start": 52665
- },
- {
- "start": 52711,
- "end": 52720
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 52724,
- "tag_type": 2,
- "start": 52720
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52729,
- "tag_type": 2,
- "start": 52724
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52733,
- "tag_type": 1,
- "start": 52729
- },
- {
- "attributes": {
- "href": "/Games/Xbox/6-/TopSellers.html"
- },
- "tag": "a",
- "end": 52774,
- "tag_type": 1,
- "start": 52733
- },
- {
- "start": 52774,
- "end": 52784
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 52788,
- "tag_type": 2,
- "start": 52784
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52793,
- "tag_type": 2,
- "start": 52788
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52797,
- "tag_type": 1,
- "start": 52793
- },
- {
- "attributes": {
- "href": "/Games/DS/6-/TopSellers.html"
- },
- "tag": "a",
- "end": 52836,
- "tag_type": 1,
- "start": 52797
- },
- {
- "start": 52836,
- "end": 52844
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 52848,
- "tag_type": 2,
- "start": 52844
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52853,
- "tag_type": 2,
- "start": 52848
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52857,
- "tag_type": 1,
- "start": 52853
- },
- {
- "attributes": {
- "href": "/Games/PlayStation2/6-/TopSellers.html"
- },
- "tag": "a",
- "end": 52906,
- "tag_type": 1,
- "start": 52857
- },
- {
- "start": 52906,
- "end": 52915
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 52919,
- "tag_type": 2,
- "start": 52915
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52924,
- "tag_type": 2,
- "start": 52919
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52928,
- "tag_type": 1,
- "start": 52924
- },
- {
- "attributes": {
- "href": "/Games/GameBoyAdvanced/6-/TopSellers.html"
- },
- "tag": "a",
- "end": 52980,
- "tag_type": 1,
- "start": 52928
- },
- {
- "start": 52980,
- "end": 52989
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 52993,
- "tag_type": 2,
- "start": 52989
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52998,
- "tag_type": 2,
- "start": 52993
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53002,
- "tag_type": 1,
- "start": 52998
- },
- {
- "attributes": {
- "href": "/Games/GameCube/6-/TopSellers.html"
- },
- "tag": "a",
- "end": 53047,
- "tag_type": 1,
- "start": 53002
- },
- {
- "start": 53047,
- "end": 53061
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 53065,
- "tag_type": 2,
- "start": 53061
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53070,
- "tag_type": 2,
- "start": 53065
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53074,
- "tag_type": 1,
- "start": 53070
- },
- {
- "attributes": {
- "href": "/Games/PC/6-/TopSellers.html"
- },
- "tag": "a",
- "end": 53113,
- "tag_type": 1,
- "start": 53074
- },
- {
- "start": 53113,
- "end": 53121
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 53125,
- "tag_type": 2,
- "start": 53121
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53130,
- "tag_type": 2,
- "start": 53125
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 53135,
- "tag_type": 2,
- "start": 53130
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53140,
- "tag_type": 2,
- "start": 53135
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53144,
- "tag_type": 1,
- "start": 53140
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/6-/PreOrderChart.html"
- },
- "tag": "a",
- "end": 53201,
- "tag_type": 1,
- "start": 53144
- },
- {
- "start": 53201,
- "end": 53212
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 53216,
- "tag_type": 2,
- "start": 53212
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 53220,
- "tag_type": 1,
- "start": 53216
- },
- {
- "attributes": {
- "class": "charts-comingsoon"
- },
- "tag": "li",
- "end": 53250,
- "tag_type": 1,
- "start": 53220
- },
- {
- "attributes": {},
- "tag": "h3",
- "end": 53254,
- "tag_type": 1,
- "start": 53250
- },
- {
- "start": 53254,
- "end": 53265
- },
- {
- "attributes": {},
- "tag": "h3",
- "end": 53270,
- "tag_type": 2,
- "start": 53265
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53275,
- "tag_type": 2,
- "start": 53270
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53279,
- "tag_type": 1,
- "start": 53275
- },
- {
- "attributes": {
- "href": "/DVD/DVD/6-/PreOrderChart.html"
- },
- "tag": "a",
- "end": 53320,
- "tag_type": 1,
- "start": 53279
- },
- {
- "start": 53320,
- "end": 53323
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 53327,
- "tag_type": 2,
- "start": 53323
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53332,
- "tag_type": 2,
- "start": 53327
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53336,
- "tag_type": 1,
- "start": 53332
- },
- {
- "attributes": {
- "href": "/Music/CD/6-/PreOrderChart.html"
- },
- "tag": "a",
- "end": 53378,
- "tag_type": 1,
- "start": 53336
- },
- {
- "start": 53378,
- "end": 53383
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 53387,
- "tag_type": 2,
- "start": 53383
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53392,
- "tag_type": 2,
- "start": 53387
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53396,
- "tag_type": 1,
- "start": 53392
- },
- {
- "attributes": {
- "href": "/Music/MP3-Download/6-/PreOrderChart.html"
- },
- "tag": "a",
- "end": 53448,
- "tag_type": 1,
- "start": 53396
- },
- {
- "start": 53448,
- "end": 53465
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 53469,
- "tag_type": 2,
- "start": 53465
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53474,
- "tag_type": 2,
- "start": 53469
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53478,
- "tag_type": 1,
- "start": 53474
- },
- {
- "attributes": {
- "href": "/Music/MP3-Download-Album/6-/PreOrderChart.html"
- },
- "tag": "a",
- "end": 53536,
- "tag_type": 1,
- "start": 53478
- },
- {
- "start": 53536,
- "end": 53555
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 53559,
- "tag_type": 2,
- "start": 53555
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53564,
- "tag_type": 2,
- "start": 53559
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53568,
- "tag_type": 1,
- "start": 53564
- },
- {
- "attributes": {
- "href": "/Music/MP3-Download-Track/6-/PreOrderChart.html"
- },
- "tag": "a",
- "end": 53626,
- "tag_type": 1,
- "start": 53568
- },
- {
- "start": 53626,
- "end": 53645
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 53649,
- "tag_type": 2,
- "start": 53645
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53654,
- "tag_type": 2,
- "start": 53649
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53658,
- "tag_type": 1,
- "start": 53654
- },
- {
- "attributes": {
- "href": "/Books/Books/6-/PreOrderChart.html"
- },
- "tag": "a",
- "end": 53703,
- "tag_type": 1,
- "start": 53658
- },
- {
- "start": 53703,
- "end": 53708
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 53712,
- "tag_type": 2,
- "start": 53708
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53717,
- "tag_type": 2,
- "start": 53712
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53721,
- "tag_type": 1,
- "start": 53717
- },
- {
- "attributes": {
- "href": "/Books/AudioBooks/6-/PreOrderChart.html"
- },
- "tag": "a",
- "end": 53771,
- "tag_type": 1,
- "start": 53721
- },
- {
- "start": 53771,
- "end": 53781
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 53785,
- "tag_type": 2,
- "start": 53781
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53790,
- "tag_type": 2,
- "start": 53785
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53794,
- "tag_type": 1,
- "start": 53790
- },
- {
- "attributes": {
- "href": "/Books/Calendars/6-/PreOrderChart.html"
- },
- "tag": "a",
- "end": 53843,
- "tag_type": 1,
- "start": 53794
- },
- {
- "start": 53843,
- "end": 53852
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 53856,
- "tag_type": 2,
- "start": 53852
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53861,
- "tag_type": 2,
- "start": 53856
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53865,
- "tag_type": 1,
- "start": 53861
- },
- {
- "attributes": {
- "href": "/Games/Xbox/6-/PreOrderChart.html"
- },
- "tag": "a",
- "end": 53909,
- "tag_type": 1,
- "start": 53865
- },
- {
- "start": 53909,
- "end": 53919
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 53923,
- "tag_type": 2,
- "start": 53919
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53928,
- "tag_type": 2,
- "start": 53923
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53932,
- "tag_type": 1,
- "start": 53928
- },
- {
- "attributes": {
- "href": "/Games/Xbox360/6-/PreOrderChart.html"
- },
- "tag": "a",
- "end": 53979,
- "tag_type": 1,
- "start": 53932
- },
- {
- "start": 53979,
- "end": 53993
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 53997,
- "tag_type": 2,
- "start": 53993
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54002,
- "tag_type": 2,
- "start": 53997
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54006,
- "tag_type": 1,
- "start": 54002
- },
- {
- "attributes": {
- "href": "/Games/PlayStation2/6-/PreOrderChart.html"
- },
- "tag": "a",
- "end": 54058,
- "tag_type": 1,
- "start": 54006
- },
- {
- "start": 54058,
- "end": 54067
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 54071,
- "tag_type": 2,
- "start": 54067
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54076,
- "tag_type": 2,
- "start": 54071
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54080,
- "tag_type": 1,
- "start": 54076
- },
- {
- "attributes": {
- "href": "/Games/PSP/6-/PreOrderChart.html"
- },
- "tag": "a",
- "end": 54123,
- "tag_type": 1,
- "start": 54080
- },
- {
- "start": 54123,
- "end": 54132
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 54136,
- "tag_type": 2,
- "start": 54132
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54141,
- "tag_type": 2,
- "start": 54136
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54145,
- "tag_type": 1,
- "start": 54141
- },
- {
- "attributes": {
- "href": "/Games/DS/6-/PreOrderChart.html"
- },
- "tag": "a",
- "end": 54187,
- "tag_type": 1,
- "start": 54145
- },
- {
- "start": 54187,
- "end": 54195
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 54199,
- "tag_type": 2,
- "start": 54195
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54204,
- "tag_type": 2,
- "start": 54199
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54208,
- "tag_type": 1,
- "start": 54204
- },
- {
- "attributes": {
- "href": "/Games/GameBoyAdvanced/6-/PreOrderChart.html"
- },
- "tag": "a",
- "end": 54263,
- "tag_type": 1,
- "start": 54208
- },
- {
- "start": 54263,
- "end": 54272
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 54276,
- "tag_type": 2,
- "start": 54272
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54281,
- "tag_type": 2,
- "start": 54276
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54285,
- "tag_type": 1,
- "start": 54281
- },
- {
- "attributes": {
- "href": "/Games/GameCube/6-/PreOrderChart.html"
- },
- "tag": "a",
- "end": 54333,
- "tag_type": 1,
- "start": 54285
- },
- {
- "start": 54333,
- "end": 54347
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 54351,
- "tag_type": 2,
- "start": 54347
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54356,
- "tag_type": 2,
- "start": 54351
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54360,
- "tag_type": 1,
- "start": 54356
- },
- {
- "attributes": {
- "href": "/Games/PC/6-/PreOrderChart.html"
- },
- "tag": "a",
- "end": 54402,
- "tag_type": 1,
- "start": 54360
- },
- {
- "start": 54402,
- "end": 54410
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 54414,
- "tag_type": 2,
- "start": 54410
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54419,
- "tag_type": 2,
- "start": 54414
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54423,
- "tag_type": 1,
- "start": 54419
- },
- {
- "attributes": {
- "href": "/Gadgets/Gadgets/6-/PreOrderChart.html"
- },
- "tag": "a",
- "end": 54472,
- "tag_type": 1,
- "start": 54423
- },
- {
- "start": 54472,
- "end": 54479
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 54483,
- "tag_type": 2,
- "start": 54479
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54488,
- "tag_type": 2,
- "start": 54483
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 54493,
- "tag_type": 2,
- "start": 54488
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54498,
- "tag_type": 2,
- "start": 54493
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54502,
- "tag_type": 1,
- "start": 54498
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/6-/RecentReleases.html"
- },
- "tag": "a",
- "end": 54560,
- "tag_type": 1,
- "start": 54502
- },
- {
- "start": 54560,
- "end": 54575
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 54579,
- "tag_type": 2,
- "start": 54575
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 54583,
- "tag_type": 1,
- "start": 54579
- },
- {
- "attributes": {
- "class": "charts-newreleases"
- },
- "tag": "li",
- "end": 54614,
- "tag_type": 1,
- "start": 54583
- },
- {
- "attributes": {},
- "tag": "h3",
- "end": 54618,
- "tag_type": 1,
- "start": 54614
- },
- {
- "start": 54618,
- "end": 54630
- },
- {
- "attributes": {},
- "tag": "h3",
- "end": 54635,
- "tag_type": 2,
- "start": 54630
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54640,
- "tag_type": 2,
- "start": 54635
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54644,
- "tag_type": 1,
- "start": 54640
- },
- {
- "attributes": {
- "href": "/DVD/DVD/6-/RecentReleases.html"
- },
- "tag": "a",
- "end": 54686,
- "tag_type": 1,
- "start": 54644
- },
- {
- "start": 54686,
- "end": 54689
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 54693,
- "tag_type": 2,
- "start": 54689
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54698,
- "tag_type": 2,
- "start": 54693
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54702,
- "tag_type": 1,
- "start": 54698
- },
- {
- "attributes": {
- "href": "/Music/CD/6-/RecentReleases.html"
- },
- "tag": "a",
- "end": 54745,
- "tag_type": 1,
- "start": 54702
- },
- {
- "start": 54745,
- "end": 54750
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 54754,
- "tag_type": 2,
- "start": 54750
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54759,
- "tag_type": 2,
- "start": 54754
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54763,
- "tag_type": 1,
- "start": 54759
- },
- {
- "attributes": {
- "href": "/Books/Books/6-/RecentReleases.html"
- },
- "tag": "a",
- "end": 54809,
- "tag_type": 1,
- "start": 54763
- },
- {
- "start": 54809,
- "end": 54814
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 54818,
- "tag_type": 2,
- "start": 54814
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54823,
- "tag_type": 2,
- "start": 54818
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54827,
- "tag_type": 1,
- "start": 54823
- },
- {
- "attributes": {
- "href": "/Books/AudioBooks/6-/RecentReleases.html"
- },
- "tag": "a",
- "end": 54878,
- "tag_type": 1,
- "start": 54827
- },
- {
- "start": 54878,
- "end": 54888
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 54892,
- "tag_type": 2,
- "start": 54888
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54897,
- "tag_type": 2,
- "start": 54892
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54901,
- "tag_type": 1,
- "start": 54897
- },
- {
- "attributes": {
- "href": "/Games/Xbox/6-/RecentReleases.html"
- },
- "tag": "a",
- "end": 54946,
- "tag_type": 1,
- "start": 54901
- },
- {
- "start": 54946,
- "end": 54956
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 54960,
- "tag_type": 2,
- "start": 54956
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54965,
- "tag_type": 2,
- "start": 54960
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54969,
- "tag_type": 1,
- "start": 54965
- },
- {
- "attributes": {
- "href": "/Games/PlayStation2/6-/RecentReleases.html"
- },
- "tag": "a",
- "end": 55022,
- "tag_type": 1,
- "start": 54969
- },
- {
- "start": 55022,
- "end": 55031
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 55035,
- "tag_type": 2,
- "start": 55031
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55040,
- "tag_type": 2,
- "start": 55035
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55044,
- "tag_type": 1,
- "start": 55040
- },
- {
- "attributes": {
- "href": "/Games/GameBoyAdvanced/6-/RecentReleases.html"
- },
- "tag": "a",
- "end": 55100,
- "tag_type": 1,
- "start": 55044
- },
- {
- "start": 55100,
- "end": 55109
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 55113,
- "tag_type": 2,
- "start": 55109
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55118,
- "tag_type": 2,
- "start": 55113
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55122,
- "tag_type": 1,
- "start": 55118
- },
- {
- "attributes": {
- "href": "/Games/GameCube/6-/RecentReleases.html"
- },
- "tag": "a",
- "end": 55171,
- "tag_type": 1,
- "start": 55122
- },
- {
- "start": 55171,
- "end": 55185
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 55189,
- "tag_type": 2,
- "start": 55185
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55194,
- "tag_type": 2,
- "start": 55189
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55198,
- "tag_type": 1,
- "start": 55194
- },
- {
- "attributes": {
- "href": "/Games/PC/6-/RecentReleases.html"
- },
- "tag": "a",
- "end": 55241,
- "tag_type": 1,
- "start": 55198
- },
- {
- "start": 55241,
- "end": 55249
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 55253,
- "tag_type": 2,
- "start": 55249
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55258,
- "tag_type": 2,
- "start": 55253
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55262,
- "tag_type": 1,
- "start": 55258
- },
- {
- "attributes": {
- "href": "/Gadgets/Gadgets/6-/RecentReleases.html"
- },
- "tag": "a",
- "end": 55312,
- "tag_type": 1,
- "start": 55262
- },
- {
- "start": 55312,
- "end": 55319
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 55323,
- "tag_type": 2,
- "start": 55319
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55328,
- "tag_type": 2,
- "start": 55323
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 55333,
- "tag_type": 2,
- "start": 55328
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55338,
- "tag_type": 2,
- "start": 55333
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55342,
- "tag_type": 1,
- "start": 55338
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/-/8986420/Samsung-Series-5-550-37-LE37B550-HD-1080p-Freeview-LCD-TV/Product.html?searchtype=genre"
- },
- "tag": "a",
- "end": 55485,
- "tag_type": 1,
- "start": 55342
- },
- {
- "start": 55485,
- "end": 55492
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 55496,
- "tag_type": 2,
- "start": 55492
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 55500,
- "tag_type": 1,
- "start": 55496
- },
- {
- "attributes": {
- "class": "charts-top100"
- },
- "tag": "li",
- "end": 55526,
- "tag_type": 1,
- "start": 55500
- },
- {
- "attributes": {},
- "tag": "h3",
- "end": 55530,
- "tag_type": 1,
- "start": 55526
- },
- {
- "start": 55530,
- "end": 55537
- },
- {
- "attributes": {},
- "tag": "h3",
- "end": 55542,
- "tag_type": 2,
- "start": 55537
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55547,
- "tag_type": 2,
- "start": 55542
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55551,
- "tag_type": 1,
- "start": 55547
- },
- {
- "attributes": {
- "href": "/DVD/DVD/6-/Top100.html"
- },
- "tag": "a",
- "end": 55585,
- "tag_type": 1,
- "start": 55551
- },
- {
- "start": 55585,
- "end": 55588
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 55592,
- "tag_type": 2,
- "start": 55588
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55597,
- "tag_type": 2,
- "start": 55592
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55601,
- "tag_type": 1,
- "start": 55597
- },
- {
- "attributes": {
- "href": "/Music/CD/6-/Top100.html"
- },
- "tag": "a",
- "end": 55636,
- "tag_type": 1,
- "start": 55601
- },
- {
- "start": 55636,
- "end": 55641
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 55645,
- "tag_type": 2,
- "start": 55641
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55650,
- "tag_type": 2,
- "start": 55645
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55654,
- "tag_type": 1,
- "start": 55650
- },
- {
- "attributes": {
- "href": "/Games/Xbox/6-/Top100.html"
- },
- "tag": "a",
- "end": 55691,
- "tag_type": 1,
- "start": 55654
- },
- {
- "start": 55691,
- "end": 55701
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 55705,
- "tag_type": 2,
- "start": 55701
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55710,
- "tag_type": 2,
- "start": 55705
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55714,
- "tag_type": 1,
- "start": 55710
- },
- {
- "attributes": {
- "href": "/Games/PlayStation2/6-/Top100.html"
- },
- "tag": "a",
- "end": 55759,
- "tag_type": 1,
- "start": 55714
- },
- {
- "start": 55759,
- "end": 55768
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 55772,
- "tag_type": 2,
- "start": 55768
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55777,
- "tag_type": 2,
- "start": 55772
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55781,
- "tag_type": 1,
- "start": 55777
- },
- {
- "attributes": {
- "href": "/Games/GameBoyAdvanced/6-/Top100.html"
- },
- "tag": "a",
- "end": 55829,
- "tag_type": 1,
- "start": 55781
- },
- {
- "start": 55829,
- "end": 55838
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 55842,
- "tag_type": 2,
- "start": 55838
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55847,
- "tag_type": 2,
- "start": 55842
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55851,
- "tag_type": 1,
- "start": 55847
- },
- {
- "attributes": {
- "href": "/Games/GameCube/6-/Top100.html"
- },
- "tag": "a",
- "end": 55892,
- "tag_type": 1,
- "start": 55851
- },
- {
- "start": 55892,
- "end": 55906
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 55910,
- "tag_type": 2,
- "start": 55906
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55915,
- "tag_type": 2,
- "start": 55910
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55919,
- "tag_type": 1,
- "start": 55915
- },
- {
- "attributes": {
- "href": "/Games/PC/6-/Top100.html"
- },
- "tag": "a",
- "end": 55954,
- "tag_type": 1,
- "start": 55919
- },
- {
- "start": 55954,
- "end": 55962
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 55966,
- "tag_type": 2,
- "start": 55962
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55971,
- "tag_type": 2,
- "start": 55966
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 55976,
- "tag_type": 2,
- "start": 55971
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55981,
- "tag_type": 2,
- "start": 55976
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 55986,
- "tag_type": 2,
- "start": 55981
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 55992,
- "tag_type": 2,
- "start": 55986
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 55998,
- "tag_type": 2,
- "start": 55992
- },
- {
- "attributes": {
- "class": "help wrap"
- },
- "tag": "div",
- "end": 56021,
- "tag_type": 1,
- "start": 55998
- },
- {
- "attributes": {
- "class": "boxhead"
- },
- "tag": "div",
- "end": 56042,
- "tag_type": 1,
- "start": 56021
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 56047,
- "tag_type": 1,
- "start": 56042
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 56052,
- "tag_type": 1,
- "start": 56047
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 56056,
- "tag_type": 1,
- "start": 56052
- },
- {
- "start": 56056,
- "end": 56069
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 56074,
- "tag_type": 2,
- "start": 56069
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 56080,
- "tag_type": 2,
- "start": 56074
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 56086,
- "tag_type": 2,
- "start": 56080
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 56092,
- "tag_type": 2,
- "start": 56086
- },
- {
- "attributes": {
- "class": "box"
- },
- "tag": "div",
- "end": 56109,
- "tag_type": 1,
- "start": 56092
- },
- {
- "attributes": {
- "href": "/HOME/HOME/6-/Help.html?page=helpdesk",
- "title": "Play.com Helpdesk"
- },
- "tag": "a",
- "end": 56183,
- "tag_type": 1,
- "start": 56109
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteCSS/Play/Live1/img/brand/helpdesk.gif",
- "style": "border-style: none; border-width: 0px; height: 56px; width: 163px;",
- "title": "Play.com Helpdesk"
- },
- "tag": "img",
- "end": 56360,
- "tag_type": 1,
- "start": 56183
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 56364,
- "tag_type": 2,
- "start": 56360
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 56370,
- "tag_type": 2,
- "start": 56364
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 56376,
- "tag_type": 2,
- "start": 56370
- },
- {
- "attributes": {
- "class": "sidebanner wrap"
- },
- "tag": "div",
- "end": 56405,
- "tag_type": 1,
- "start": 56376
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 56410,
- "tag_type": 1,
- "start": 56405
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/8821116/-/Product.html?page=title&dpr=0",
- "manual_cm_re": "Left-_-SideBanner1-_-ELEC_freeAlbumDownload_double.jpg"
- },
- "tag": "a",
- "end": 56562,
- "tag_type": 1,
- "start": 56410
- },
- {
- "attributes": {
- "src": "http://images.play.com/PROMOTIONAL_IMAGES/SIDE_BANNERS/253462.jpg",
- "alt": "Free album download - Double",
- "style": "border-width: 0px;"
- },
- "tag": "img",
- "end": 56701,
- "tag_type": 1,
- "start": 56562
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 56705,
- "tag_type": 2,
- "start": 56701
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 56711,
- "tag_type": 2,
- "start": 56705
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 56717,
- "tag_type": 2,
- "start": 56711
- },
- {
- "attributes": {
- "class": "sidebanner wrap"
- },
- "tag": "div",
- "end": 56746,
- "tag_type": 1,
- "start": 56717
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 56751,
- "tag_type": 1,
- "start": 56746
- },
- {
- "attributes": {
- "href": "/Campaign.html?campaign=6453&cid=2839989&dpr=0",
- "manual_cm_sp": "ELEC_SonyHeadphones.jpg-_-LeftSideBanner3-_-ELEC",
- "manual_cm_re": "Left-_-SideBanner3-_-ELEC_SonyHeadphones.jpg"
- },
- "tag": "a",
- "end": 56940,
- "tag_type": 1,
- "start": 56751
- },
- {
- "attributes": {
- "src": "http://images.play.com/PROMOTIONAL_IMAGES/SIDE_BANNERS/208001.jpg",
- "alt": "Sony Headphones",
- "style": "border-width: 0px;"
- },
- "tag": "img",
- "end": 57066,
- "tag_type": 1,
- "start": 56940
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 57070,
- "tag_type": 2,
- "start": 57066
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 57076,
- "tag_type": 2,
- "start": 57070
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 57082,
- "tag_type": 2,
- "start": 57076
- },
- {
- "attributes": {
- "class": "sidebanner wrap"
- },
- "tag": "div",
- "end": 57111,
- "tag_type": 1,
- "start": 57082
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 57116,
- "tag_type": 1,
- "start": 57111
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/3-/255882/2-/Promo.html?dpr=255882",
- "manual_cm_sp": "ELEC_ToshibaDVD_GBP.jpg_GBP-_-LeftSideBanner4-_-ELEC",
- "manual_cm_re": "Left-_-SideBanner4-_-ELEC_ToshibaDVD_GBP.jpg_GBP"
- },
- "tag": "a",
- "end": 57318,
- "tag_type": 1,
- "start": 57116
- },
- {
- "attributes": {
- "src": "http://images.play.com/PROMOTIONAL_IMAGES/SIDE_BANNERS/181202_GBP.jpg",
- "alt": "Toshiba DVD Players",
- "style": "border-width: 0px;"
- },
- "tag": "img",
- "end": 57452,
- "tag_type": 1,
- "start": 57318
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 57456,
- "tag_type": 2,
- "start": 57452
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 57462,
- "tag_type": 2,
- "start": 57456
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 57468,
- "tag_type": 2,
- "start": 57462
- },
- {
- "attributes": {
- "class": "sidebanner wrap"
- },
- "tag": "div",
- "end": 57497,
- "tag_type": 1,
- "start": 57468
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 57502,
- "tag_type": 1,
- "start": 57497
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/3-/166828/2-/Promo.html?dpr=166828",
- "manual_cm_sp": "ELEC_LogitechRemotes.gif-_-LeftSideBanner5-_-ELEC",
- "manual_cm_re": "Left-_-SideBanner5-_-ELEC_LogitechRemotes.gif"
- },
- "tag": "a",
- "end": 57698,
- "tag_type": 1,
- "start": 57502
- },
- {
- "attributes": {
- "src": "http://images.play.com/PROMOTIONAL_IMAGES/SIDE_BANNERS/218403.gif",
- "alt": "Logitech Remotes",
- "style": "border-width: 0px;"
- },
- "tag": "img",
- "end": 57825,
- "tag_type": 1,
- "start": 57698
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 57829,
- "tag_type": 2,
- "start": 57825
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 57835,
- "tag_type": 2,
- "start": 57829
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 57841,
- "tag_type": 2,
- "start": 57835
- },
- {
- "attributes": {
- "class": "playstores wrap"
- },
- "tag": "div",
- "end": 57870,
- "tag_type": 1,
- "start": 57841
- },
- {
- "attributes": {
- "class": "boxhead"
- },
- "tag": "div",
- "end": 57891,
- "tag_type": 1,
- "start": 57870
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 57896,
- "tag_type": 1,
- "start": 57891
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 57901,
- "tag_type": 1,
- "start": 57896
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 57905,
- "tag_type": 1,
- "start": 57901
- },
- {
- "start": 57905,
- "end": 57916
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 57921,
- "tag_type": 2,
- "start": 57916
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 57927,
- "tag_type": 2,
- "start": 57921
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 57933,
- "tag_type": 2,
- "start": 57927
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 57939,
- "tag_type": 2,
- "start": 57933
- },
- {
- "attributes": {
- "class": "box"
- },
- "tag": "div",
- "end": 57956,
- "tag_type": 1,
- "start": 57939
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 57961,
- "tag_type": 1,
- "start": 57956
- },
- {
- "attributes": {
- "href": "/HOME/HOME/6-/Campaign.html?campaign=6383&cid=5044118"
- },
- "tag": "a",
- "end": 58029,
- "tag_type": 1,
- "start": 57961
- },
- {
- "attributes": {
- "src": "http://images.play.com/newimages/store_disney.gif",
- "style": "border-width: 0px;"
- },
- "tag": "img",
- "end": 58117,
- "tag_type": 1,
- "start": 58029
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 58121,
- "tag_type": 2,
- "start": 58117
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 58127,
- "tag_type": 2,
- "start": 58121
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 58132,
- "tag_type": 1,
- "start": 58127
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/6-/Campaign.html?campaign=2450&cid=9602708"
- },
- "tag": "a",
- "end": 58214,
- "tag_type": 1,
- "start": 58132
- },
- {
- "attributes": {
- "src": "http://images.play.com/newimages/store_sony.gif",
- "style": "border-width: 0px;"
- },
- "tag": "img",
- "end": 58300,
- "tag_type": 1,
- "start": 58214
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 58304,
- "tag_type": 2,
- "start": 58300
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 58310,
- "tag_type": 2,
- "start": 58304
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 58315,
- "tag_type": 1,
- "start": 58310
- },
- {
- "attributes": {
- "href": "/HOME/HOME/6-/Campaign.html?campaign=621&cid=6096431"
- },
- "tag": "a",
- "end": 58382,
- "tag_type": 1,
- "start": 58315
- },
- {
- "attributes": {
- "src": "http://images.play.com/newimages/store_dummies.gif",
- "style": "border-width: 0px;"
- },
- "tag": "img",
- "end": 58471,
- "tag_type": 1,
- "start": 58382
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 58475,
- "tag_type": 2,
- "start": 58471
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 58481,
- "tag_type": 2,
- "start": 58475
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 58486,
- "tag_type": 1,
- "start": 58481
- },
- {
- "attributes": {
- "href": "/HOME/HOME/6-/Campaign.html?campaign=6001&cid=3425819"
- },
- "tag": "a",
- "end": 58554,
- "tag_type": 1,
- "start": 58486
- },
- {
- "attributes": {
- "src": "http://images.play.com/newimages/store_nintendo.jpg",
- "style": "border-width: 0px;"
- },
- "tag": "img",
- "end": 58644,
- "tag_type": 1,
- "start": 58554
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 58648,
- "tag_type": 2,
- "start": 58644
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 58654,
- "tag_type": 2,
- "start": 58648
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 58659,
- "tag_type": 1,
- "start": 58654
- },
- {
- "attributes": {
- "href": "/HOME/HOME/6-/Campaign.html?campaign=2030&cid=6256562"
- },
- "tag": "a",
- "end": 58727,
- "tag_type": 1,
- "start": 58659
- },
- {
- "attributes": {
- "src": "http://images.play.com/newimages/ea_store.gif",
- "style": "border-width: 0px;"
- },
- "tag": "img",
- "end": 58811,
- "tag_type": 1,
- "start": 58727
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 58815,
- "tag_type": 2,
- "start": 58811
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 58821,
- "tag_type": 2,
- "start": 58815
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 58826,
- "tag_type": 1,
- "start": 58821
- },
- {
- "attributes": {
- "href": "/HOME/HOME/6-/Campaign.html?campaign=2720&cid=6896143"
- },
- "tag": "a",
- "end": 58894,
- "tag_type": 1,
- "start": 58826
- },
- {
- "attributes": {
- "src": "http://images.play.com/newimages/store_hbo.gif",
- "style": "border-width: 0px;"
- },
- "tag": "img",
- "end": 58979,
- "tag_type": 1,
- "start": 58894
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 58983,
- "tag_type": 2,
- "start": 58979
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 58989,
- "tag_type": 2,
- "start": 58983
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 58995,
- "tag_type": 2,
- "start": 58989
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 59001,
- "tag_type": 2,
- "start": 58995
- },
- {
- "start": 59001,
- "end": 59009
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 59015,
- "tag_type": 2,
- "start": 59009
- },
- {
- "start": 59015,
- "end": 59019
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 59025,
- "tag_type": 2,
- "start": 59019
- },
- {
- "start": 59025,
- "end": 59029
- },
- {
- "attributes": {
- "class": "clear"
- },
- "tag": "div",
- "end": 59048,
- "tag_type": 1,
- "start": 59029
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 59054,
- "tag_type": 2,
- "start": 59048
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 59060,
- "tag_type": 2,
- "start": 59054
- },
- {
- "start": 59060,
- "end": 59080
- },
- {
- "attributes": {
- "class": null,
- "id": "rightCol"
- },
- "tag": "div",
- "end": 59108,
- "tag_type": 1,
- "start": 59080
- },
- {
- "start": 59108,
- "end": 59132
- },
- {
- "attributes": {
- "class": "column"
- },
- "tag": "div",
- "end": 59152,
- "tag_type": 1,
- "start": 59132
- },
- {
- "start": 59152,
- "end": 59172
- },
- {
- "attributes": {
- "class": "shortbanner wrap"
- },
- "tag": "div",
- "end": 59202,
- "tag_type": 1,
- "start": 59172
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 59207,
- "tag_type": 1,
- "start": 59202
- },
- {
- "attributes": {
- "href": "/campaign.aspx?campaign=6688&cid=5685422&dpr=0",
- "manual_cm_sp": "ELEC_valpak.jpg-_-RightShortBanner1-_-ELEC",
- "manual_cm_re": "Right-_-ShortBanner1-_-ELEC_valpak.jpg"
- },
- "tag": "a",
- "end": 59384,
- "tag_type": 1,
- "start": 59207
- },
- {
- "attributes": {
- "src": "http://images.play.com/PROMOTIONAL_IMAGES/SHORT_BANNERS/220656.jpg",
- "alt": "Valpak - short banner",
- "style": "border-width: 0px;",
- "class": null
- },
- "tag": "img",
- "end": 59526,
- "tag_type": 1,
- "start": 59384
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 59530,
- "tag_type": 2,
- "start": 59526
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 59536,
- "tag_type": 2,
- "start": 59530
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 59542,
- "tag_type": 2,
- "start": 59536
- },
- {
- "attributes": {
- "class": "shortbanner wrap"
- },
- "tag": "div",
- "end": 59572,
- "tag_type": 1,
- "start": 59542
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 59577,
- "tag_type": 1,
- "start": 59572
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/3-/2074/2-/Promo.html?dpr=2074",
- "manual_cm_sp": "ELEC_I-Pod-Speakers.jpg-_-RightShortBanner2-_-ELEC",
- "manual_cm_re": "Right-_-ShortBanner2-_-ELEC_I-Pod-Speakers.jpg"
- },
- "tag": "a",
- "end": 59771,
- "tag_type": 1,
- "start": 59577
- },
- {
- "attributes": {
- "src": "http://images.play.com/PROMOTIONAL_IMAGES/SHORT_BANNERS/10287.jpg",
- "alt": "iPod speakers Save Up To 50%",
- "style": "border-width: 0px;"
- },
- "tag": "img",
- "end": 59910,
- "tag_type": 1,
- "start": 59771
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 59914,
- "tag_type": 2,
- "start": 59910
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 59920,
- "tag_type": 2,
- "start": 59914
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 59926,
- "tag_type": 2,
- "start": 59920
- },
- {
- "attributes": {
- "class": "countdown wrap"
- },
- "tag": "div",
- "end": 59954,
- "tag_type": 1,
- "start": 59926
- },
- {
- "attributes": {
- "class": "boxhead"
- },
- "tag": "div",
- "end": 59975,
- "tag_type": 1,
- "start": 59954
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 59980,
- "tag_type": 1,
- "start": 59975
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 59985,
- "tag_type": 1,
- "start": 59980
- },
- {
- "start": 59985,
- "end": 59989
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/3-/CountDownList.html?searchtype=genre"
- },
- "tag": "a",
- "end": 60073,
- "tag_type": 1,
- "start": 59989
- },
- {
- "start": 60073,
- "end": 60081
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 60085,
- "tag_type": 1,
- "start": 60081
- },
- {
- "start": 60085,
- "end": 60094
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 60099,
- "tag_type": 2,
- "start": 60094
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 60103,
- "tag_type": 2,
- "start": 60099
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 60109,
- "tag_type": 2,
- "start": 60103
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 60115,
- "tag_type": 2,
- "start": 60109
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 60121,
- "tag_type": 2,
- "start": 60115
- },
- {
- "attributes": {
- "class": "box"
- },
- "tag": "div",
- "end": 60138,
- "tag_type": 1,
- "start": 60121
- },
- {
- "attributes": {
- "cellspacing": "0"
- },
- "tag": "table",
- "end": 60161,
- "tag_type": 1,
- "start": 60138
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 60168,
- "tag_type": 1,
- "start": 60161
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 60172,
- "tag_type": 1,
- "start": 60168
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 60176,
- "tag_type": 1,
- "start": 60172
- },
- {
- "attributes": {
- "class": "image"
- },
- "tag": "div",
- "end": 60195,
- "tag_type": 1,
- "start": 60176
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/-/8839534/Sony-Bravia-S-Series-26-26S5500-HD-Ready-Freeview-Widescreen-LCD-TV/Product.html?searchtype=genre"
- },
- "tag": "a",
- "end": 60348,
- "tag_type": 1,
- "start": 60195
- },
- {
- "attributes": {
- "onerror": null,
- "src": "http://images.play.com/covers/8839534s.jpg",
- "alt": "Sony Bravia S Series 26" 26S5500 HD Ready Freeview Widescreen LCD TV",
- "style": "border-width: 0px; height: 60px; width: 60px;",
- "class": "sideimageline"
- },
- "tag": "img",
- "end": 60569,
- "tag_type": 1,
- "start": 60348
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 60573,
- "tag_type": 2,
- "start": 60569
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 60579,
- "tag_type": 2,
- "start": 60573
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 60584,
- "tag_type": 2,
- "start": 60579
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 60588,
- "tag_type": 1,
- "start": 60584
- },
- {
- "attributes": {
- "class": "days"
- },
- "tag": "div",
- "end": 60606,
- "tag_type": 1,
- "start": 60588
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteCSS/Play/Live1/img/countdown/28.gif",
- "style": "border-width: 0px;",
- "border": "0"
- },
- "tag": "img",
- "end": 60718,
- "tag_type": 1,
- "start": 60606
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 60724,
- "tag_type": 2,
- "start": 60718
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 60729,
- "tag_type": 2,
- "start": 60724
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 60734,
- "tag_type": 2,
- "start": 60729
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 60738,
- "tag_type": 1,
- "start": 60734
- },
- {
- "attributes": {
- "colspan": "2"
- },
- "tag": "td",
- "end": 60754,
- "tag_type": 1,
- "start": 60738
- },
- {
- "attributes": {},
- "tag": "h5",
- "end": 60758,
- "tag_type": 1,
- "start": 60754
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/-/8839534/Sony-Bravia-S-Series-26-26S5500-HD-Ready-Freeview-Widescreen-LCD-TV/Product.html?searchtype=genre"
- },
- "tag": "a",
- "end": 60911,
- "tag_type": 1,
- "start": 60758
- },
- {
- "start": 60911,
- "end": 60979
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 60983,
- "tag_type": 2,
- "start": 60979
- },
- {
- "attributes": {},
- "tag": "h5",
- "end": 60988,
- "tag_type": 2,
- "start": 60983
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 60993,
- "tag_type": 2,
- "start": 60988
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 60998,
- "tag_type": 2,
- "start": 60993
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 61002,
- "tag_type": 1,
- "start": 60998
- },
- {
- "attributes": {
- "colspan": "2"
- },
- "tag": "td",
- "end": 61018,
- "tag_type": 1,
- "start": 61002
- },
- {
- "attributes": {},
- "tag": "h6",
- "end": 61022,
- "tag_type": 1,
- "start": 61018
- },
- {
- "attributes": {},
- "tag": "h6",
- "end": 61027,
- "tag_type": 2,
- "start": 61022
- },
- {
- "attributes": {},
- "tag": "h6",
- "end": 61031,
- "tag_type": 1,
- "start": 61027
- },
- {
- "start": 61031,
- "end": 61038
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 61044,
- "tag_type": 1,
- "start": 61038
- },
- {
- "start": 61044,
- "end": 61058
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 61065,
- "tag_type": 2,
- "start": 61058
- },
- {
- "attributes": {},
- "tag": "h6",
- "end": 61070,
- "tag_type": 2,
- "start": 61065
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 61075,
- "tag_type": 2,
- "start": 61070
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 61080,
- "tag_type": 2,
- "start": 61075
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 61088,
- "tag_type": 2,
- "start": 61080
- },
- {
- "attributes": {},
- "tag": "table",
- "end": 61096,
- "tag_type": 2,
- "start": 61088
- },
- {
- "attributes": {
- "class": "more"
- },
- "tag": "p",
- "end": 61112,
- "tag_type": 1,
- "start": 61096
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/3-/CountDownList.html?searchtype=genre"
- },
- "tag": "a",
- "end": 61196,
- "tag_type": 1,
- "start": 61112
- },
- {
- "start": 61196,
- "end": 61205
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 61211,
- "tag_type": 1,
- "start": 61205
- },
- {
- "start": 61211,
- "end": 61212
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 61219,
- "tag_type": 2,
- "start": 61212
- },
- {
- "start": 61219,
- "end": 61220
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 61224,
- "tag_type": 2,
- "start": 61220
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 61228,
- "tag_type": 2,
- "start": 61224
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 61234,
- "tag_type": 2,
- "start": 61228
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 61240,
- "tag_type": 2,
- "start": 61234
- },
- {
- "attributes": {
- "class": "topsellers wrap"
- },
- "tag": "div",
- "end": 61269,
- "tag_type": 1,
- "start": 61240
- },
- {
- "attributes": {
- "class": "boxhead"
- },
- "tag": "div",
- "end": 61290,
- "tag_type": 1,
- "start": 61269
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 61295,
- "tag_type": 1,
- "start": 61290
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 61300,
- "tag_type": 1,
- "start": 61295
- },
- {
- "start": 61300,
- "end": 61304
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/3-/TopSellers.html?searchtype=genre"
- },
- "tag": "a",
- "end": 61385,
- "tag_type": 1,
- "start": 61304
- },
- {
- "start": 61385,
- "end": 61393
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 61397,
- "tag_type": 1,
- "start": 61393
- },
- {
- "start": 61397,
- "end": 61420
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 61425,
- "tag_type": 2,
- "start": 61420
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 61429,
- "tag_type": 2,
- "start": 61425
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 61435,
- "tag_type": 2,
- "start": 61429
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 61441,
- "tag_type": 2,
- "start": 61435
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 61447,
- "tag_type": 2,
- "start": 61441
- },
- {
- "attributes": {
- "class": "box"
- },
- "tag": "div",
- "end": 61464,
- "tag_type": 1,
- "start": 61447
- },
- {
- "attributes": {},
- "tag": "ol",
- "end": 61468,
- "tag_type": 1,
- "start": 61464
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 61472,
- "tag_type": 1,
- "start": 61468
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/8839538/Sony-Bravia-S-Series-32-32S5500-HD-Ready-Freeview-Widescreen-LCD-TV/Product.html",
- "class": "chart01",
- "title": "Price: \u00a3379.99 Free Delivery"
- },
- "tag": "a",
- "end": 61652,
- "tag_type": 1,
- "start": 61472
- },
- {
- "attributes": {
- "class": "title"
- },
- "tag": "span",
- "end": 61672,
- "tag_type": 1,
- "start": 61652
- },
- {
- "start": 61672,
- "end": 61773
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 61780,
- "tag_type": 2,
- "start": 61773
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 61784,
- "tag_type": 2,
- "start": 61780
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 61789,
- "tag_type": 2,
- "start": 61784
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 61793,
- "tag_type": 1,
- "start": 61789
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/8986397/Samsung-Series-4-450-32-LE32B450-HD-Ready-Freeview-LCD-TV/Product.html",
- "class": "chart02",
- "title": "Price: \u00a3334.99 Free Delivery"
- },
- "tag": "a",
- "end": 61963,
- "tag_type": 1,
- "start": 61793
- },
- {
- "attributes": {
- "class": "title"
- },
- "tag": "span",
- "end": 61983,
- "tag_type": 1,
- "start": 61963
- },
- {
- "start": 61983,
- "end": 62055
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 62062,
- "tag_type": 2,
- "start": 62055
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 62066,
- "tag_type": 2,
- "start": 62062
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 62071,
- "tag_type": 2,
- "start": 62066
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 62075,
- "tag_type": 1,
- "start": 62071
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/9159265/Humax-FoxSat-HDR-Freesat-320GB-HDD-DTR-HD-Recorder/Product.html",
- "class": "chart03",
- "title": "Price: \u00a3249.99 Free Delivery"
- },
- "tag": "a",
- "end": 62238,
- "tag_type": 1,
- "start": 62075
- },
- {
- "attributes": {
- "class": "title"
- },
- "tag": "span",
- "end": 62258,
- "tag_type": 1,
- "start": 62238
- },
- {
- "start": 62258,
- "end": 62308
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 62315,
- "tag_type": 2,
- "start": 62308
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 62319,
- "tag_type": 2,
- "start": 62315
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 62324,
- "tag_type": 2,
- "start": 62319
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 62328,
- "tag_type": 1,
- "start": 62324
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/6904657/Vivanco-Universal-Sky-Remote-Control-Sky-Sky+/Product.html",
- "class": "chart04",
- "title": "Price: \u00a34.99 Free Delivery"
- },
- "tag": "a",
- "end": 62484,
- "tag_type": 1,
- "start": 62328
- },
- {
- "attributes": {
- "class": "title"
- },
- "tag": "span",
- "end": 62504,
- "tag_type": 1,
- "start": 62484
- },
- {
- "start": 62504,
- "end": 62551
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 62558,
- "tag_type": 2,
- "start": 62551
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 62562,
- "tag_type": 2,
- "start": 62558
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 62567,
- "tag_type": 2,
- "start": 62562
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 62571,
- "tag_type": 1,
- "start": 62567
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/5985149/Synn-LTS4201-B-Glass-Stand-for-TVs-Up-To-42-/Product.html",
- "class": "chart05",
- "title": "Price: \u00a399.99 Free Delivery"
- },
- "tag": "a",
- "end": 62727,
- "tag_type": 1,
- "start": 62571
- },
- {
- "attributes": {
- "class": "title"
- },
- "tag": "span",
- "end": 62747,
- "tag_type": 1,
- "start": 62727
- },
- {
- "start": 62747,
- "end": 62808
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 62815,
- "tag_type": 2,
- "start": 62808
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 62819,
- "tag_type": 2,
- "start": 62815
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 62824,
- "tag_type": 2,
- "start": 62819
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 62828,
- "tag_type": 1,
- "start": 62824
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/9404087/LG-22-M227WD-HD-1080p-Freeview-Widescreen-LCD-TV/Product.html",
- "class": "chart06",
- "title": "Price: \u00a3199.99 Free Delivery"
- },
- "tag": "a",
- "end": 62989,
- "tag_type": 1,
- "start": 62828
- },
- {
- "attributes": {
- "class": "title"
- },
- "tag": "span",
- "end": 63009,
- "tag_type": 1,
- "start": 62989
- },
- {
- "start": 63009,
- "end": 63058
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 63065,
- "tag_type": 2,
- "start": 63058
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 63069,
- "tag_type": 2,
- "start": 63065
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 63074,
- "tag_type": 2,
- "start": 63069
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 63078,
- "tag_type": 1,
- "start": 63074
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/1112311/Linx-1-2m-Luxury-24k-Gold-Plated-HDMI-Cable/Product.html",
- "class": "chart07",
- "title": "Price: \u00a38.99 Free Delivery"
- },
- "tag": "a",
- "end": 63232,
- "tag_type": 1,
- "start": 63078
- },
- {
- "attributes": {
- "class": "title"
- },
- "tag": "span",
- "end": 63252,
- "tag_type": 1,
- "start": 63232
- },
- {
- "start": 63252,
- "end": 63296
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 63303,
- "tag_type": 2,
- "start": 63296
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 63307,
- "tag_type": 2,
- "start": 63303
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 63312,
- "tag_type": 2,
- "start": 63307
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 63316,
- "tag_type": 1,
- "start": 63312
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/5447796/Samsung-20-T200-HD-Ready-Freeview-Widescreen-LCD-TV/Product.html",
- "class": "chart08",
- "title": "Price: \u00a3169.99 Free Delivery"
- },
- "tag": "a",
- "end": 63480,
- "tag_type": 1,
- "start": 63316
- },
- {
- "attributes": {
- "class": "title"
- },
- "tag": "span",
- "end": 63500,
- "tag_type": 1,
- "start": 63480
- },
- {
- "start": 63500,
- "end": 63572
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 63579,
- "tag_type": 2,
- "start": 63572
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 63583,
- "tag_type": 2,
- "start": 63579
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 63588,
- "tag_type": 2,
- "start": 63583
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 63592,
- "tag_type": 1,
- "start": 63588
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/3271416/Linx-TVM021-TV-Stand-Up-To-37-/Product.html",
- "class": "chart09",
- "title": "Price: \u00a329.99 Free Delivery"
- },
- "tag": "a",
- "end": 63734,
- "tag_type": 1,
- "start": 63592
- },
- {
- "attributes": {
- "class": "title"
- },
- "tag": "span",
- "end": 63754,
- "tag_type": 1,
- "start": 63734
- },
- {
- "start": 63754,
- "end": 63784
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 63791,
- "tag_type": 2,
- "start": 63784
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 63795,
- "tag_type": 2,
- "start": 63791
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 63800,
- "tag_type": 2,
- "start": 63795
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 63804,
- "tag_type": 1,
- "start": 63800
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/9481062/Toshiba-Regza-AV-Series-32-32AV615DB-HD-Ready-Freeview-LCD-TV/Product.html",
- "class": "chart10",
- "title": "Price: \u00a3339.99 Free Delivery"
- },
- "tag": "a",
- "end": 63978,
- "tag_type": 1,
- "start": 63804
- },
- {
- "attributes": {
- "class": "title"
- },
- "tag": "span",
- "end": 63998,
- "tag_type": 1,
- "start": 63978
- },
- {
- "start": 63998,
- "end": 64112
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 64119,
- "tag_type": 2,
- "start": 64112
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 64123,
- "tag_type": 2,
- "start": 64119
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 64128,
- "tag_type": 2,
- "start": 64123
- },
- {
- "attributes": {},
- "tag": "ol",
- "end": 64133,
- "tag_type": 2,
- "start": 64128
- },
- {
- "attributes": {
- "class": "more"
- },
- "tag": "p",
- "end": 64149,
- "tag_type": 1,
- "start": 64133
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/3-/TopSellers.html?searchtype=genre"
- },
- "tag": "a",
- "end": 64230,
- "tag_type": 1,
- "start": 64149
- },
- {
- "start": 64230,
- "end": 64247
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 64253,
- "tag_type": 1,
- "start": 64247
- },
- {
- "start": 64253,
- "end": 64254
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 64261,
- "tag_type": 2,
- "start": 64254
- },
- {
- "start": 64261,
- "end": 64262
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 64266,
- "tag_type": 2,
- "start": 64262
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 64270,
- "tag_type": 2,
- "start": 64266
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 64276,
- "tag_type": 2,
- "start": 64270
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 64282,
- "tag_type": 2,
- "start": 64276
- },
- {
- "attributes": {
- "class": "comingsoon wrap"
- },
- "tag": "div",
- "end": 64311,
- "tag_type": 1,
- "start": 64282
- },
- {
- "attributes": {
- "class": "boxhead"
- },
- "tag": "div",
- "end": 64332,
- "tag_type": 1,
- "start": 64311
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 64337,
- "tag_type": 1,
- "start": 64332
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 64342,
- "tag_type": 1,
- "start": 64337
- },
- {
- "start": 64342,
- "end": 64346
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/3-/ComingSoon.html?searchtype=genre"
- },
- "tag": "a",
- "end": 64427,
- "tag_type": 1,
- "start": 64346
- },
- {
- "start": 64427,
- "end": 64435
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 64439,
- "tag_type": 1,
- "start": 64435
- },
- {
- "start": 64439,
- "end": 64450
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 64455,
- "tag_type": 2,
- "start": 64450
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 64459,
- "tag_type": 2,
- "start": 64455
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 64465,
- "tag_type": 2,
- "start": 64459
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 64471,
- "tag_type": 2,
- "start": 64465
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 64477,
- "tag_type": 2,
- "start": 64471
- },
- {
- "attributes": {
- "class": "box"
- },
- "tag": "div",
- "end": 64494,
- "tag_type": 1,
- "start": 64477
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 64498,
- "tag_type": 1,
- "start": 64494
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 64502,
- "tag_type": 1,
- "start": 64498
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/10502045/Accessory-Agents-10-37-Low-Profile-Wall-Bracket/Product.html",
- "class": "arrow",
- "title": "Price: \u00a314.99 Free Delivery"
- },
- "tag": "a",
- "end": 64660,
- "tag_type": 1,
- "start": 64502
- },
- {
- "start": 64660,
- "end": 64711
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 64715,
- "tag_type": 2,
- "start": 64711
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 64720,
- "tag_type": 2,
- "start": 64715
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 64724,
- "tag_type": 1,
- "start": 64720
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/8839704/Sony-Bravia-Z-Series-40-40Z5500-HD-1080p-Freeview-Widescreen-LCD-TV/Product.html",
- "class": "arrow",
- "title": "Price: \u00a31399.99 Free Delivery"
- },
- "tag": "a",
- "end": 64903,
- "tag_type": 1,
- "start": 64724
- },
- {
- "start": 64903,
- "end": 65004
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 65008,
- "tag_type": 2,
- "start": 65004
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 65013,
- "tag_type": 2,
- "start": 65008
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 65017,
- "tag_type": 1,
- "start": 65013
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/8839534/Sony-Bravia-S-Series-26-26S5500-HD-Ready-Freeview-Widescreen-LCD-TV/Product.html",
- "class": "arrow",
- "title": "Price: \u00a3399.99 Free Delivery"
- },
- "tag": "a",
- "end": 65195,
- "tag_type": 1,
- "start": 65017
- },
- {
- "start": 65195,
- "end": 65263
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 65267,
- "tag_type": 2,
- "start": 65263
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 65272,
- "tag_type": 2,
- "start": 65267
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 65276,
- "tag_type": 1,
- "start": 65272
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/10772232/Samsung-22-LE22B350-Widescreen-LCD-TV/Product.html",
- "class": "arrow",
- "title": "Price: \u00a3199.99 Free Delivery"
- },
- "tag": "a",
- "end": 65425,
- "tag_type": 1,
- "start": 65276
- },
- {
- "start": 65425,
- "end": 65463
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 65467,
- "tag_type": 2,
- "start": 65463
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 65472,
- "tag_type": 2,
- "start": 65467
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 65476,
- "tag_type": 1,
- "start": 65472
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/8839719/Sony-Bravia-Z-Series-52-52Z5500-HD-1080p-Freeview-Widescreen-LCD-TV/Product.html",
- "class": "arrow",
- "title": "Price: \u00a32199.99 Free Delivery"
- },
- "tag": "a",
- "end": 65655,
- "tag_type": 1,
- "start": 65476
- },
- {
- "start": 65655,
- "end": 65756
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 65760,
- "tag_type": 2,
- "start": 65756
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 65765,
- "tag_type": 2,
- "start": 65760
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 65769,
- "tag_type": 1,
- "start": 65765
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/9223463/Panasonic-Viera-NeoPDP-G15-Series-46-TX-P46G15-HD-1080p-Freesat-Freeview-Plasma-TV/Product.html",
- "class": "arrow",
- "title": "Price: \u00a31299.99 Free Delivery"
- },
- "tag": "a",
- "end": 65963,
- "tag_type": 1,
- "start": 65769
- },
- {
- "start": 65963,
- "end": 66052
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 66056,
- "tag_type": 2,
- "start": 66052
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 66061,
- "tag_type": 2,
- "start": 66056
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 66065,
- "tag_type": 1,
- "start": 66061
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/10333427/Samsung-Series-7-7020-32-UE32B7020-HD-1080p-Freeview-Ultra-Slim-LED-TV/Product.html",
- "class": "arrow",
- "title": "Price: \u00a3999.99 Free Delivery"
- },
- "tag": "a",
- "end": 66247,
- "tag_type": 1,
- "start": 66065
- },
- {
- "start": 66247,
- "end": 66341
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 66345,
- "tag_type": 2,
- "start": 66341
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 66350,
- "tag_type": 2,
- "start": 66345
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 66354,
- "tag_type": 1,
- "start": 66350
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/9924416/Toshiba-DV-Series-19-DV616DB-HD-Ready-Freeview-Integrated-DVD-LCD-TV/Product.html",
- "class": "arrow",
- "title": "Price: \u00a3269.99 Free Delivery"
- },
- "tag": "a",
- "end": 66533,
- "tag_type": 1,
- "start": 66354
- },
- {
- "start": 66533,
- "end": 66616
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 66620,
- "tag_type": 2,
- "start": 66616
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 66625,
- "tag_type": 2,
- "start": 66620
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 66629,
- "tag_type": 1,
- "start": 66625
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/9769759/Toshiba-Regza-ZV-Series-42-42ZV635-HD-1080p-Freeview-LCD-TV/Product.html",
- "class": "arrow",
- "title": "Price: \u00a3899.99 Free Delivery"
- },
- "tag": "a",
- "end": 66799,
- "tag_type": 1,
- "start": 66629
- },
- {
- "start": 66799,
- "end": 66863
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 66867,
- "tag_type": 2,
- "start": 66863
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 66872,
- "tag_type": 2,
- "start": 66867
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 66876,
- "tag_type": 1,
- "start": 66872
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/10772167/Samsung-Series-5-530-32-LE32B530-HD-1080p-Freeview-LCD-TV/Product.html",
- "class": "arrow",
- "title": "Price: \u00a3449.99 Free Delivery"
- },
- "tag": "a",
- "end": 67045,
- "tag_type": 1,
- "start": 66876
- },
- {
- "start": 67045,
- "end": 67107
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 67111,
- "tag_type": 2,
- "start": 67107
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 67116,
- "tag_type": 2,
- "start": 67111
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 67121,
- "tag_type": 2,
- "start": 67116
- },
- {
- "attributes": {
- "class": "more"
- },
- "tag": "p",
- "end": 67137,
- "tag_type": 1,
- "start": 67121
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/3-/ComingSoon.html?searchtype=genre"
- },
- "tag": "a",
- "end": 67218,
- "tag_type": 1,
- "start": 67137
- },
- {
- "start": 67218,
- "end": 67230
- },
- {
- "attributes": {
- "class": "orangepanel"
- },
- "tag": "span",
- "end": 67256,
- "tag_type": 1,
- "start": 67230
- },
- {
- "start": 67256,
- "end": 67257
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 67264,
- "tag_type": 2,
- "start": 67257
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 67268,
- "tag_type": 2,
- "start": 67264
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 67272,
- "tag_type": 2,
- "start": 67268
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 67278,
- "tag_type": 2,
- "start": 67272
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 67284,
- "tag_type": 2,
- "start": 67278
- },
- {
- "attributes": {
- "class": "sidebanner wrap"
- },
- "tag": "div",
- "end": 67313,
- "tag_type": 1,
- "start": 67284
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 67318,
- "tag_type": 1,
- "start": 67313
- },
- {
- "attributes": {
- "href": "/DVD/Blu-ray/6-/Campaign.html?campaign=7147&cid=1528342&dpr=0",
- "manual_cm_sp": "BLU_blu-ray_month_from799_doubles_GBP.jpg_GBP-_-RightSideBanner1-_-ELEC",
- "manual_cm_re": "Right-_-SideBanner1-_-BLU_blu-ray_month_from799_doubles_GBP.jpg_GBP"
- },
- "tag": "a",
- "end": 67568,
- "tag_type": 1,
- "start": 67318
- },
- {
- "attributes": {
- "src": "http://images.play.com/PROMOTIONAL_IMAGES/SIDE_BANNERS/249662_GBP.jpg",
- "alt": "Blu-ray from \u00a37.99",
- "style": "border-width: 0px;"
- },
- "tag": "img",
- "end": 67701,
- "tag_type": 1,
- "start": 67568
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 67705,
- "tag_type": 2,
- "start": 67701
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 67711,
- "tag_type": 2,
- "start": 67705
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 67717,
- "tag_type": 2,
- "start": 67711
- },
- {
- "attributes": {
- "class": "sidebanner wrap"
- },
- "tag": "div",
- "end": 67746,
- "tag_type": 1,
- "start": 67717
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 67751,
- "tag_type": 1,
- "start": 67746
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/3-/301482/2-/Promo.html?dpr=301482",
- "manual_cm_sp": "ELEC_SonyLCDTVs_GBP.gif_GBP-_-RightSideBanner2-_-ELEC",
- "manual_cm_re": "Right-_-SideBanner2-_-ELEC_SonyLCDTVs_GBP.gif_GBP"
- },
- "tag": "a",
- "end": 67955,
- "tag_type": 1,
- "start": 67751
- },
- {
- "attributes": {
- "src": "http://images.play.com/PROMOTIONAL_IMAGES/SIDE_BANNERS/225463_GBP.gif",
- "alt": "Sony LCD TV's - Double",
- "style": "border-width: 0px;"
- },
- "tag": "img",
- "end": 68092,
- "tag_type": 1,
- "start": 67955
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 68096,
- "tag_type": 2,
- "start": 68092
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 68102,
- "tag_type": 2,
- "start": 68096
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 68108,
- "tag_type": 2,
- "start": 68102
- },
- {
- "attributes": {
- "class": "sidebanner wrap"
- },
- "tag": "div",
- "end": 68137,
- "tag_type": 1,
- "start": 68108
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 68142,
- "tag_type": 1,
- "start": 68137
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/3-/255083/2-/Promo.html?dpr=255083",
- "manual_cm_sp": "ELEC_Blu-ray-Players_GBP.jpg_GBP-_-RightSideBanner3-_-ELEC",
- "manual_cm_re": "Right-_-SideBanner3-_-ELEC_Blu-ray-Players_GBP.jpg_GBP"
- },
- "tag": "a",
- "end": 68356,
- "tag_type": 1,
- "start": 68142
- },
- {
- "attributes": {
- "src": "http://images.play.com/PROMOTIONAL_IMAGES/SIDE_BANNERS/181200_GBP.jpg",
- "alt": "Blu-ray players from \u00a3199.99",
- "style": "border-width: 0px;"
- },
- "tag": "img",
- "end": 68499,
- "tag_type": 1,
- "start": 68356
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 68503,
- "tag_type": 2,
- "start": 68499
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 68509,
- "tag_type": 2,
- "start": 68503
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 68515,
- "tag_type": 2,
- "start": 68509
- },
- {
- "attributes": {
- "class": "sidebanner wrap"
- },
- "tag": "div",
- "end": 68544,
- "tag_type": 1,
- "start": 68515
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 68549,
- "tag_type": 1,
- "start": 68544
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/3-/351362/2-/Promo.html?dpr=351362",
- "manual_cm_sp": "ELEC_Flip_GBP.gif_GBP-_-RightSideBanner4-_-ELEC",
- "manual_cm_re": "Right-_-SideBanner4-_-ELEC_Flip_GBP.gif_GBP"
- },
- "tag": "a",
- "end": 68741,
- "tag_type": 1,
- "start": 68549
- },
- {
- "attributes": {
- "src": "http://images.play.com/PROMOTIONAL_IMAGES/SIDE_BANNERS/250490_GBP.gif",
- "alt": "Flip Camcorders - From Only \u00a379.99",
- "style": "border-width: 0px;"
- },
- "tag": "img",
- "end": 68890,
- "tag_type": 1,
- "start": 68741
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 68894,
- "tag_type": 2,
- "start": 68890
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 68900,
- "tag_type": 2,
- "start": 68894
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 68906,
- "tag_type": 2,
- "start": 68900
- },
- {
- "start": 68906,
- "end": 68926
- },
- {
- "attributes": {
- "class": "secureshopping wrap"
- },
- "tag": "div",
- "end": 68959,
- "tag_type": 1,
- "start": 68926
- },
- {
- "attributes": {
- "class": "boxhead"
- },
- "tag": "div",
- "end": 68980,
- "tag_type": 1,
- "start": 68959
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 68985,
- "tag_type": 1,
- "start": 68980
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 68990,
- "tag_type": 1,
- "start": 68985
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 68994,
- "tag_type": 1,
- "start": 68990
- },
- {
- "start": 68994,
- "end": 69009
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 69014,
- "tag_type": 2,
- "start": 69009
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 69020,
- "tag_type": 2,
- "start": 69014
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 69026,
- "tag_type": 2,
- "start": 69020
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 69032,
- "tag_type": 2,
- "start": 69026
- },
- {
- "attributes": {
- "class": "box"
- },
- "tag": "div",
- "end": 69049,
- "tag_type": 1,
- "start": 69032
- },
- {
- "attributes": {
- "href": "about:blank",
- "border": "0"
- },
- "tag": "a",
- "end": 69082,
- "tag_type": 1,
- "start": 69049
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteCSS/Play/Live1/img/brand/verisign.gif",
- "height": "52",
- "border": "0",
- "width": "94"
- },
- "tag": "img",
- "end": 69192,
- "tag_type": 1,
- "start": 69082
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 69196,
- "tag_type": 2,
- "start": 69192
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 69202,
- "tag_type": 2,
- "start": 69196
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 69208,
- "tag_type": 2,
- "start": 69202
- },
- {
- "start": 69208,
- "end": 69228
- },
- {
- "attributes": {
- "class": "sidebanner wrap"
- },
- "tag": "div",
- "end": 69257,
- "tag_type": 1,
- "start": 69228
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 69262,
- "tag_type": 1,
- "start": 69257
- },
- {
- "attributes": {
- "href": "/HOME/HOME/6-/GiftVouchers.html?dpr=0",
- "manual_cm_sp": "giftvoucher_sb.jpg-_-SideBanner1-_-ELEC",
- "manual_cm_re": "-_-SideBanner1-_-giftvoucher_sb.jpg"
- },
- "tag": "a",
- "end": 69416,
- "tag_type": 1,
- "start": 69262
- },
- {
- "attributes": {
- "src": "http://images.play.com/PROMOTIONAL_IMAGES/SIDE_BANNERS/229863.jpg",
- "alt": "Buy Gift Vouchers",
- "style": "border-width: 0px;"
- },
- "tag": "img",
- "end": 69544,
- "tag_type": 1,
- "start": 69416
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 69548,
- "tag_type": 2,
- "start": 69544
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 69554,
- "tag_type": 2,
- "start": 69548
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 69560,
- "tag_type": 2,
- "start": 69554
- },
- {
- "attributes": {
- "class": "sidebanner wrap"
- },
- "tag": "div",
- "end": 69589,
- "tag_type": 1,
- "start": 69560
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 69594,
- "tag_type": 1,
- "start": 69589
- },
- {
- "attributes": {
- "href": "/Campaign.html?campaign=6748&cid=5106868&dpr=0",
- "manual_cm_sp": "ccard_sb.jpg-_-SideBanner2-_-ELEC",
- "manual_cm_re": "-_-SideBanner2-_-ccard_sb.jpg"
- },
- "tag": "a",
- "end": 69753,
- "tag_type": 1,
- "start": 69594
- },
- {
- "attributes": {
- "src": "http://images.play.com/PROMOTIONAL_IMAGES/SIDE_BANNERS/238668.jpg",
- "alt": "Play.com Credit Card",
- "style": "border-width: 0px;"
- },
- "tag": "img",
- "end": 69884,
- "tag_type": 1,
- "start": 69753
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 69888,
- "tag_type": 2,
- "start": 69884
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 69894,
- "tag_type": 2,
- "start": 69888
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 69900,
- "tag_type": 2,
- "start": 69894
- },
- {
- "start": 69900,
- "end": 69924
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 69930,
- "tag_type": 2,
- "start": 69924
- },
- {
- "start": 69930,
- "end": 69950
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 69956,
- "tag_type": 2,
- "start": 69950
- },
- {
- "start": 69956,
- "end": 69976
- },
- {
- "attributes": {
- "class": "clear"
- },
- "tag": "div",
- "end": 69995,
- "tag_type": 1,
- "start": 69976
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 70001,
- "tag_type": 2,
- "start": 69995
- },
- {
- "start": 70001,
- "end": 70021
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 70027,
- "tag_type": 2,
- "start": 70021
- },
- {
- "start": 70027,
- "end": 70035
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 70041,
- "tag_type": 2,
- "start": 70035
- },
- {
- "start": 70041,
- "end": 70045
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 70051,
- "tag_type": 2,
- "start": 70045
- },
- {
- "start": 70051,
- "end": 70059
- },
- {
- "attributes": {
- "type": "text/javascript",
- "language": "JavaScript"
- },
- "tag": "script",
- "end": 70112,
- "tag_type": 1,
- "start": 70059
- },
- {
- "start": 70112,
- "end": 70136
- },
- {
- "attributes": {},
- "tag": "script",
- "end": 70145,
- "tag_type": 2,
- "start": 70136
- },
- {
- "start": 70145,
- "end": 70153
- },
- {
- "attributes": {
- "class": "footer"
- },
- "tag": "div",
- "end": 70173,
- "tag_type": 1,
- "start": 70153
- },
- {
- "start": 70173,
- "end": 70181
- },
- {
- "attributes": {
- "class": "links"
- },
- "tag": "p",
- "end": 70198,
- "tag_type": 1,
- "start": 70181
- },
- {
- "attributes": {
- "href": "/"
- },
- "tag": "a",
- "end": 70210,
- "tag_type": 1,
- "start": 70198
- },
- {
- "start": 70210,
- "end": 70214
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 70218,
- "tag_type": 2,
- "start": 70214
- },
- {
- "start": 70218,
- "end": 70231
- },
- {
- "attributes": {
- "href": "/DVD/DVD/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 70269,
- "tag_type": 1,
- "start": 70231
- },
- {
- "start": 70269,
- "end": 70272
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 70276,
- "tag_type": 2,
- "start": 70272
- },
- {
- "start": 70276,
- "end": 70289
- },
- {
- "attributes": {
- "href": "/DVD/Blu-ray/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 70331,
- "tag_type": 1,
- "start": 70289
- },
- {
- "start": 70331,
- "end": 70338
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 70342,
- "tag_type": 2,
- "start": 70338
- },
- {
- "start": 70342,
- "end": 70355
- },
- {
- "attributes": {
- "href": "/Music/CD/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 70394,
- "tag_type": 1,
- "start": 70355
- },
- {
- "start": 70394,
- "end": 70399
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 70403,
- "tag_type": 2,
- "start": 70399
- },
- {
- "start": 70403,
- "end": 70416
- },
- {
- "attributes": {
- "href": "/Tickets/TicketsEvent/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 70467,
- "tag_type": 1,
- "start": 70416
- },
- {
- "start": 70467,
- "end": 70474
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 70478,
- "tag_type": 2,
- "start": 70474
- },
- {
- "start": 70478,
- "end": 70491
- },
- {
- "attributes": {
- "href": "/Games/Games/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 70533,
- "tag_type": 1,
- "start": 70491
- },
- {
- "start": 70533,
- "end": 70538
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 70542,
- "tag_type": 2,
- "start": 70538
- },
- {
- "start": 70542,
- "end": 70555
- },
- {
- "attributes": {
- "href": "/Books/Books/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 70597,
- "tag_type": 1,
- "start": 70555
- },
- {
- "start": 70597,
- "end": 70602
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 70606,
- "tag_type": 2,
- "start": 70602
- },
- {
- "start": 70606,
- "end": 70619
- },
- {
- "attributes": {
- "href": "/Clothing/Clothing/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 70667,
- "tag_type": 1,
- "start": 70619
- },
- {
- "start": 70667,
- "end": 70675
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 70679,
- "tag_type": 2,
- "start": 70675
- },
- {
- "start": 70679,
- "end": 70692
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 70700,
- "tag_type": 1,
- "start": 70692
- },
- {
- "start": 70700,
- "end": 70711
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 70720,
- "tag_type": 2,
- "start": 70711
- },
- {
- "start": 70720,
- "end": 70733
- },
- {
- "attributes": {
- "href": "/PC/PCs/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 70770,
- "tag_type": 1,
- "start": 70733
- },
- {
- "start": 70770,
- "end": 70779
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 70783,
- "tag_type": 2,
- "start": 70779
- },
- {
- "start": 70783,
- "end": 70796
- },
- {
- "attributes": {
- "href": "/Gadgets/Gadgets/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 70842,
- "tag_type": 1,
- "start": 70796
- },
- {
- "start": 70842,
- "end": 70849
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 70853,
- "tag_type": 2,
- "start": 70849
- },
- {
- "start": 70853,
- "end": 70866
- },
- {
- "attributes": {
- "href": "/Mobiles/Mobile/6-/MobileHome.html"
- },
- "tag": "a",
- "end": 70911,
- "tag_type": 1,
- "start": 70866
- },
- {
- "start": 70911,
- "end": 70917
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 70921,
- "tag_type": 2,
- "start": 70917
- },
- {
- "start": 70921,
- "end": 70934
- },
- {
- "attributes": {
- "href": "/HOME/HOME/6-/LandingPage.html?page=playtrade"
- },
- "tag": "a",
- "end": 70990,
- "tag_type": 1,
- "start": 70934
- },
- {
- "start": 70990,
- "end": 71005
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 71009,
- "tag_type": 2,
- "start": 71005
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 71013,
- "tag_type": 2,
- "start": 71009
- },
- {
- "start": 71013,
- "end": 71021
- },
- {
- "attributes": {
- "class": "cards"
- },
- "tag": "div",
- "end": 71040,
- "tag_type": 1,
- "start": 71021
- },
- {
- "start": 71040,
- "end": 71061
- },
- {
- "attributes": {
- "cellpadding": "0"
- },
- "tag": "table",
- "end": 71084,
- "tag_type": 1,
- "start": 71061
- },
- {
- "start": 71084,
- "end": 71096
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 71103,
- "tag_type": 1,
- "start": 71096
- },
- {
- "start": 71103,
- "end": 71119
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 71123,
- "tag_type": 1,
- "start": 71119
- },
- {
- "start": 71123,
- "end": 71143
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 71147,
- "tag_type": 1,
- "start": 71143
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteCSS/Play/Live1/img/footer/cards.gif",
- "alt": "We accept these cards: Delta, MasterCard, Solo, Switch, Maestro, Visa, Electron",
- "style": "border-width: 0px;"
- },
- "tag": "img",
- "end": 71334,
- "tag_type": 1,
- "start": 71147
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 71339,
- "tag_type": 2,
- "start": 71334
- },
- {
- "start": 71339,
- "end": 71359
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 71363,
- "tag_type": 1,
- "start": 71359
- },
- {
- "attributes": {
- "href": "/HOME/HOME/6-/Campaign.html?campaign=6748&cid=5106868",
- "title": "Play.com Credit Card"
- },
- "tag": "a",
- "end": 71460,
- "tag_type": 1,
- "start": 71363
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteCSS/Play/Live1/img/footer/play-credit-cards.gif",
- "alt": "Play.com Credit Card",
- "style": "border-width: 0px;"
- },
- "tag": "img",
- "end": 71600,
- "tag_type": 1,
- "start": 71460
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 71604,
- "tag_type": 2,
- "start": 71600
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 71609,
- "tag_type": 2,
- "start": 71604
- },
- {
- "start": 71609,
- "end": 71625
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 71630,
- "tag_type": 2,
- "start": 71625
- },
- {
- "start": 71630,
- "end": 71642
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 71650,
- "tag_type": 2,
- "start": 71642
- },
- {
- "start": 71650,
- "end": 71658
- },
- {
- "attributes": {},
- "tag": "table",
- "end": 71666,
- "tag_type": 2,
- "start": 71658
- },
- {
- "start": 71666,
- "end": 71670
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 71676,
- "tag_type": 2,
- "start": 71670
- },
- {
- "attributes": {
- "class": "contact"
- },
- "tag": "div",
- "end": 71697,
- "tag_type": 1,
- "start": 71676
- },
- {
- "attributes": {
- "cellspacing": "0"
- },
- "tag": "table",
- "end": 71720,
- "tag_type": 1,
- "start": 71697
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 71727,
- "tag_type": 1,
- "start": 71720
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 71731,
- "tag_type": 1,
- "start": 71727
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 71735,
- "tag_type": 1,
- "start": 71731
- },
- {
- "attributes": {
- "href": "/HOME/HOME/6-/Help.html?page=helpdesk",
- "title": "Play.com Helpdesk"
- },
- "tag": "a",
- "end": 71809,
- "tag_type": 1,
- "start": 71735
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteCSS/Play/Live1/img/footer/helpdesk.gif",
- "alt": "Play.com Helpdesk",
- "style": "border-width: 0px;"
- },
- "tag": "img",
- "end": 71937,
- "tag_type": 1,
- "start": 71809
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 71941,
- "tag_type": 2,
- "start": 71937
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 71946,
- "tag_type": 2,
- "start": 71941
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 71950,
- "tag_type": 1,
- "start": 71946
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteCSS/Play/Live1/img/footer/pipe.gif",
- "style": "border-width: 0px; height: 32px; width: 23px;"
- },
- "tag": "img",
- "end": 72077,
- "tag_type": 1,
- "start": 71950
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 72082,
- "tag_type": 2,
- "start": 72077
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 72086,
- "tag_type": 1,
- "start": 72082
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteCSS/Play/Live1/img/footer/phone.gif",
- "alt": "Customer Services: 0845 800 1020",
- "style": "border-width: 0px;"
- },
- "tag": "img",
- "end": 72226,
- "tag_type": 1,
- "start": 72086
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 72231,
- "tag_type": 2,
- "start": 72226
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 72236,
- "tag_type": 2,
- "start": 72231
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 72244,
- "tag_type": 2,
- "start": 72236
- },
- {
- "attributes": {},
- "tag": "table",
- "end": 72252,
- "tag_type": 2,
- "start": 72244
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 72258,
- "tag_type": 2,
- "start": 72252
- },
- {
- "attributes": {
- "class": "legal"
- },
- "tag": "p",
- "end": 72275,
- "tag_type": 1,
- "start": 72258
- },
- {
- "attributes": {
- "href": "/HOME/HOME/6-/Help.html?page=priv"
- },
- "tag": "a",
- "end": 72319,
- "tag_type": 1,
- "start": 72275
- },
- {
- "start": 72319,
- "end": 72333
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 72337,
- "tag_type": 2,
- "start": 72333
- },
- {
- "start": 72337,
- "end": 72340
- },
- {
- "attributes": {
- "href": "/HOME/HOME/6-/Help.html?page=terms"
- },
- "tag": "a",
- "end": 72385,
- "tag_type": 1,
- "start": 72340
- },
- {
- "start": 72385,
- "end": 72407
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 72411,
- "tag_type": 2,
- "start": 72407
- },
- {
- "start": 72411,
- "end": 72414
- },
- {
- "attributes": {
- "style": "color: rgb(0, 0, 0);"
- },
- "tag": "span",
- "end": 72449,
- "tag_type": 1,
- "start": 72414
- },
- {
- "start": 72449,
- "end": 72484
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 72491,
- "tag_type": 2,
- "start": 72484
- },
- {
- "start": 72491,
- "end": 72494
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 72500,
- "tag_type": 1,
- "start": 72494
- },
- {
- "start": 72500,
- "end": 72515
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 72522,
- "tag_type": 2,
- "start": 72515
- },
- {
- "start": 72522,
- "end": 72523
- },
- {
- "attributes": {
- "href": "http://www.PlayUSA.com"
- },
- "tag": "a",
- "end": 72556,
- "tag_type": 1,
- "start": 72523
- },
- {
- "start": 72556,
- "end": 72557
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteCSS/Play/Live1/img/footer/playincorporated.gif",
- "alt": "Play Incorporated",
- "style": "border-width: 0px; height: 16px; width: 55px;"
- },
- "tag": "img",
- "end": 72720,
- "tag_type": 1,
- "start": 72557
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 72724,
- "tag_type": 2,
- "start": 72720
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 72728,
- "tag_type": 2,
- "start": 72724
- },
- {
- "start": 72728,
- "end": 72736
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 72742,
- "tag_type": 2,
- "start": 72736
- },
- {
- "start": 72742,
- "end": 72786
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 72792,
- "tag_type": 2,
- "start": 72786
- },
- {
- "attributes": {},
- "tag": "body",
- "end": 72799,
- "tag_type": 2,
- "start": 72792
- }
-]
diff --git a/scrapy/tests/test_contrib_ibl/samples/samples_htmlpage_2.html b/scrapy/tests/test_contrib_ibl/samples/samples_htmlpage_2.html
deleted file mode 100644
index 330ae6fe3..000000000
--- a/scrapy/tests/test_contrib_ibl/samples/samples_htmlpage_2.html
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Samsung Series 5 550 37" LE37B550 / HD 1080p / Freeview / LCD TV (Black)
( 1 customer rating )
RRP: £749.99 | You save: £170.00 (22%)
In stock | Usually dispatched within 24 hours
Half Price TV Stand Save 50% On This TV Stand When Purchased With This TV
Please be aware that this item will be delivered via a courier and will require a signature. Please contact customer service team with a daytime contact number. Screen Size: 37" Resolution: 1920 x 1080 Technology: CCFL Picture Engine: DNIe+ Dynamic Contrast Ratio: High Contrast Wide Colour Enhancer:WCE 2 1080 24p Real Movie Audio Sound Effect System: SRS Trusurround HD & Dolby Digital Plus Speaker Type: Down Firing Sound Output(RMS): 10W x 2 Features USB 2.0 Teletext(TTXT) Anynet+ (HDMI-CEC) Game mode User Interface OSD Language Sleep Timer Clock & On/Off Timer Auto Channel Search Auto Power Off EPG Auto Volume Leveller Hotel Mode(S/W) System DTV Type DTV Tuner Built-in Inputs / Outputs HDMI: back + side USB: side CI Slot: side Composite(AV): side Service: back PC input (D-sub): back PC Audio Input (Mini Jack): back DVI Audio Input (Mini Jack): back Component(Y/Pb/Pr): back Digital Audio (Optical): back Headphone: back RF Input: back Audio Out(L/R): back RS232C: back Scart: back Design Type: Samsung Crystal TV Colour: Platinum Black Swivel (Left/Right) Dimensions: Set Size(WXDXH) with Stand: 923 x 253 x 659.4 Set Size(WXDXH) without Stand: 923 x 78.5 x 597 Weight Set Weight with Stand: 19.4 Set weight without stand: 14.8 Accessory Vesa Wall Mount (WXH): Yes (32-40":200x200) Remote Controller Batteries Power Cable Average rating (1 review)
This TV is amazing - if you unlock some setting you can play Xvid, Dvix and MKV files through the TV (USB 2.0). The TV is well worth the money.
Related Items - Electronics
£334.99 Free Delivery RRP:£499.99 You save:£165.00
View All »
-
diff --git a/scrapy/tests/test_contrib_ibl/samples/samples_htmlpage_2.json b/scrapy/tests/test_contrib_ibl/samples/samples_htmlpage_2.json
deleted file mode 100644
index c856f4a92..000000000
--- a/scrapy/tests/test_contrib_ibl/samples/samples_htmlpage_2.json
+++ /dev/null
@@ -1,21792 +0,0 @@
-[
- {
- "attributes": {
- "lang": "en",
- "xml:lang": "en",
- "xmlns": "http://www.w3.org/1999/xhtml"
- },
- "tag": "html",
- "end": 188,
- "start": 121,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "head",
- "end": 194,
- "start": 188,
- "tag_type": 1
- },
- {
- "attributes": {
- "id": "_pageTemplate__header__title"
- },
- "tag": "title",
- "end": 235,
- "start": 194,
- "tag_type": 1
- },
- {
- "start": 235,
- "end": 358
- },
- {
- "attributes": {},
- "tag": "title",
- "end": 366,
- "start": 358,
- "tag_type": 2
- },
- {
- "start": 366,
- "end": 367
- },
- {
- "attributes": {
- "content": "NOODP",
- "name": "ROBOTS"
- },
- "tag": "meta",
- "end": 403,
- "start": 367,
- "tag_type": 1
- },
- {
- "attributes": {
- "content": "no-cache",
- "http-equiv": "Pragma"
- },
- "tag": "meta",
- "end": 450,
- "start": 403,
- "tag_type": 3
- },
- {
- "attributes": {
- "content": "en-us",
- "http-equiv": "Content-Language"
- },
- "tag": "meta",
- "end": 504,
- "start": 450,
- "tag_type": 3
- },
- {
- "attributes": {
- "content": "Samsung Series 5 550 37" LE37B550 / HD 1080p / Freeview / LCD TV, electronics, dvd players, digital cameras, mobile phones, pc peripherals, buy, free delivery, uk, online, entertainment, shopping, shop, bargain, special offer",
- "id": "_pageTemplate__header__metaKeywords",
- "name": "keywords"
- },
- "tag": "meta",
- "end": 808,
- "start": 504,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "meta",
- "end": 815,
- "start": 808,
- "tag_type": 2
- },
- {
- "attributes": {
- "content": "Play.com - Buy Samsung Series 5 550 37" LE37B550 / HD 1080p / Freeview / LCD TV, with free delivery to UK and Europe. Play.com is the top site for dvds, cds and games in the UK. We stock all major movies on DVD.",
- "id": "_pageTemplate__header__metaDescription",
- "name": "description"
- },
- "tag": "meta",
- "end": 1113,
- "start": 815,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "meta",
- "end": 1120,
- "start": 1113,
- "tag_type": 2
- },
- {
- "attributes": {
- "content": "text/html; charset=ISO-8859-1",
- "http-equiv": "Content-Type"
- },
- "tag": "meta",
- "end": 1194,
- "start": 1120,
- "tag_type": 3
- },
- {
- "attributes": {
- "href": "http://images.play.com/SiteCSS/Play/Live1/css/play.min.css",
- "type": "text/css",
- "id": "_pageTemplate__header__styleSheet",
- "rel": "stylesheet"
- },
- "tag": "link",
- "end": 1338,
- "start": 1194,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "link",
- "end": 1345,
- "start": 1338,
- "tag_type": 2
- },
- {
- "attributes": {
- "href": "http://images.play.com/SiteCSS/Play/Live1/img/brand/favicon.ico",
- "rel": "icon"
- },
- "tag": "link",
- "end": 1435,
- "start": 1345,
- "tag_type": 3
- },
- {
- "attributes": {
- "href": "http://images.play.com/SiteCSS/Play/Live1/img/brand/favicon.ico",
- "rel": "shortcut icon"
- },
- "tag": "link",
- "end": 1534,
- "start": 1435,
- "tag_type": 3
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteScript/Play/Components/JavaScript/ChartsMenu.js",
- "type": "text/javascript",
- "language": "JavaScript"
- },
- "tag": "script",
- "end": 1668,
- "start": 1534,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "script",
- "end": 1677,
- "start": 1668,
- "tag_type": 2
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteScript/Play/Components/JavaScript/Other.js",
- "type": "text/javascript",
- "language": "JavaScript"
- },
- "tag": "script",
- "end": 1806,
- "start": 1677,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "script",
- "end": 1815,
- "start": 1806,
- "tag_type": 2
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteScript/Play/Components/JavaScript/Reloaded.js",
- "type": "text/javascript",
- "language": "JavaScript"
- },
- "tag": "script",
- "end": 1947,
- "start": 1815,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "script",
- "end": 1956,
- "start": 1947,
- "tag_type": 2
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteScript/Play/Components/JavaScript/cookieTools.js",
- "type": "text/javascript",
- "language": "JavaScript"
- },
- "tag": "script",
- "end": 2091,
- "start": 1956,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "script",
- "end": 2100,
- "start": 2091,
- "tag_type": 2
- },
- {
- "attributes": {
- "content": "6hM6+2zExVEjvWx8GYWXLAXLBAOfYdLvkK8mzEZLy6o=",
- "name": "verify-v1"
- },
- "tag": "meta",
- "end": 2180,
- "start": 2100,
- "tag_type": 3
- },
- {
- "start": 2180,
- "end": 2182
- },
- {
- "start": 2182,
- "end": 2205
- },
- {
- "start": 2205,
- "end": 2206
- },
- {
- "attributes": {
- "src": "http://images.play.com/sitetrak/cmdatatagutilsA.js",
- "type": "text/javascript",
- "language": "javascript1.1"
- },
- "tag": "script",
- "end": 2319,
- "start": 2206,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "script",
- "end": 2328,
- "start": 2319,
- "tag_type": 2
- },
- {
- "start": 2328,
- "end": 2329
- },
- {
- "attributes": {
- "src": "http://images.play.com/sitetrak/v40/eluminateA.js",
- "type": "text/javascript",
- "language": "javascript1.1"
- },
- "tag": "script",
- "end": 2441,
- "start": 2329,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "script",
- "end": 2450,
- "start": 2441,
- "tag_type": 2
- },
- {
- "start": 2450,
- "end": 2452
- },
- {
- "attributes": {
- "type": "text/javascript",
- "language": "javascript1.1"
- },
- "tag": "script",
- "end": 2508,
- "start": 2452,
- "tag_type": 1
- },
- {
- "start": 2508,
- "end": 2509
- },
- {
- "start": 2509,
- "end": 2663
- },
- {
- "start": 2663,
- "end": 2664
- },
- {
- "attributes": {},
- "tag": "script",
- "end": 2673,
- "start": 2664,
- "tag_type": 2
- },
- {
- "start": 2673,
- "end": 2677
- },
- {
- "attributes": {
- "type": "text/javascript"
- },
- "tag": "script",
- "end": 2708,
- "start": 2677,
- "tag_type": 1
- },
- {
- "start": 2708,
- "end": 2928
- },
- {
- "attributes": {},
- "tag": "script",
- "end": 2937,
- "start": 2928,
- "tag_type": 2
- },
- {
- "start": 2937,
- "end": 2938
- },
- {
- "attributes": {
- "type": "text/javascript"
- },
- "tag": "script",
- "end": 2969,
- "start": 2938,
- "tag_type": 1
- },
- {
- "start": 2969,
- "end": 3077
- },
- {
- "attributes": {},
- "tag": "script",
- "end": 3086,
- "start": 3077,
- "tag_type": 2
- },
- {
- "start": 3086,
- "end": 3087
- },
- {
- "start": 3087,
- "end": 3108
- },
- {
- "start": 3108,
- "end": 3110
- },
- {
- "attributes": {},
- "tag": "head",
- "end": 3117,
- "start": 3110,
- "tag_type": 2
- },
- {
- "start": 3117,
- "end": 3118
- },
- {
- "attributes": {
- "id": "goto-top",
- "class": "region-ELEC-404 greyBg goto-top",
- "name": "goto-top"
- },
- "tag": "body",
- "end": 3194,
- "start": 3118,
- "tag_type": 1
- },
- {
- "start": 3194,
- "end": 3198
- },
- {
- "attributes": {
- "id": "mainContainer"
- },
- "tag": "div",
- "end": 3222,
- "start": 3198,
- "tag_type": 1
- },
- {
- "start": 3222,
- "end": 3226
- },
- {
- "attributes": {
- "class": "header"
- },
- "tag": "div",
- "end": 3246,
- "start": 3226,
- "tag_type": 1
- },
- {
- "start": 3246,
- "end": 3250
- },
- {
- "attributes": {
- "class": "new_menu"
- },
- "tag": "div",
- "end": 3272,
- "start": 3250,
- "tag_type": 1
- },
- {
- "attributes": {
- "action": "https://www.play.com/OrdersPost.aspx",
- "method": "post",
- "class": "nomargin"
- },
- "tag": "form",
- "end": 3355,
- "start": 3272,
- "tag_type": 1
- },
- {
- "attributes": {
- "type": "hidden",
- "name": "transfer",
- "value": "transfer"
- },
- "tag": "input",
- "end": 3411,
- "start": 3355,
- "tag_type": 3
- },
- {
- "attributes": {
- "type": "hidden",
- "name": "returnURL",
- "value": "http://www.play.com/Product.aspx?searchtype=genre&r=ELEC&p=318&g=404&title=8986420&PRODUCT_TITLE=Samsung-Series-5-550-37-LE37B550-HD-1080p-Freeview-LCD-TV"
- },
- "tag": "input",
- "end": 3614,
- "start": 3411,
- "tag_type": 3
- },
- {
- "attributes": {
- "type": "hidden",
- "name": "hpcode",
- "value": null
- },
- "tag": "input",
- "end": 3660,
- "start": 3614,
- "tag_type": 3
- },
- {
- "attributes": {
- "type": "hidden",
- "name": "hpCardMessage",
- "value": "no"
- },
- "tag": "input",
- "end": 3715,
- "start": 3660,
- "tag_type": 3
- },
- {
- "attributes": {
- "type": "hidden",
- "name": "basketPromotionId",
- "value": null
- },
- "tag": "input",
- "end": 3772,
- "start": 3715,
- "tag_type": 3
- },
- {
- "attributes": {
- "type": "hidden",
- "name": "products",
- "value": null
- },
- "tag": "input",
- "end": 3820,
- "start": 3772,
- "tag_type": 3
- },
- {
- "attributes": {
- "type": "hidden",
- "name": "quantity",
- "value": null
- },
- "tag": "input",
- "end": 3868,
- "start": 3820,
- "tag_type": 3
- },
- {
- "attributes": {
- "type": "hidden",
- "name": "promoid",
- "value": null
- },
- "tag": "input",
- "end": 3915,
- "start": 3868,
- "tag_type": 3
- },
- {
- "attributes": {
- "type": "hidden",
- "name": "source",
- "value": "0"
- },
- "tag": "input",
- "end": 3962,
- "start": 3915,
- "tag_type": 3
- },
- {
- "attributes": {
- "type": "hidden",
- "name": "currency",
- "value": "257"
- },
- "tag": "input",
- "end": 4013,
- "start": 3962,
- "tag_type": 3
- },
- {
- "attributes": {
- "type": "hidden",
- "name": "regions",
- "value": null
- },
- "tag": "input",
- "end": 4060,
- "start": 4013,
- "tag_type": 3
- },
- {
- "attributes": {
- "type": "hidden",
- "name": "mpListings",
- "value": null
- },
- "tag": "input",
- "end": 4110,
- "start": 4060,
- "tag_type": 3
- },
- {
- "attributes": {
- "type": "hidden",
- "name": "sitecurrencies",
- "value": null
- },
- "tag": "input",
- "end": 4164,
- "start": 4110,
- "tag_type": 3
- },
- {
- "attributes": {
- "type": "hidden",
- "name": "applyPromotions",
- "value": null
- },
- "tag": "input",
- "end": 4219,
- "start": 4164,
- "tag_type": 3
- },
- {
- "attributes": {
- "type": "hidden",
- "name": "lispTypes",
- "value": null
- },
- "tag": "input",
- "end": 4268,
- "start": 4219,
- "tag_type": 3
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteCSS/Play/Live1/img/menu/my_account.gif",
- "name": "My Account",
- "type": "image",
- "alt": "My Account",
- "border": "0",
- "class": "my_account"
- },
- "tag": "input",
- "end": 4426,
- "start": 4268,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "form",
- "end": 4433,
- "start": 4426,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 4439,
- "start": 4433,
- "tag_type": 1
- },
- {
- "start": 4439,
- "end": 4442
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 4449,
- "start": 4442,
- "tag_type": 2
- },
- {
- "attributes": {
- "href": "/HOME/HOME/6-/Help.html?page=helpdesk"
- },
- "tag": "a",
- "end": 4497,
- "start": 4449,
- "tag_type": 1
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteCSS/Play/Live1/img/menu/help_r.gif",
- "alt": "Help"
- },
- "tag": "img",
- "end": 4582,
- "start": 4497,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 4586,
- "start": 4582,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 4592,
- "start": 4586,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "currency_flags"
- },
- "tag": "div",
- "end": 4620,
- "start": 4592,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "gbp"
- },
- "tag": "div",
- "end": 4637,
- "start": 4620,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 4640,
- "start": 4637,
- "tag_type": 1
- },
- {
- "start": 4640,
- "end": 4641
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 4645,
- "start": 4641,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 4651,
- "start": 4645,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "gbp_active"
- },
- "tag": "div",
- "end": 4675,
- "start": 4651,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/-/8986420/Samsung-Series-5-550-37-LE37B550-HD-1080p-Freeview-LCD-TV/Product.html?searchtype=genre&cur=257"
- },
- "tag": "a",
- "end": 4826,
- "start": 4675,
- "tag_type": 1
- },
- {
- "start": 4826,
- "end": 4832
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 4836,
- "start": 4832,
- "tag_type": 2
- },
- {
- "start": 4836,
- "end": 4837
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 4843,
- "start": 4837,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "euro"
- },
- "tag": "div",
- "end": 4861,
- "start": 4843,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 4864,
- "start": 4861,
- "tag_type": 1
- },
- {
- "start": 4864,
- "end": 4865
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 4869,
- "start": 4865,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 4875,
- "start": 4869,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "euro_inactive"
- },
- "tag": "div",
- "end": 4902,
- "start": 4875,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/-/8986420/Samsung-Series-5-550-37-LE37B550-HD-1080p-Freeview-LCD-TV/Product.html?searchtype=genre&cur=258"
- },
- "tag": "a",
- "end": 5053,
- "start": 4902,
- "tag_type": 1
- },
- {
- "start": 5053,
- "end": 5058
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 5062,
- "start": 5058,
- "tag_type": 2
- },
- {
- "start": 5062,
- "end": 5063
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 5069,
- "start": 5063,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 5075,
- "start": 5069,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "wide"
- },
- "tag": "div",
- "end": 5093,
- "start": 5075,
- "tag_type": 1
- },
- {
- "attributes": {
- "cellpadding": "0",
- "cellspacing": "0"
- },
- "tag": "table",
- "end": 5132,
- "start": 5093,
- "tag_type": 1
- },
- {
- "start": 5132,
- "end": 5136
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 5140,
- "start": 5136,
- "tag_type": 1
- },
- {
- "start": 5140,
- "end": 5144
- },
- {
- "attributes": {
- "class": "head_l"
- },
- "tag": "td",
- "end": 5163,
- "start": 5144,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "newlogo"
- },
- "tag": "div",
- "end": 5184,
- "start": 5163,
- "tag_type": 1
- },
- {
- "start": 5184,
- "end": 5188
- },
- {
- "attributes": {},
- "tag": "h1",
- "end": 5192,
- "start": 5188,
- "tag_type": 1
- },
- {
- "start": 5192,
- "end": 5196
- },
- {
- "attributes": {
- "href": "/"
- },
- "tag": "a",
- "end": 5208,
- "start": 5196,
- "tag_type": 1
- },
- {
- "start": 5208,
- "end": 5212
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteCSS/Play/Live1/img/brand/logo.gif",
- "alt": "play.com",
- "style": "height:38px;width:194px;border-width:0px;"
- },
- "tag": "img",
- "end": 5351,
- "start": 5212,
- "tag_type": 3
- },
- {
- "start": 5351,
- "end": 5355
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 5359,
- "start": 5355,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "h1",
- "end": 5364,
- "start": 5359,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 5370,
- "start": 5364,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "freedelivery"
- },
- "tag": "div",
- "end": 5396,
- "start": 5370,
- "tag_type": 1
- },
- {
- "attributes": {
- "type": "text/javascript",
- "language": "JavaScript"
- },
- "tag": "script",
- "end": 5449,
- "start": 5396,
- "tag_type": 1
- },
- {
- "start": 5449,
- "end": 5640
- },
- {
- "attributes": {},
- "tag": "script",
- "end": 5649,
- "start": 5640,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "noscript",
- "end": 5659,
- "start": 5649,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 5664,
- "start": 5659,
- "tag_type": 1
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteCSS/Play/Live1/img/brand/freedelivery.gif",
- "alt": "Free delivery on everything!",
- "height": "28",
- "width": "200"
- },
- "tag": "img",
- "end": 5805,
- "start": 5664,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 5811,
- "start": 5805,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "noscript",
- "end": 5822,
- "start": 5811,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 5828,
- "start": 5822,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 5833,
- "start": 5828,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 5837,
- "start": 5833,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "sc"
- },
- "tag": "div",
- "end": 5853,
- "start": 5837,
- "tag_type": 1
- },
- {
- "start": 5853,
- "end": 5857
- },
- {
- "attributes": {
- "class": "sback_r"
- },
- "tag": "div",
- "end": 5878,
- "start": 5857,
- "tag_type": 1
- },
- {
- "start": 5878,
- "end": 5882
- },
- {
- "attributes": {
- "class": "searchbox"
- },
- "tag": "div",
- "end": 5905,
- "start": 5882,
- "tag_type": 1
- },
- {
- "start": 5905,
- "end": 5909
- },
- {
- "attributes": {
- "action": "/Search.aspx",
- "method": "get",
- "name": "search",
- "class": "nomargin"
- },
- "tag": "form",
- "end": 5981,
- "start": 5909,
- "tag_type": 1
- },
- {
- "attributes": {
- "cellpadding": "0",
- "cellspacing": "0"
- },
- "tag": "table",
- "end": 6020,
- "start": 5981,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 6024,
- "start": 6020,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "region_td"
- },
- "tag": "td",
- "end": 6046,
- "start": 6024,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "region"
- },
- "tag": "div",
- "end": 6066,
- "start": 6046,
- "tag_type": 1
- },
- {
- "attributes": {
- "name": "searchtype",
- "class": "searchtype"
- },
- "tag": "select",
- "end": 6111,
- "start": 6066,
- "tag_type": 1
- },
- {
- "attributes": {
- "value": "allproducts"
- },
- "tag": "option",
- "end": 6140,
- "start": 6111,
- "tag_type": 1
- },
- {
- "start": 6140,
- "end": 6152
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 6161,
- "start": 6152,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "-----------------------"
- },
- "tag": "option",
- "end": 6202,
- "start": 6161,
- "tag_type": 1
- },
- {
- "start": 6202,
- "end": 6225
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 6234,
- "start": 6225,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "r2alldvd"
- },
- "tag": "option",
- "end": 6260,
- "start": 6234,
- "tag_type": 1
- },
- {
- "start": 6260,
- "end": 6263
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 6272,
- "start": 6263,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "musicall"
- },
- "tag": "option",
- "end": 6298,
- "start": 6272,
- "tag_type": 1
- },
- {
- "start": 6298,
- "end": 6303
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 6312,
- "start": 6303,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "gameall"
- },
- "tag": "option",
- "end": 6337,
- "start": 6312,
- "tag_type": 1
- },
- {
- "start": 6337,
- "end": 6342
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 6351,
- "start": 6342,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "bookall"
- },
- "tag": "option",
- "end": 6376,
- "start": 6351,
- "tag_type": 1
- },
- {
- "start": 6376,
- "end": 6381
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 6390,
- "start": 6381,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "abcdall"
- },
- "tag": "option",
- "end": 6415,
- "start": 6390,
- "tag_type": 1
- },
- {
- "start": 6415,
- "end": 6425
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 6434,
- "start": 6425,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "CAL"
- },
- "tag": "option",
- "end": 6455,
- "start": 6434,
- "tag_type": 1
- },
- {
- "start": 6455,
- "end": 6464
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 6473,
- "start": 6464,
- "tag_type": 2
- },
- {
- "attributes": {
- "selected": null,
- "value": "ELEC"
- },
- "tag": "option",
- "end": 6503,
- "start": 6473,
- "tag_type": 1
- },
- {
- "start": 6503,
- "end": 6514
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 6523,
- "start": 6514,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "PCSH"
- },
- "tag": "option",
- "end": 6545,
- "start": 6523,
- "tag_type": 1
- },
- {
- "start": 6545,
- "end": 6554
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 6563,
- "start": 6554,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "GADG"
- },
- "tag": "option",
- "end": 6585,
- "start": 6563,
- "tag_type": 1
- },
- {
- "start": 6585,
- "end": 6592
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 6601,
- "start": 6592,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "MBLS"
- },
- "tag": "option",
- "end": 6623,
- "start": 6601,
- "tag_type": 1
- },
- {
- "start": 6623,
- "end": 6636
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 6645,
- "start": 6636,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "mobileall"
- },
- "tag": "option",
- "end": 6672,
- "start": 6645,
- "tag_type": 1
- },
- {
- "start": 6672,
- "end": 6686
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 6695,
- "start": 6686,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "clothingall"
- },
- "tag": "option",
- "end": 6724,
- "start": 6695,
- "tag_type": 1
- },
- {
- "start": 6724,
- "end": 6732
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 6741,
- "start": 6732,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "TICKETS_ALL"
- },
- "tag": "option",
- "end": 6770,
- "start": 6741,
- "tag_type": 1
- },
- {
- "start": 6770,
- "end": 6777
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 6786,
- "start": 6777,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "-----------------------"
- },
- "tag": "option",
- "end": 6827,
- "start": 6786,
- "tag_type": 1
- },
- {
- "start": 6827,
- "end": 6850
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 6859,
- "start": 6850,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "r2alldvd"
- },
- "tag": "option",
- "end": 6885,
- "start": 6859,
- "tag_type": 1
- },
- {
- "start": 6885,
- "end": 6888
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 6897,
- "start": 6888,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "R2"
- },
- "tag": "option",
- "end": 6917,
- "start": 6897,
- "tag_type": 1
- },
- {
- "start": 6917,
- "end": 6924
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 6933,
- "start": 6924,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "r2title"
- },
- "tag": "option",
- "end": 6958,
- "start": 6933,
- "tag_type": 1
- },
- {
- "start": 6958,
- "end": 6971
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 6980,
- "start": 6971,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "r2actor"
- },
- "tag": "option",
- "end": 7005,
- "start": 6980,
- "tag_type": 1
- },
- {
- "start": 7005,
- "end": 7018
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7027,
- "start": 7018,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "r2director"
- },
- "tag": "option",
- "end": 7055,
- "start": 7027,
- "tag_type": 1
- },
- {
- "start": 7055,
- "end": 7071
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7080,
- "start": 7071,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "r2language"
- },
- "tag": "option",
- "end": 7108,
- "start": 7080,
- "tag_type": 1
- },
- {
- "start": 7108,
- "end": 7124
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7133,
- "start": 7124,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "r2subtitles"
- },
- "tag": "option",
- "end": 7162,
- "start": 7133,
- "tag_type": 1
- },
- {
- "start": 7162,
- "end": 7178
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7187,
- "start": 7178,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "BLU"
- },
- "tag": "option",
- "end": 7208,
- "start": 7187,
- "tag_type": 1
- },
- {
- "start": 7208,
- "end": 7219
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7228,
- "start": 7219,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "HD"
- },
- "tag": "option",
- "end": 7248,
- "start": 7228,
- "tag_type": 1
- },
- {
- "start": 7248,
- "end": 7258
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7267,
- "start": 7258,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "-----------------------"
- },
- "tag": "option",
- "end": 7308,
- "start": 7267,
- "tag_type": 1
- },
- {
- "start": 7308,
- "end": 7331
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7340,
- "start": 7331,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "musicall"
- },
- "tag": "option",
- "end": 7366,
- "start": 7340,
- "tag_type": 1
- },
- {
- "start": 7366,
- "end": 7371
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7380,
- "start": 7371,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "cdall"
- },
- "tag": "option",
- "end": 7403,
- "start": 7380,
- "tag_type": 1
- },
- {
- "start": 7403,
- "end": 7409
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7418,
- "start": 7409,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "downloadall"
- },
- "tag": "option",
- "end": 7447,
- "start": 7418,
- "tag_type": 1
- },
- {
- "start": 7447,
- "end": 7460
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7469,
- "start": 7460,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "rmtitle"
- },
- "tag": "option",
- "end": 7494,
- "start": 7469,
- "tag_type": 1
- },
- {
- "start": 7494,
- "end": 7507
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7516,
- "start": 7507,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "musicartist"
- },
- "tag": "option",
- "end": 7545,
- "start": 7516,
- "tag_type": 1
- },
- {
- "start": 7545,
- "end": 7555
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7564,
- "start": 7555,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "-----------------------"
- },
- "tag": "option",
- "end": 7605,
- "start": 7564,
- "tag_type": 1
- },
- {
- "start": 7605,
- "end": 7628
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7637,
- "start": 7628,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "gameall"
- },
- "tag": "option",
- "end": 7662,
- "start": 7637,
- "tag_type": 1
- },
- {
- "start": 7662,
- "end": 7667
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7676,
- "start": 7667,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "PC"
- },
- "tag": "option",
- "end": 7696,
- "start": 7676,
- "tag_type": 1
- },
- {
- "start": 7696,
- "end": 7702
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7711,
- "start": 7702,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "PS2"
- },
- "tag": "option",
- "end": 7732,
- "start": 7711,
- "tag_type": 1
- },
- {
- "start": 7732,
- "end": 7739
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7748,
- "start": 7739,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "PS3"
- },
- "tag": "option",
- "end": 7769,
- "start": 7748,
- "tag_type": 1
- },
- {
- "start": 7769,
- "end": 7776
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7785,
- "start": 7776,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "PSP"
- },
- "tag": "option",
- "end": 7806,
- "start": 7785,
- "tag_type": 1
- },
- {
- "start": 7806,
- "end": 7813
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7822,
- "start": 7813,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "XBOX"
- },
- "tag": "option",
- "end": 7844,
- "start": 7822,
- "tag_type": 1
- },
- {
- "start": 7844,
- "end": 7852
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7861,
- "start": 7852,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "X360"
- },
- "tag": "option",
- "end": 7883,
- "start": 7861,
- "tag_type": 1
- },
- {
- "start": 7883,
- "end": 7895
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7904,
- "start": 7895,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "DS"
- },
- "tag": "option",
- "end": 7924,
- "start": 7904,
- "tag_type": 1
- },
- {
- "start": 7924,
- "end": 7930
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7939,
- "start": 7930,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "GBA"
- },
- "tag": "option",
- "end": 7960,
- "start": 7939,
- "tag_type": 1
- },
- {
- "start": 7960,
- "end": 7967
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 7976,
- "start": 7967,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "GC"
- },
- "tag": "option",
- "end": 7996,
- "start": 7976,
- "tag_type": 1
- },
- {
- "start": 7996,
- "end": 8008
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 8017,
- "start": 8008,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "WII"
- },
- "tag": "option",
- "end": 8038,
- "start": 8017,
- "tag_type": 1
- },
- {
- "start": 8038,
- "end": 8045
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 8054,
- "start": 8045,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "-----------------------"
- },
- "tag": "option",
- "end": 8095,
- "start": 8054,
- "tag_type": 1
- },
- {
- "start": 8095,
- "end": 8118
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 8127,
- "start": 8118,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "bookall"
- },
- "tag": "option",
- "end": 8152,
- "start": 8127,
- "tag_type": 1
- },
- {
- "start": 8152,
- "end": 8157
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 8166,
- "start": 8157,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "booktitle"
- },
- "tag": "option",
- "end": 8193,
- "start": 8166,
- "tag_type": 1
- },
- {
- "start": 8193,
- "end": 8202
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 8211,
- "start": 8202,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "bookauthor"
- },
- "tag": "option",
- "end": 8239,
- "start": 8211,
- "tag_type": 1
- },
- {
- "start": 8239,
- "end": 8249
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 8258,
- "start": 8249,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "bookisbn"
- },
- "tag": "option",
- "end": 8284,
- "start": 8258,
- "tag_type": 1
- },
- {
- "start": 8284,
- "end": 8292
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 8301,
- "start": 8292,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "-----------------------"
- },
- "tag": "option",
- "end": 8342,
- "start": 8301,
- "tag_type": 1
- },
- {
- "start": 8342,
- "end": 8365
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 8374,
- "start": 8365,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "abcdall"
- },
- "tag": "option",
- "end": 8399,
- "start": 8374,
- "tag_type": 1
- },
- {
- "start": 8399,
- "end": 8409
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 8418,
- "start": 8409,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "abcdtitle"
- },
- "tag": "option",
- "end": 8445,
- "start": 8418,
- "tag_type": 1
- },
- {
- "start": 8445,
- "end": 8454
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 8463,
- "start": 8454,
- "tag_type": 2
- },
- {
- "attributes": {
- "value": "abcdauthor"
- },
- "tag": "option",
- "end": 8491,
- "start": 8463,
- "tag_type": 1
- },
- {
- "start": 8491,
- "end": 8501
- },
- {
- "attributes": {},
- "tag": "option",
- "end": 8510,
- "start": 8501,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "select",
- "end": 8519,
- "start": 8510,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 8525,
- "start": 8519,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 8530,
- "start": 8525,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 8534,
- "start": 8530,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "data"
- },
- "tag": "div",
- "end": 8552,
- "start": 8534,
- "tag_type": 1
- },
- {
- "attributes": {
- "type": "text",
- "name": "searchstring",
- "value": null
- },
- "tag": "input",
- "end": 8602,
- "start": 8552,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 8608,
- "start": 8602,
- "tag_type": 2
- },
- {
- "attributes": {
- "type": "hidden",
- "name": "page",
- "value": "search"
- },
- "tag": "input",
- "end": 8656,
- "start": 8608,
- "tag_type": 1
- },
- {
- "attributes": {
- "type": "hidden",
- "name": "pa",
- "value": "search"
- },
- "tag": "input",
- "end": 8702,
- "start": 8656,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 8707,
- "start": 8702,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "action_td"
- },
- "tag": "td",
- "end": 8729,
- "start": 8707,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "action"
- },
- "tag": "div",
- "end": 8749,
- "start": 8729,
- "tag_type": 1
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteCSS/Play/Live1/img/button/search.gif",
- "name": "go",
- "type": "image",
- "alt": "Search",
- "border": "0",
- "id": "go"
- },
- "tag": "input",
- "end": 8883,
- "start": 8749,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 8889,
- "start": 8883,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 8894,
- "start": 8889,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 8899,
- "start": 8894,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "table",
- "end": 8907,
- "start": 8899,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "form",
- "end": 8914,
- "start": 8907,
- "tag_type": 2
- },
- {
- "start": 8914,
- "end": 8918
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 8924,
- "start": 8918,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 8930,
- "start": 8924,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 8936,
- "start": 8930,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "head_r"
- },
- "tag": "td",
- "end": 8955,
- "start": 8936,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "sbasket"
- },
- "tag": "div",
- "end": 8976,
- "start": 8955,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "h3",
- "end": 8980,
- "start": 8976,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/HOME/HOME/6-/ShoppingBasket.html"
- },
- "tag": "a",
- "end": 9024,
- "start": 8980,
- "tag_type": 1
- },
- {
- "start": 9024,
- "end": 9042
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 9046,
- "start": 9042,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "h3",
- "end": 9051,
- "start": 9046,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "text_empty"
- },
- "tag": "div",
- "end": 9075,
- "start": 9051,
- "tag_type": 1
- },
- {
- "start": 9075,
- "end": 9082
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 9085,
- "start": 9082,
- "tag_type": 1
- },
- {
- "start": 9085,
- "end": 9105
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 9109,
- "start": 9105,
- "tag_type": 2
- },
- {
- "start": 9109,
- "end": 9113
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 9119,
- "start": 9113,
- "tag_type": 2
- },
- {
- "start": 9119,
- "end": 9123
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 9129,
- "start": 9123,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 9134,
- "start": 9129,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 9139,
- "start": 9134,
- "tag_type": 2
- },
- {
- "start": 9139,
- "end": 9143
- },
- {
- "attributes": {},
- "tag": "table",
- "end": 9151,
- "start": 9143,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 9157,
- "start": 9151,
- "tag_type": 2
- },
- {
- "start": 9157,
- "end": 9169
- },
- {
- "attributes": {
- "id": "navbar_contain"
- },
- "tag": "div",
- "end": 9194,
- "start": 9169,
- "tag_type": 1
- },
- {
- "start": 9194,
- "end": 9206
- },
- {
- "attributes": {
- "id": "navbar"
- },
- "tag": "ul",
- "end": 9222,
- "start": 9206,
- "tag_type": 1
- },
- {
- "start": 9222,
- "end": 9234
- },
- {
- "attributes": {
- "id": "nav_home"
- },
- "tag": "li",
- "end": 9252,
- "start": 9234,
- "tag_type": 1
- },
- {
- "start": 9252,
- "end": 9264
- },
- {
- "attributes": {
- "href": "/"
- },
- "tag": "a",
- "end": 9276,
- "start": 9264,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 9282,
- "start": 9276,
- "tag_type": 1
- },
- {
- "start": 9282,
- "end": 9286
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 9293,
- "start": 9286,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 9297,
- "start": 9293,
- "tag_type": 2
- },
- {
- "start": 9297,
- "end": 9321
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 9326,
- "start": 9321,
- "tag_type": 2
- },
- {
- "start": 9326,
- "end": 9338
- },
- {
- "attributes": {
- "id": "nav_dvd"
- },
- "tag": "li",
- "end": 9355,
- "start": 9338,
- "tag_type": 1
- },
- {
- "start": 9355,
- "end": 9367
- },
- {
- "attributes": {
- "href": "/DVD/DVD/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 9405,
- "start": 9367,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 9411,
- "start": 9405,
- "tag_type": 1
- },
- {
- "start": 9411,
- "end": 9414
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 9421,
- "start": 9414,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 9425,
- "start": 9421,
- "tag_type": 2
- },
- {
- "start": 9425,
- "end": 9465
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 9469,
- "start": 9465,
- "tag_type": 1
- },
- {
- "start": 9469,
- "end": 9513
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 9517,
- "start": 9513,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/DVD/DVD/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 9555,
- "start": 9517,
- "tag_type": 1
- },
- {
- "start": 9555,
- "end": 9558
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 9562,
- "start": 9558,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 9567,
- "start": 9562,
- "tag_type": 2
- },
- {
- "start": 9567,
- "end": 9611
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 9615,
- "start": 9611,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/DVD/DVD/-/55/70/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 9678,
- "start": 9615,
- "tag_type": 1
- },
- {
- "start": 9678,
- "end": 9687
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 9691,
- "start": 9687,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 9696,
- "start": 9691,
- "tag_type": 2
- },
- {
- "start": 9696,
- "end": 9740
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 9744,
- "start": 9740,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/DVD/DVD/-/46/61/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 9807,
- "start": 9744,
- "tag_type": 1
- },
- {
- "start": 9807,
- "end": 9820
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 9824,
- "start": 9820,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 9829,
- "start": 9824,
- "tag_type": 2
- },
- {
- "start": 9829,
- "end": 9873
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 9877,
- "start": 9873,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Music/MusicDVD/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 9922,
- "start": 9877,
- "tag_type": 1
- },
- {
- "start": 9922,
- "end": 9931
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 9935,
- "start": 9931,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 9940,
- "start": 9935,
- "tag_type": 2
- },
- {
- "start": 9940,
- "end": 9984
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 9988,
- "start": 9984,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/261/341/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 10069,
- "start": 9988,
- "tag_type": 1
- },
- {
- "start": 10069,
- "end": 10080
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 10084,
- "start": 10080,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 10089,
- "start": 10084,
- "tag_type": 2
- },
- {
- "start": 10089,
- "end": 10133
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 10137,
- "start": 10133,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Gadgets/Gadgets/-/392/492/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 10210,
- "start": 10137,
- "tag_type": 1
- },
- {
- "start": 10210,
- "end": 10226
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 10230,
- "start": 10226,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 10235,
- "start": 10230,
- "tag_type": 2
- },
- {
- "start": 10235,
- "end": 10279
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 10283,
- "start": 10279,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Clothing/T-Shirts/-/723/931/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 10358,
- "start": 10283,
- "tag_type": 1
- },
- {
- "start": 10358,
- "end": 10376
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 10380,
- "start": 10376,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 10385,
- "start": 10380,
- "tag_type": 2
- },
- {
- "start": 10385,
- "end": 10429
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 10433,
- "start": 10429,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Gadgets/Gadgets/-/565/750/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 10506,
- "start": 10433,
- "tag_type": 1
- },
- {
- "start": 10506,
- "end": 10518
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 10522,
- "start": 10518,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 10527,
- "start": 10522,
- "tag_type": 2
- },
- {
- "start": 10527,
- "end": 10571
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 10575,
- "start": 10571,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Books/Books/-/184/241/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 10644,
- "start": 10575,
- "tag_type": 1
- },
- {
- "start": 10644,
- "end": 10654
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 10658,
- "start": 10654,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 10663,
- "start": 10658,
- "tag_type": 2
- },
- {
- "start": 10663,
- "end": 10707
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 10711,
- "start": 10707,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/landingpage.aspx?page=playtrade&dpr=0&dpr=0&dpr=0&product=dvd"
- },
- "tag": "a",
- "end": 10784,
- "start": 10711,
- "tag_type": 1
- },
- {
- "start": 10784,
- "end": 10798
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 10802,
- "start": 10798,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 10807,
- "start": 10802,
- "tag_type": 2
- },
- {
- "start": 10807,
- "end": 10851
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 10856,
- "start": 10851,
- "tag_type": 2
- },
- {
- "start": 10856,
- "end": 10884
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 10889,
- "start": 10884,
- "tag_type": 2
- },
- {
- "start": 10889,
- "end": 10901
- },
- {
- "attributes": {
- "id": "nav_blu"
- },
- "tag": "li",
- "end": 10918,
- "start": 10901,
- "tag_type": 1
- },
- {
- "start": 10918,
- "end": 10930
- },
- {
- "attributes": {
- "href": "/DVD/Blu-ray/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 10972,
- "start": 10930,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 10978,
- "start": 10972,
- "tag_type": 1
- },
- {
- "start": 10978,
- "end": 10985
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 10992,
- "start": 10985,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 10996,
- "start": 10992,
- "tag_type": 2
- },
- {
- "start": 10996,
- "end": 11036
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 11040,
- "start": 11036,
- "tag_type": 1
- },
- {
- "start": 11040,
- "end": 11084
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 11088,
- "start": 11084,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/DVD/Blu-ray/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 11130,
- "start": 11088,
- "tag_type": 1
- },
- {
- "start": 11130,
- "end": 11134
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 11138,
- "start": 11134,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 11143,
- "start": 11138,
- "tag_type": 2
- },
- {
- "start": 11143,
- "end": 11187
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 11191,
- "start": 11187,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/DVD/Blu-ray/6-/TopSellers.html"
- },
- "tag": "a",
- "end": 11233,
- "start": 11191,
- "tag_type": 1
- },
- {
- "start": 11233,
- "end": 11252
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 11256,
- "start": 11252,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 11261,
- "start": 11256,
- "tag_type": 2
- },
- {
- "start": 11261,
- "end": 11305
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 11309,
- "start": 11305,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/DVD/Blu-ray/6-/PreOrderChart.html"
- },
- "tag": "a",
- "end": 11354,
- "start": 11309,
- "tag_type": 1
- },
- {
- "start": 11354,
- "end": 11371
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 11375,
- "start": 11371,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 11380,
- "start": 11375,
- "tag_type": 2
- },
- {
- "start": 11380,
- "end": 11424
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 11428,
- "start": 11424,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/DVD/Blu-ray/6-/PromoList.html"
- },
- "tag": "a",
- "end": 11469,
- "start": 11428,
- "tag_type": 1
- },
- {
- "start": 11469,
- "end": 11485
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 11489,
- "start": 11485,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 11494,
- "start": 11489,
- "tag_type": 2
- },
- {
- "start": 11494,
- "end": 11538
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 11542,
- "start": 11538,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/836/1052/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 11624,
- "start": 11542,
- "tag_type": 1
- },
- {
- "start": 11624,
- "end": 11639
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 11643,
- "start": 11639,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 11648,
- "start": 11643,
- "tag_type": 2
- },
- {
- "start": 11648,
- "end": 11692
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 11696,
- "start": 11692,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 11777,
- "start": 11696,
- "tag_type": 1
- },
- {
- "start": 11777,
- "end": 11783
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 11787,
- "start": 11783,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 11792,
- "start": 11787,
- "tag_type": 2
- },
- {
- "start": 11792,
- "end": 11836
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 11840,
- "start": 11836,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Games/PlayStation3/3-/164637/2-/Promo.html"
- },
- "tag": "a",
- "end": 11894,
- "start": 11840,
- "tag_type": 1
- },
- {
- "start": 11894,
- "end": 11906
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 11910,
- "start": 11906,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 11915,
- "start": 11910,
- "tag_type": 2
- },
- {
- "start": 11915,
- "end": 11959
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 11963,
- "start": 11959,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Games/PlayStation3/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 12012,
- "start": 11963,
- "tag_type": 1
- },
- {
- "start": 12012,
- "end": 12021
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 12025,
- "start": 12021,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 12030,
- "start": 12025,
- "tag_type": 2
- },
- {
- "start": 12030,
- "end": 12074
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 12078,
- "start": 12074,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/281/363/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 12159,
- "start": 12078,
- "tag_type": 1
- },
- {
- "start": 12159,
- "end": 12178
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 12182,
- "start": 12178,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 12187,
- "start": 12182,
- "tag_type": 2
- },
- {
- "start": 12187,
- "end": 12231
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 12236,
- "start": 12231,
- "tag_type": 2
- },
- {
- "start": 12236,
- "end": 12264
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 12269,
- "start": 12264,
- "tag_type": 2
- },
- {
- "start": 12269,
- "end": 12281
- },
- {
- "attributes": {
- "id": "nav_music"
- },
- "tag": "li",
- "end": 12300,
- "start": 12281,
- "tag_type": 1
- },
- {
- "start": 12300,
- "end": 12312
- },
- {
- "attributes": {
- "href": "/Music/CD/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 12351,
- "start": 12312,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 12357,
- "start": 12351,
- "tag_type": 1
- },
- {
- "start": 12357,
- "end": 12362
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 12369,
- "start": 12362,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 12373,
- "start": 12369,
- "tag_type": 2
- },
- {
- "start": 12373,
- "end": 12413
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 12417,
- "start": 12413,
- "tag_type": 1
- },
- {
- "start": 12417,
- "end": 12461
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 12465,
- "start": 12461,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Music/CD/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 12504,
- "start": 12465,
- "tag_type": 1
- },
- {
- "start": 12504,
- "end": 12506
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 12510,
- "start": 12506,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 12515,
- "start": 12510,
- "tag_type": 2
- },
- {
- "start": 12515,
- "end": 12559
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 12563,
- "start": 12559,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Music/CD/-/27/30/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 12627,
- "start": 12563,
- "tag_type": 1
- },
- {
- "start": 12627,
- "end": 12639
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 12643,
- "start": 12639,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 12648,
- "start": 12643,
- "tag_type": 2
- },
- {
- "start": 12648,
- "end": 12692
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 12696,
- "start": 12692,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Tickets/TicketsEvent/-/959/1208/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 12775,
- "start": 12696,
- "tag_type": 1
- },
- {
- "start": 12775,
- "end": 12790
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 12794,
- "start": 12790,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 12799,
- "start": 12794,
- "tag_type": 2
- },
- {
- "start": 12799,
- "end": 12843
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 12847,
- "start": 12843,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Music/MP3-Download/6-/DigitalHome.html"
- },
- "tag": "a",
- "end": 12897,
- "start": 12847,
- "tag_type": 1
- },
- {
- "start": 12897,
- "end": 12910
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 12914,
- "start": 12910,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 12919,
- "start": 12914,
- "tag_type": 2
- },
- {
- "start": 12919,
- "end": 12963
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 12967,
- "start": 12963,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Music/MusicDVD/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 13012,
- "start": 12967,
- "tag_type": 1
- },
- {
- "start": 13012,
- "end": 13021
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 13025,
- "start": 13021,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 13030,
- "start": 13025,
- "tag_type": 2
- },
- {
- "start": 13030,
- "end": 13074
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 13078,
- "start": 13074,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/291/375/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 13159,
- "start": 13078,
- "tag_type": 1
- },
- {
- "start": 13159,
- "end": 13178
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 13182,
- "start": 13178,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 13187,
- "start": 13182,
- "tag_type": 2
- },
- {
- "start": 13187,
- "end": 13231
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 13235,
- "start": 13231,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Clothing/Clothing/6-/Campaign.html?campaign=2831&cid=6512018"
- },
- "tag": "a",
- "end": 13307,
- "start": 13235,
- "tag_type": 1
- },
- {
- "start": 13307,
- "end": 13321
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 13325,
- "start": 13321,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 13330,
- "start": 13325,
- "tag_type": 2
- },
- {
- "start": 13330,
- "end": 13374
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 13378,
- "start": 13374,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Gadgets/Gadgets/-/570/755/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 13451,
- "start": 13378,
- "tag_type": 1
- },
- {
- "start": 13451,
- "end": 13464
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 13468,
- "start": 13464,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 13473,
- "start": 13468,
- "tag_type": 2
- },
- {
- "start": 13473,
- "end": 13517
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 13521,
- "start": 13517,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Books/Books/-/184/241/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 13590,
- "start": 13521,
- "tag_type": 1
- },
- {
- "start": 13590,
- "end": 13601
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 13605,
- "start": 13601,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 13610,
- "start": 13605,
- "tag_type": 2
- },
- {
- "start": 13610,
- "end": 13654
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 13658,
- "start": 13654,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/landingpage.aspx?page=playtrade&dpr=0&dpr=0&dpr=0&product=cd"
- },
- "tag": "a",
- "end": 13730,
- "start": 13658,
- "tag_type": 1
- },
- {
- "start": 13730,
- "end": 13743
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 13747,
- "start": 13743,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 13752,
- "start": 13747,
- "tag_type": 2
- },
- {
- "start": 13752,
- "end": 13796
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 13801,
- "start": 13796,
- "tag_type": 2
- },
- {
- "start": 13801,
- "end": 13829
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 13834,
- "start": 13829,
- "tag_type": 2
- },
- {
- "start": 13834,
- "end": 13846
- },
- {
- "attributes": {
- "id": "nav_tickets"
- },
- "tag": "li",
- "end": 13867,
- "start": 13846,
- "tag_type": 1
- },
- {
- "start": 13867,
- "end": 13879
- },
- {
- "attributes": {
- "href": "/Tickets/TicketsEvent/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 13930,
- "start": 13879,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 13936,
- "start": 13930,
- "tag_type": 1
- },
- {
- "start": 13936,
- "end": 13943
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 13950,
- "start": 13943,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 13954,
- "start": 13950,
- "tag_type": 2
- },
- {
- "start": 13954,
- "end": 13994
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 13998,
- "start": 13994,
- "tag_type": 1
- },
- {
- "start": 13998,
- "end": 14042
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 14046,
- "start": 14042,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Tickets/TicketsEvent/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 14097,
- "start": 14046,
- "tag_type": 1
- },
- {
- "start": 14097,
- "end": 14101
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 14105,
- "start": 14101,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 14110,
- "start": 14105,
- "tag_type": 2
- },
- {
- "start": 14110,
- "end": 14154
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 14158,
- "start": 14154,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Tickets/TicketsEvent/-/959/1208/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 14237,
- "start": 14158,
- "tag_type": 1
- },
- {
- "start": 14237,
- "end": 14252
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 14256,
- "start": 14252,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 14261,
- "start": 14256,
- "tag_type": 2
- },
- {
- "start": 14261,
- "end": 14305
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 14309,
- "start": 14305,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Tickets/TicketsEvent/-/968/1217/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 14388,
- "start": 14309,
- "tag_type": 1
- },
- {
- "start": 14388,
- "end": 14402
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 14406,
- "start": 14402,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 14411,
- "start": 14406,
- "tag_type": 2
- },
- {
- "start": 14411,
- "end": 14455
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 14459,
- "start": 14455,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/GenreBrowse.aspx?r=TICKETS_EVENT&p=969&g=1218"
- },
- "tag": "a",
- "end": 14516,
- "start": 14459,
- "tag_type": 1
- },
- {
- "start": 14516,
- "end": 14522
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 14526,
- "start": 14522,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 14531,
- "start": 14526,
- "tag_type": 2
- },
- {
- "start": 14531,
- "end": 14575
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 14579,
- "start": 14575,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Tickets/TicketsEvent/-/975/1224/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 14658,
- "start": 14579,
- "tag_type": 1
- },
- {
- "start": 14658,
- "end": 14664
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 14668,
- "start": 14664,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 14673,
- "start": 14668,
- "tag_type": 2
- },
- {
- "start": 14673,
- "end": 14717
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 14721,
- "start": 14717,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Tickets/TicketsEvent/-/1079/1315/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 14801,
- "start": 14721,
- "tag_type": 1
- },
- {
- "start": 14801,
- "end": 14812
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 14816,
- "start": 14812,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 14821,
- "start": 14816,
- "tag_type": 2
- },
- {
- "start": 14821,
- "end": 14865
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 14869,
- "start": 14865,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Clothing/Clothing/6-/Campaign.html?campaign=2831&cid=6512018"
- },
- "tag": "a",
- "end": 14941,
- "start": 14869,
- "tag_type": 1
- },
- {
- "start": 14941,
- "end": 14955
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 14959,
- "start": 14955,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 14964,
- "start": 14959,
- "tag_type": 2
- },
- {
- "start": 14964,
- "end": 15008
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 15012,
- "start": 15008,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/landingpage.aspx?page=playtrade&dpr=0&dpr=0&dpr=0&product=ticket"
- },
- "tag": "a",
- "end": 15088,
- "start": 15012,
- "tag_type": 1
- },
- {
- "start": 15088,
- "end": 15105
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 15109,
- "start": 15105,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 15114,
- "start": 15109,
- "tag_type": 2
- },
- {
- "start": 15114,
- "end": 15158
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 15163,
- "start": 15158,
- "tag_type": 2
- },
- {
- "start": 15163,
- "end": 15191
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 15196,
- "start": 15191,
- "tag_type": 2
- },
- {
- "start": 15196,
- "end": 15208
- },
- {
- "attributes": {
- "id": "nav_game"
- },
- "tag": "li",
- "end": 15226,
- "start": 15208,
- "tag_type": 1
- },
- {
- "start": 15226,
- "end": 15238
- },
- {
- "attributes": {
- "href": "/Games/Games/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 15280,
- "start": 15238,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 15286,
- "start": 15280,
- "tag_type": 1
- },
- {
- "start": 15286,
- "end": 15291
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 15298,
- "start": 15291,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 15302,
- "start": 15298,
- "tag_type": 2
- },
- {
- "start": 15302,
- "end": 15342
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 15346,
- "start": 15342,
- "tag_type": 1
- },
- {
- "start": 15346,
- "end": 15390
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 15394,
- "start": 15390,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Games/Games/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 15436,
- "start": 15394,
- "tag_type": 1
- },
- {
- "start": 15436,
- "end": 15440
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 15444,
- "start": 15440,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 15449,
- "start": 15444,
- "tag_type": 2
- },
- {
- "start": 15449,
- "end": 15493
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 15497,
- "start": 15493,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Games/Games/6-/Campaign.html?campaign=5371&cid=2061705"
- },
- "tag": "a",
- "end": 15563,
- "start": 15497,
- "tag_type": 1
- },
- {
- "start": 15563,
- "end": 15577
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 15581,
- "start": 15577,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 15586,
- "start": 15581,
- "tag_type": 2
- },
- {
- "start": 15586,
- "end": 15630
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 15634,
- "start": 15630,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Games/PlayStation3/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 15683,
- "start": 15634,
- "tag_type": 1
- },
- {
- "start": 15683,
- "end": 15691
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 15695,
- "start": 15691,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 15700,
- "start": 15695,
- "tag_type": 2
- },
- {
- "start": 15700,
- "end": 15744
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 15748,
- "start": 15744,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Games/PlayStation2/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 15797,
- "start": 15748,
- "tag_type": 1
- },
- {
- "start": 15797,
- "end": 15805
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 15809,
- "start": 15805,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 15814,
- "start": 15809,
- "tag_type": 2
- },
- {
- "start": 15814,
- "end": 15858
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 15862,
- "start": 15858,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Games/PSP/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 15902,
- "start": 15862,
- "tag_type": 1
- },
- {
- "start": 15902,
- "end": 15910
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 15914,
- "start": 15910,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 15919,
- "start": 15914,
- "tag_type": 2
- },
- {
- "start": 15919,
- "end": 15963
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 15967,
- "start": 15963,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Games/Wii/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 16007,
- "start": 15967,
- "tag_type": 1
- },
- {
- "start": 16007,
- "end": 16019
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 16023,
- "start": 16019,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 16028,
- "start": 16023,
- "tag_type": 2
- },
- {
- "start": 16028,
- "end": 16072
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 16076,
- "start": 16072,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Games/DS/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 16115,
- "start": 16076,
- "tag_type": 1
- },
- {
- "start": 16115,
- "end": 16132
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 16136,
- "start": 16132,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 16141,
- "start": 16136,
- "tag_type": 2
- },
- {
- "start": 16141,
- "end": 16185
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 16189,
- "start": 16185,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Games/Xbox360/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 16233,
- "start": 16189,
- "tag_type": 1
- },
- {
- "start": 16233,
- "end": 16241
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 16245,
- "start": 16241,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 16250,
- "start": 16245,
- "tag_type": 2
- },
- {
- "start": 16250,
- "end": 16294
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 16298,
- "start": 16294,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Games/PC/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 16337,
- "start": 16298,
- "tag_type": 1
- },
- {
- "start": 16337,
- "end": 16345
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 16349,
- "start": 16345,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 16354,
- "start": 16349,
- "tag_type": 2
- },
- {
- "start": 16354,
- "end": 16398
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 16402,
- "start": 16398,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Games/PC/3-/4047/2-/Promo.html?dpr=4047"
- },
- "tag": "a",
- "end": 16453,
- "start": 16402,
- "tag_type": 1
- },
- {
- "start": 16453,
- "end": 16462
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 16466,
- "start": 16462,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 16471,
- "start": 16466,
- "tag_type": 2
- },
- {
- "start": 16471,
- "end": 16515
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 16519,
- "start": 16515,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Books/Books/-/128/185/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 16588,
- "start": 16519,
- "tag_type": 1
- },
- {
- "start": 16588,
- "end": 16600
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 16604,
- "start": 16600,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 16609,
- "start": 16604,
- "tag_type": 2
- },
- {
- "start": 16609,
- "end": 16653
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 16657,
- "start": 16653,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Clothing/T-Shirts/-/837/1053/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 16733,
- "start": 16657,
- "tag_type": 1
- },
- {
- "start": 16733,
- "end": 16747
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 16751,
- "start": 16747,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 16756,
- "start": 16751,
- "tag_type": 2
- },
- {
- "start": 16756,
- "end": 16800
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 16804,
- "start": 16800,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Gadgets/Gadgets/-/835/1051/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 16878,
- "start": 16804,
- "tag_type": 1
- },
- {
- "start": 16878,
- "end": 16895
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 16899,
- "start": 16895,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 16904,
- "start": 16899,
- "tag_type": 2
- },
- {
- "start": 16904,
- "end": 16948
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 16952,
- "start": 16948,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/landingpage.aspx?page=playtrade&dpr=0&dpr=0&dpr=0&product=game"
- },
- "tag": "a",
- "end": 17026,
- "start": 16952,
- "tag_type": 1
- },
- {
- "start": 17026,
- "end": 17041
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 17045,
- "start": 17041,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 17050,
- "start": 17045,
- "tag_type": 2
- },
- {
- "start": 17050,
- "end": 17094
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 17099,
- "start": 17094,
- "tag_type": 2
- },
- {
- "start": 17099,
- "end": 17127
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 17132,
- "start": 17127,
- "tag_type": 2
- },
- {
- "start": 17132,
- "end": 17144
- },
- {
- "attributes": {
- "id": "nav_book"
- },
- "tag": "li",
- "end": 17162,
- "start": 17144,
- "tag_type": 1
- },
- {
- "start": 17162,
- "end": 17174
- },
- {
- "attributes": {
- "href": "/Books/Books/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 17216,
- "start": 17174,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 17222,
- "start": 17216,
- "tag_type": 1
- },
- {
- "start": 17222,
- "end": 17227
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 17234,
- "start": 17227,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 17238,
- "start": 17234,
- "tag_type": 2
- },
- {
- "start": 17238,
- "end": 17278
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 17282,
- "start": 17278,
- "tag_type": 1
- },
- {
- "start": 17282,
- "end": 17326
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 17330,
- "start": 17326,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Books/Books/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 17372,
- "start": 17330,
- "tag_type": 1
- },
- {
- "start": 17372,
- "end": 17376
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 17380,
- "start": 17376,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 17385,
- "start": 17380,
- "tag_type": 2
- },
- {
- "start": 17385,
- "end": 17429
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 17433,
- "start": 17429,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Books/Books/-/104/161/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 17502,
- "start": 17433,
- "tag_type": 1
- },
- {
- "start": 17502,
- "end": 17512
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 17516,
- "start": 17512,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 17521,
- "start": 17516,
- "tag_type": 2
- },
- {
- "start": 17521,
- "end": 17565
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 17569,
- "start": 17565,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Books/Books/-/100/157/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 17638,
- "start": 17569,
- "tag_type": 1
- },
- {
- "start": 17638,
- "end": 17647
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 17651,
- "start": 17647,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 17656,
- "start": 17651,
- "tag_type": 2
- },
- {
- "start": 17656,
- "end": 17700
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 17704,
- "start": 17700,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Books/Books/-/203/260/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 17773,
- "start": 17704,
- "tag_type": 1
- },
- {
- "start": 17773,
- "end": 17787
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 17791,
- "start": 17787,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 17796,
- "start": 17791,
- "tag_type": 2
- },
- {
- "start": 17796,
- "end": 17840
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 17844,
- "start": 17840,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Books/Books/-/200/257/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 17913,
- "start": 17844,
- "tag_type": 1
- },
- {
- "start": 17913,
- "end": 17929
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 17933,
- "start": 17929,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 17938,
- "start": 17933,
- "tag_type": 2
- },
- {
- "start": 17938,
- "end": 17982
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 17986,
- "start": 17982,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Books/Books/-/142/199/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 18055,
- "start": 17986,
- "tag_type": 1
- },
- {
- "start": 18055,
- "end": 18069
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 18073,
- "start": 18069,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 18078,
- "start": 18073,
- "tag_type": 2
- },
- {
- "start": 18078,
- "end": 18122
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 18126,
- "start": 18122,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Books/Books/-/159/216/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 18195,
- "start": 18126,
- "tag_type": 1
- },
- {
- "start": 18195,
- "end": 18207
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 18211,
- "start": 18207,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 18216,
- "start": 18211,
- "tag_type": 2
- },
- {
- "start": 18216,
- "end": 18260
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 18264,
- "start": 18260,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Books/Books/-/151/208/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 18333,
- "start": 18264,
- "tag_type": 1
- },
- {
- "start": 18333,
- "end": 18340
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 18344,
- "start": 18340,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 18349,
- "start": 18344,
- "tag_type": 2
- },
- {
- "start": 18349,
- "end": 18393
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 18397,
- "start": 18393,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Books/AudioBooks/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 18444,
- "start": 18397,
- "tag_type": 1
- },
- {
- "start": 18444,
- "end": 18454
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 18458,
- "start": 18454,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 18463,
- "start": 18458,
- "tag_type": 2
- },
- {
- "start": 18463,
- "end": 18507
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 18511,
- "start": 18507,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/landingpage.aspx?page=playtrade&dpr=0&dpr=0&dpr=0&product=book"
- },
- "tag": "a",
- "end": 18585,
- "start": 18511,
- "tag_type": 1
- },
- {
- "start": 18585,
- "end": 18600
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 18604,
- "start": 18600,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 18609,
- "start": 18604,
- "tag_type": 2
- },
- {
- "start": 18609,
- "end": 18653
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 18658,
- "start": 18653,
- "tag_type": 2
- },
- {
- "start": 18658,
- "end": 18686
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 18691,
- "start": 18686,
- "tag_type": 2
- },
- {
- "start": 18691,
- "end": 18703
- },
- {
- "attributes": {
- "id": "nav_clth"
- },
- "tag": "li",
- "end": 18721,
- "start": 18703,
- "tag_type": 1
- },
- {
- "start": 18721,
- "end": 18733
- },
- {
- "attributes": {
- "href": "/Clothing/Clothing/6-/ClothingHome.html"
- },
- "tag": "a",
- "end": 18783,
- "start": 18733,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 18789,
- "start": 18783,
- "tag_type": 1
- },
- {
- "start": 18789,
- "end": 18797
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 18804,
- "start": 18797,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 18808,
- "start": 18804,
- "tag_type": 2
- },
- {
- "start": 18808,
- "end": 18848
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 18852,
- "start": 18848,
- "tag_type": 1
- },
- {
- "start": 18852,
- "end": 18896
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 18900,
- "start": 18896,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Clothing/Clothing/6-/ClothingHome.html"
- },
- "tag": "a",
- "end": 18950,
- "start": 18900,
- "tag_type": 1
- },
- {
- "start": 18950,
- "end": 18954
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 18958,
- "start": 18954,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 18963,
- "start": 18958,
- "tag_type": 2
- },
- {
- "start": 18963,
- "end": 19007
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 19011,
- "start": 19007,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Clothing/T-Shirts/-/720/928/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 19086,
- "start": 19011,
- "tag_type": 1
- },
- {
- "start": 19086,
- "end": 19099
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 19103,
- "start": 19099,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 19108,
- "start": 19103,
- "tag_type": 2
- },
- {
- "start": 19108,
- "end": 19152
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 19156,
- "start": 19152,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Clothing/T-Shirts/-/721/929/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 19231,
- "start": 19156,
- "tag_type": 1
- },
- {
- "start": 19231,
- "end": 19246
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 19250,
- "start": 19246,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 19255,
- "start": 19250,
- "tag_type": 2
- },
- {
- "start": 19255,
- "end": 19299
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 19303,
- "start": 19299,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Clothing/Clothing/6-/Campaign.html?campaign=2825&cid=1354516"
- },
- "tag": "a",
- "end": 19375,
- "start": 19303,
- "tag_type": 1
- },
- {
- "start": 19375,
- "end": 19388
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 19392,
- "start": 19388,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 19397,
- "start": 19392,
- "tag_type": 2
- },
- {
- "start": 19397,
- "end": 19441
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 19445,
- "start": 19441,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Clothing/Clothing/6-/Campaign.html?campaign=2831&cid=6512018"
- },
- "tag": "a",
- "end": 19517,
- "start": 19445,
- "tag_type": 1
- },
- {
- "start": 19517,
- "end": 19531
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 19535,
- "start": 19531,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 19540,
- "start": 19535,
- "tag_type": 2
- },
- {
- "start": 19540,
- "end": 19584
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 19588,
- "start": 19584,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Clothing/T-Shirts/-/723/931/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 19663,
- "start": 19588,
- "tag_type": 1
- },
- {
- "start": 19663,
- "end": 19681
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 19685,
- "start": 19681,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 19690,
- "start": 19685,
- "tag_type": 2
- },
- {
- "start": 19690,
- "end": 19734
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 19738,
- "start": 19734,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Clothing/Accessories/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 19789,
- "start": 19738,
- "tag_type": 1
- },
- {
- "start": 19789,
- "end": 19800
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 19804,
- "start": 19800,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 19809,
- "start": 19804,
- "tag_type": 2
- },
- {
- "start": 19809,
- "end": 19853
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 19857,
- "start": 19853,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Clothing/Accessories/-/2026/1276/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 19937,
- "start": 19857,
- "tag_type": 1
- },
- {
- "start": 19937,
- "end": 19947
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 19951,
- "start": 19947,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 19956,
- "start": 19951,
- "tag_type": 2
- },
- {
- "start": 19956,
- "end": 20000
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 20005,
- "start": 20000,
- "tag_type": 2
- },
- {
- "start": 20005,
- "end": 20033
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 20038,
- "start": 20033,
- "tag_type": 2
- },
- {
- "start": 20038,
- "end": 20050
- },
- {
- "attributes": {
- "id": "nav_elec"
- },
- "tag": "li",
- "end": 20068,
- "start": 20050,
- "tag_type": 1
- },
- {
- "start": 20068,
- "end": 20080
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/6-/RegionHome.html",
- "class": "this"
- },
- "tag": "a",
- "end": 20147,
- "start": 20080,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 20153,
- "start": 20147,
- "tag_type": 1
- },
- {
- "start": 20153,
- "end": 20164
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 20171,
- "start": 20164,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 20175,
- "start": 20171,
- "tag_type": 2
- },
- {
- "start": 20175,
- "end": 20215
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 20219,
- "start": 20215,
- "tag_type": 1
- },
- {
- "start": 20219,
- "end": 20263
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 20267,
- "start": 20263,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 20321,
- "start": 20267,
- "tag_type": 1
- },
- {
- "start": 20321,
- "end": 20325
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 20329,
- "start": 20325,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 20334,
- "start": 20329,
- "tag_type": 2
- },
- {
- "start": 20334,
- "end": 20378
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 20382,
- "start": 20378,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 20463,
- "start": 20382,
- "tag_type": 1
- },
- {
- "start": 20463,
- "end": 20474
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 20478,
- "start": 20474,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 20483,
- "start": 20478,
- "tag_type": 2
- },
- {
- "start": 20483,
- "end": 20527
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 20531,
- "start": 20527,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/291/375/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 20612,
- "start": 20531,
- "tag_type": 1
- },
- {
- "start": 20612,
- "end": 20631
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 20635,
- "start": 20631,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 20640,
- "start": 20635,
- "tag_type": 2
- },
- {
- "start": 20640,
- "end": 20684
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 20688,
- "start": 20684,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/2168/1435/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 20771,
- "start": 20688,
- "tag_type": 1
- },
- {
- "start": 20771,
- "end": 20779
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 20783,
- "start": 20779,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 20788,
- "start": 20783,
- "tag_type": 2
- },
- {
- "start": 20788,
- "end": 20832
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 20836,
- "start": 20832,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Games/Games/6-/Campaign.html?campaign=5371&cid=2061705"
- },
- "tag": "a",
- "end": 20902,
- "start": 20836,
- "tag_type": 1
- },
- {
- "start": 20902,
- "end": 20916
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 20920,
- "start": 20916,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 20925,
- "start": 20920,
- "tag_type": 2
- },
- {
- "start": 20925,
- "end": 20969
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 20973,
- "start": 20969,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/PC/PCs/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 21010,
- "start": 20973,
- "tag_type": 1
- },
- {
- "start": 21010,
- "end": 21019
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 21023,
- "start": 21019,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 21028,
- "start": 21023,
- "tag_type": 2
- },
- {
- "start": 21028,
- "end": 21072
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 21076,
- "start": 21072,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/261/341/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 21157,
- "start": 21076,
- "tag_type": 1
- },
- {
- "start": 21157,
- "end": 21178
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 21182,
- "start": 21178,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 21187,
- "start": 21182,
- "tag_type": 2
- },
- {
- "start": 21187,
- "end": 21231
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 21235,
- "start": 21231,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/256/336/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 21316,
- "start": 21235,
- "tag_type": 1
- },
- {
- "start": 21316,
- "end": 21331
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 21335,
- "start": 21331,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 21340,
- "start": 21335,
- "tag_type": 2
- },
- {
- "start": 21340,
- "end": 21384
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 21388,
- "start": 21384,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/253/333/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 21469,
- "start": 21388,
- "tag_type": 1
- },
- {
- "start": 21469,
- "end": 21479
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 21483,
- "start": 21479,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 21488,
- "start": 21483,
- "tag_type": 2
- },
- {
- "start": 21488,
- "end": 21532
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 21536,
- "start": 21532,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/281/363/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 21617,
- "start": 21536,
- "tag_type": 1
- },
- {
- "start": 21617,
- "end": 21628
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 21632,
- "start": 21628,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 21637,
- "start": 21632,
- "tag_type": 2
- },
- {
- "start": 21637,
- "end": 21681
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 21685,
- "start": 21681,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/275/355/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 21766,
- "start": 21685,
- "tag_type": 1
- },
- {
- "start": 21766,
- "end": 21779
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 21783,
- "start": 21779,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 21788,
- "start": 21783,
- "tag_type": 2
- },
- {
- "start": 21788,
- "end": 21832
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 21836,
- "start": 21832,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/316/402/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 21917,
- "start": 21836,
- "tag_type": 1
- },
- {
- "start": 21917,
- "end": 21924
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 21928,
- "start": 21924,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 21933,
- "start": 21928,
- "tag_type": 2
- },
- {
- "start": 21933,
- "end": 21977
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 21981,
- "start": 21977,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/267/347/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 22062,
- "start": 21981,
- "tag_type": 1
- },
- {
- "start": 22062,
- "end": 22074
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 22078,
- "start": 22074,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 22083,
- "start": 22078,
- "tag_type": 2
- },
- {
- "start": 22083,
- "end": 22127
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 22131,
- "start": 22127,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/996/1241/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 22213,
- "start": 22131,
- "tag_type": 1
- },
- {
- "start": 22213,
- "end": 22219
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 22223,
- "start": 22219,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 22228,
- "start": 22223,
- "tag_type": 2
- },
- {
- "start": 22228,
- "end": 22272
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 22276,
- "start": 22272,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/271/351/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 22357,
- "start": 22276,
- "tag_type": 1
- },
- {
- "start": 22357,
- "end": 22367
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 22371,
- "start": 22367,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 22376,
- "start": 22371,
- "tag_type": 2
- },
- {
- "start": 22376,
- "end": 22420
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 22424,
- "start": 22420,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/988/1236/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 22506,
- "start": 22424,
- "tag_type": 1
- },
- {
- "start": 22506,
- "end": 22526
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 22530,
- "start": 22526,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 22535,
- "start": 22530,
- "tag_type": 2
- },
- {
- "start": 22535,
- "end": 22579
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 22584,
- "start": 22579,
- "tag_type": 2
- },
- {
- "start": 22584,
- "end": 22612
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 22617,
- "start": 22612,
- "tag_type": 2
- },
- {
- "start": 22617,
- "end": 22629
- },
- {
- "attributes": {
- "id": "nav_pcsh"
- },
- "tag": "li",
- "end": 22647,
- "start": 22629,
- "tag_type": 1
- },
- {
- "start": 22647,
- "end": 22659
- },
- {
- "attributes": {
- "href": "/PC/PCs/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 22696,
- "start": 22659,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 22702,
- "start": 22696,
- "tag_type": 1
- },
- {
- "start": 22702,
- "end": 22711
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 22718,
- "start": 22711,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 22722,
- "start": 22718,
- "tag_type": 2
- },
- {
- "start": 22722,
- "end": 22762
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 22766,
- "start": 22762,
- "tag_type": 1
- },
- {
- "start": 22766,
- "end": 22810
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 22814,
- "start": 22810,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/PC/PCs/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 22851,
- "start": 22814,
- "tag_type": 1
- },
- {
- "start": 22851,
- "end": 22855
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 22859,
- "start": 22855,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 22864,
- "start": 22859,
- "tag_type": 2
- },
- {
- "start": 22864,
- "end": 22908
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 22912,
- "start": 22908,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/PC/PCs/-/653/860/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 22976,
- "start": 22912,
- "tag_type": 1
- },
- {
- "start": 22976,
- "end": 22985
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 22989,
- "start": 22985,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 22994,
- "start": 22989,
- "tag_type": 2
- },
- {
- "start": 22994,
- "end": 23038
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 23042,
- "start": 23038,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/PC/PCs/-/654/861/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 23106,
- "start": 23042,
- "tag_type": 1
- },
- {
- "start": 23106,
- "end": 23113
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 23117,
- "start": 23113,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 23122,
- "start": 23117,
- "tag_type": 2
- },
- {
- "start": 23122,
- "end": 23166
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 23170,
- "start": 23166,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/PC/PCs/-/707/915/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 23234,
- "start": 23170,
- "tag_type": 1
- },
- {
- "start": 23234,
- "end": 23237
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 23241,
- "start": 23237,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 23246,
- "start": 23241,
- "tag_type": 2
- },
- {
- "start": 23246,
- "end": 23290
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 23294,
- "start": 23290,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/PC/PCs/-/684/891/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 23358,
- "start": 23294,
- "tag_type": 1
- },
- {
- "start": 23358,
- "end": 23366
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 23370,
- "start": 23366,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 23375,
- "start": 23370,
- "tag_type": 2
- },
- {
- "start": 23375,
- "end": 23419
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 23423,
- "start": 23419,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/PC/PCs/-/713/921/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 23487,
- "start": 23423,
- "tag_type": 1
- },
- {
- "start": 23487,
- "end": 23498
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 23502,
- "start": 23498,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 23507,
- "start": 23502,
- "tag_type": 2
- },
- {
- "start": 23507,
- "end": 23551
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 23555,
- "start": 23551,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/PC/PCs/-/667/874/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 23619,
- "start": 23555,
- "tag_type": 1
- },
- {
- "start": 23619,
- "end": 23629
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 23633,
- "start": 23629,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 23638,
- "start": 23633,
- "tag_type": 2
- },
- {
- "start": 23638,
- "end": 23682
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 23686,
- "start": 23682,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/PC/PCs/-/2144/1411/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 23752,
- "start": 23686,
- "tag_type": 1
- },
- {
- "start": 23752,
- "end": 23773
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 23777,
- "start": 23773,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 23782,
- "start": 23777,
- "tag_type": 2
- },
- {
- "start": 23782,
- "end": 23826
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 23830,
- "start": 23826,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/PC/PCs/-/660/867/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 23894,
- "start": 23830,
- "tag_type": 1
- },
- {
- "start": 23894,
- "end": 23904
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 23908,
- "start": 23904,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 23913,
- "start": 23908,
- "tag_type": 2
- },
- {
- "start": 23913,
- "end": 23957
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 23961,
- "start": 23957,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/PC/PCs/-/2159/1426/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 24027,
- "start": 23961,
- "tag_type": 1
- },
- {
- "start": 24027,
- "end": 24033
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 24037,
- "start": 24033,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 24042,
- "start": 24037,
- "tag_type": 2
- },
- {
- "start": 24042,
- "end": 24086
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 24090,
- "start": 24086,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/PC/PCs/-/677/884/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 24154,
- "start": 24090,
- "tag_type": 1
- },
- {
- "start": 24154,
- "end": 24162
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 24166,
- "start": 24162,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 24171,
- "start": 24166,
- "tag_type": 2
- },
- {
- "start": 24171,
- "end": 24215
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 24219,
- "start": 24215,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/PC/PCs/6-/Campaign.html?campaign=4661&cid=4083104"
- },
- "tag": "a",
- "end": 24280,
- "start": 24219,
- "tag_type": 1
- },
- {
- "start": 24280,
- "end": 24298
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 24302,
- "start": 24298,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 24307,
- "start": 24302,
- "tag_type": 2
- },
- {
- "start": 24307,
- "end": 24351
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 24355,
- "start": 24351,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/PC/PCs/-/989/1237/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 24420,
- "start": 24355,
- "tag_type": 1
- },
- {
- "start": 24420,
- "end": 24431
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 24435,
- "start": 24431,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 24440,
- "start": 24435,
- "tag_type": 2
- },
- {
- "start": 24440,
- "end": 24484
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 24488,
- "start": 24484,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/PC/PCs/-/694/901/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 24552,
- "start": 24488,
- "tag_type": 1
- },
- {
- "start": 24552,
- "end": 24563
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 24567,
- "start": 24563,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 24572,
- "start": 24567,
- "tag_type": 2
- },
- {
- "start": 24572,
- "end": 24616
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 24621,
- "start": 24616,
- "tag_type": 2
- },
- {
- "start": 24621,
- "end": 24649
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 24654,
- "start": 24649,
- "tag_type": 2
- },
- {
- "start": 24654,
- "end": 24666
- },
- {
- "attributes": {
- "id": "nav_gadg"
- },
- "tag": "li",
- "end": 24684,
- "start": 24666,
- "tag_type": 1
- },
- {
- "start": 24684,
- "end": 24696
- },
- {
- "attributes": {
- "href": "/Gadgets/Gadgets/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 24742,
- "start": 24696,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 24748,
- "start": 24742,
- "tag_type": 1
- },
- {
- "start": 24748,
- "end": 24755
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 24762,
- "start": 24755,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 24766,
- "start": 24762,
- "tag_type": 2
- },
- {
- "start": 24766,
- "end": 24806
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 24810,
- "start": 24806,
- "tag_type": 1
- },
- {
- "start": 24810,
- "end": 24854
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 24858,
- "start": 24854,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Gadgets/Gadgets/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 24904,
- "start": 24858,
- "tag_type": 1
- },
- {
- "start": 24904,
- "end": 24908
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 24912,
- "start": 24908,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 24917,
- "start": 24912,
- "tag_type": 2
- },
- {
- "start": 24917,
- "end": 24961
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 24965,
- "start": 24961,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Gadgets/Gadgets/-/392/492/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 25038,
- "start": 24965,
- "tag_type": 1
- },
- {
- "start": 25038,
- "end": 25054
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 25058,
- "start": 25054,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 25063,
- "start": 25058,
- "tag_type": 2
- },
- {
- "start": 25063,
- "end": 25107
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 25111,
- "start": 25107,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Gadgets/Gadgets/-/558/743/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 25184,
- "start": 25111,
- "tag_type": 1
- },
- {
- "start": 25184,
- "end": 25191
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 25195,
- "start": 25191,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 25200,
- "start": 25195,
- "tag_type": 2
- },
- {
- "start": 25200,
- "end": 25244
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 25248,
- "start": 25244,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Gadgets/Gadgets/-/434/534/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 25321,
- "start": 25248,
- "tag_type": 1
- },
- {
- "start": 25321,
- "end": 25342
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 25346,
- "start": 25342,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 25351,
- "start": 25346,
- "tag_type": 2
- },
- {
- "start": 25351,
- "end": 25395
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 25399,
- "start": 25395,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Gadgets/Gadgets/-/382/482/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 25472,
- "start": 25399,
- "tag_type": 1
- },
- {
- "start": 25472,
- "end": 25482
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 25486,
- "start": 25482,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 25491,
- "start": 25486,
- "tag_type": 2
- },
- {
- "start": 25491,
- "end": 25535
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 25539,
- "start": 25535,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Gadgets/Gadgets/-/372/472/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 25612,
- "start": 25539,
- "tag_type": 1
- },
- {
- "start": 25612,
- "end": 25625
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 25629,
- "start": 25625,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 25634,
- "start": 25629,
- "tag_type": 2
- },
- {
- "start": 25634,
- "end": 25678
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 25682,
- "start": 25678,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Gadgets/Gadgets/-/440/540/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 25755,
- "start": 25682,
- "tag_type": 1
- },
- {
- "start": 25755,
- "end": 25766
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 25770,
- "start": 25766,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 25775,
- "start": 25770,
- "tag_type": 2
- },
- {
- "start": 25775,
- "end": 25819
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 25823,
- "start": 25819,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Gadgets/Gadgets/-/415/515/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 25896,
- "start": 25823,
- "tag_type": 1
- },
- {
- "start": 25896,
- "end": 25909
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 25913,
- "start": 25909,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 25918,
- "start": 25913,
- "tag_type": 2
- },
- {
- "start": 25918,
- "end": 25962
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 25966,
- "start": 25962,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Gadgets/Gadgets/-/411/511/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 26039,
- "start": 25966,
- "tag_type": 1
- },
- {
- "start": 26039,
- "end": 26055
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 26059,
- "start": 26055,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 26064,
- "start": 26059,
- "tag_type": 2
- },
- {
- "start": 26064,
- "end": 26108
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 26112,
- "start": 26108,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Gadgets/Gadgets/-/401/501/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 26185,
- "start": 26112,
- "tag_type": 1
- },
- {
- "start": 26185,
- "end": 26190
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 26194,
- "start": 26190,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 26199,
- "start": 26194,
- "tag_type": 2
- },
- {
- "start": 26199,
- "end": 26243
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 26247,
- "start": 26243,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Gadgets/Gadgets/-/426/526/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 26320,
- "start": 26247,
- "tag_type": 1
- },
- {
- "start": 26320,
- "end": 26324
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 26328,
- "start": 26324,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 26333,
- "start": 26328,
- "tag_type": 2
- },
- {
- "start": 26333,
- "end": 26377
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 26382,
- "start": 26377,
- "tag_type": 2
- },
- {
- "start": 26382,
- "end": 26410
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 26415,
- "start": 26410,
- "tag_type": 2
- },
- {
- "start": 26415,
- "end": 26427
- },
- {
- "attributes": {
- "id": "nav_mbls"
- },
- "tag": "li",
- "end": 26445,
- "start": 26427,
- "tag_type": 1
- },
- {
- "start": 26445,
- "end": 26457
- },
- {
- "attributes": {
- "href": "/Mobiles/Mobile/6-/MobileHome.html"
- },
- "tag": "a",
- "end": 26502,
- "start": 26457,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 26508,
- "start": 26502,
- "tag_type": 1
- },
- {
- "start": 26508,
- "end": 26514
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 26521,
- "start": 26514,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 26525,
- "start": 26521,
- "tag_type": 2
- },
- {
- "start": 26525,
- "end": 26565
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 26569,
- "start": 26565,
- "tag_type": 1
- },
- {
- "start": 26569,
- "end": 26613
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 26617,
- "start": 26613,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Mobiles/Mobile/6-/MobileHome.html"
- },
- "tag": "a",
- "end": 26662,
- "start": 26617,
- "tag_type": 1
- },
- {
- "start": 26662,
- "end": 26666
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 26670,
- "start": 26666,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 26675,
- "start": 26670,
- "tag_type": 2
- },
- {
- "start": 26675,
- "end": 26719
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 26723,
- "start": 26719,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Mobiles/Mobile/-/529/686/3-/HardwareHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 26797,
- "start": 26723,
- "tag_type": 1
- },
- {
- "start": 26797,
- "end": 26811
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 26815,
- "start": 26811,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 26820,
- "start": 26815,
- "tag_type": 2
- },
- {
- "start": 26820,
- "end": 26864
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 26868,
- "start": 26864,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Mobiles/Mobile/-/530/687/3-/HardwareHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 26942,
- "start": 26868,
- "tag_type": 1
- },
- {
- "start": 26942,
- "end": 26957
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 26961,
- "start": 26957,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 26966,
- "start": 26961,
- "tag_type": 2
- },
- {
- "start": 26966,
- "end": 27010
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 27014,
- "start": 27010,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Mobiles/Mobile/-/1020/1265/3-/HardwareBrowse.html?searchtype=genre"
- },
- "tag": "a",
- "end": 27092,
- "start": 27014,
- "tag_type": 1
- },
- {
- "start": 27092,
- "end": 27102
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 27106,
- "start": 27102,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 27111,
- "start": 27106,
- "tag_type": 2
- },
- {
- "start": 27111,
- "end": 27155
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 27159,
- "start": 27155,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Mobiles/Mobile/-/531/688/3-/HardwareHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 27233,
- "start": 27159,
- "tag_type": 1
- },
- {
- "start": 27233,
- "end": 27244
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 27248,
- "start": 27244,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 27253,
- "start": 27248,
- "tag_type": 2
- },
- {
- "start": 27253,
- "end": 27297
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 27301,
- "start": 27297,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Mobiles/Mobile/-/526/683/3-/MobileContent.html?searchtype=genre"
- },
- "tag": "a",
- "end": 27376,
- "start": 27301,
- "tag_type": 1
- },
- {
- "start": 27376,
- "end": 27390
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 27394,
- "start": 27390,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 27399,
- "start": 27394,
- "tag_type": 2
- },
- {
- "start": 27399,
- "end": 27443
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 27448,
- "start": 27443,
- "tag_type": 2
- },
- {
- "start": 27448,
- "end": 27476
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 27481,
- "start": 27476,
- "tag_type": 2
- },
- {
- "start": 27481,
- "end": 27493
- },
- {
- "attributes": {
- "id": "Li2"
- },
- "tag": "li",
- "end": 27506,
- "start": 27493,
- "tag_type": 1
- },
- {
- "start": 27506,
- "end": 27518
- },
- {
- "attributes": {
- "href": "/HOME/HOME/6-/LandingPage.html?page=playtrade"
- },
- "tag": "a",
- "end": 27574,
- "start": 27518,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 27580,
- "start": 27574,
- "tag_type": 1
- },
- {
- "start": 27580,
- "end": 27595
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 27602,
- "start": 27595,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 27606,
- "start": 27602,
- "tag_type": 2
- },
- {
- "start": 27606,
- "end": 27646
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 27650,
- "start": 27646,
- "tag_type": 1
- },
- {
- "start": 27650,
- "end": 27694
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 27698,
- "start": 27694,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/landingpage.aspx?page=playtrade&dpr=0&dpr=0&dpr=0&product=dvd"
- },
- "tag": "a",
- "end": 27771,
- "start": 27698,
- "tag_type": 1
- },
- {
- "start": 27771,
- "end": 27785
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 27789,
- "start": 27785,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 27794,
- "start": 27789,
- "tag_type": 2
- },
- {
- "start": 27794,
- "end": 27838
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 27842,
- "start": 27838,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/landingpage.aspx?page=playtrade&dpr=0&dpr=0&dpr=0&product=cd"
- },
- "tag": "a",
- "end": 27914,
- "start": 27842,
- "tag_type": 1
- },
- {
- "start": 27914,
- "end": 27927
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 27931,
- "start": 27927,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 27936,
- "start": 27931,
- "tag_type": 2
- },
- {
- "start": 27936,
- "end": 27980
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 27984,
- "start": 27980,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/landingpage.aspx?page=playtrade&dpr=0&dpr=0&dpr=0&product=game"
- },
- "tag": "a",
- "end": 28058,
- "start": 27984,
- "tag_type": 1
- },
- {
- "start": 28058,
- "end": 28073
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 28077,
- "start": 28073,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 28082,
- "start": 28077,
- "tag_type": 2
- },
- {
- "start": 28082,
- "end": 28126
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 28130,
- "start": 28126,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/landingpage.aspx?page=playtrade&dpr=0&dpr=0&dpr=0&product=book"
- },
- "tag": "a",
- "end": 28204,
- "start": 28130,
- "tag_type": 1
- },
- {
- "start": 28204,
- "end": 28219
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 28223,
- "start": 28219,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 28228,
- "start": 28223,
- "tag_type": 2
- },
- {
- "start": 28228,
- "end": 28272
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 28276,
- "start": 28272,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/landingpage.aspx?page=playtrade&dpr=0&dpr=0&dpr=0&product=ticket"
- },
- "tag": "a",
- "end": 28352,
- "start": 28276,
- "tag_type": 1
- },
- {
- "start": 28352,
- "end": 28369
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 28373,
- "start": 28369,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 28378,
- "start": 28373,
- "tag_type": 2
- },
- {
- "start": 28378,
- "end": 28422
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 28426,
- "start": 28422,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/landingpage.aspx?page=playtrade&dpr=0&dpr=0&dpr=0&product=console"
- },
- "tag": "a",
- "end": 28503,
- "start": 28426,
- "tag_type": 1
- },
- {
- "start": 28503,
- "end": 28521
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 28525,
- "start": 28521,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 28530,
- "start": 28525,
- "tag_type": 2
- },
- {
- "start": 28530,
- "end": 28574
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 28579,
- "start": 28574,
- "tag_type": 2
- },
- {
- "start": 28579,
- "end": 28607
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 28612,
- "start": 28607,
- "tag_type": 2
- },
- {
- "start": 28612,
- "end": 28628
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 28633,
- "start": 28628,
- "tag_type": 2
- },
- {
- "start": 28633,
- "end": 28642
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 28648,
- "start": 28642,
- "tag_type": 2
- },
- {
- "start": 28648,
- "end": 28652
- },
- {
- "attributes": {
- "id": "nav_submenu_contain"
- },
- "tag": "div",
- "end": 28682,
- "start": 28652,
- "tag_type": 1
- },
- {
- "start": 28682,
- "end": 28698
- },
- {
- "attributes": {
- "id": "nav_submenu"
- },
- "tag": "ul",
- "end": 28719,
- "start": 28698,
- "tag_type": 1
- },
- {
- "start": 28719,
- "end": 28739
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 28743,
- "start": 28739,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 28797,
- "start": 28743,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 28803,
- "start": 28797,
- "tag_type": 1
- },
- {
- "start": 28803,
- "end": 28807
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 28814,
- "start": 28807,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 28818,
- "start": 28814,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 28823,
- "start": 28818,
- "tag_type": 2
- },
- {
- "start": 28823,
- "end": 28843
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 28847,
- "start": 28843,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/3-/RegionHome.html?searchtype=genre",
- "class": "this"
- },
- "tag": "a",
- "end": 28941,
- "start": 28847,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 28947,
- "start": 28941,
- "tag_type": 1
- },
- {
- "start": 28947,
- "end": 28958
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 28965,
- "start": 28958,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 28969,
- "start": 28965,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 28974,
- "start": 28969,
- "tag_type": 2
- },
- {
- "start": 28974,
- "end": 28994
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 28998,
- "start": 28994,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/291/375/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 29079,
- "start": 28998,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 29085,
- "start": 29079,
- "tag_type": 1
- },
- {
- "start": 29085,
- "end": 29104
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 29111,
- "start": 29104,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 29115,
- "start": 29111,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 29120,
- "start": 29115,
- "tag_type": 2
- },
- {
- "start": 29120,
- "end": 29140
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 29144,
- "start": 29140,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/2168/1435/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 29227,
- "start": 29144,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 29233,
- "start": 29227,
- "tag_type": 1
- },
- {
- "start": 29233,
- "end": 29241
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 29248,
- "start": 29241,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 29252,
- "start": 29248,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 29257,
- "start": 29252,
- "tag_type": 2
- },
- {
- "start": 29257,
- "end": 29277
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 29281,
- "start": 29277,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/261/341/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 29362,
- "start": 29281,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 29368,
- "start": 29362,
- "tag_type": 1
- },
- {
- "start": 29368,
- "end": 29389
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 29396,
- "start": 29389,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 29400,
- "start": 29396,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 29405,
- "start": 29400,
- "tag_type": 2
- },
- {
- "start": 29405,
- "end": 29425
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 29429,
- "start": 29425,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/256/336/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 29510,
- "start": 29429,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 29516,
- "start": 29510,
- "tag_type": 1
- },
- {
- "start": 29516,
- "end": 29531
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 29538,
- "start": 29531,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 29542,
- "start": 29538,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 29547,
- "start": 29542,
- "tag_type": 2
- },
- {
- "start": 29547,
- "end": 29567
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 29571,
- "start": 29567,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/281/363/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 29652,
- "start": 29571,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 29658,
- "start": 29652,
- "tag_type": 1
- },
- {
- "start": 29658,
- "end": 29669
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 29676,
- "start": 29669,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 29680,
- "start": 29676,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 29685,
- "start": 29680,
- "tag_type": 2
- },
- {
- "start": 29685,
- "end": 29705
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 29709,
- "start": 29705,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/267/347/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 29790,
- "start": 29709,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 29796,
- "start": 29790,
- "tag_type": 1
- },
- {
- "start": 29796,
- "end": 29808
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 29815,
- "start": 29808,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 29819,
- "start": 29815,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 29824,
- "start": 29819,
- "tag_type": 2
- },
- {
- "start": 29824,
- "end": 29844
- },
- {
- "attributes": {
- "class": "endlink"
- },
- "tag": "li",
- "end": 29864,
- "start": 29844,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/271/351/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 29945,
- "start": 29864,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 29951,
- "start": 29945,
- "tag_type": 1
- },
- {
- "start": 29951,
- "end": 29961
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 29968,
- "start": 29961,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 29972,
- "start": 29968,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 29977,
- "start": 29972,
- "tag_type": 2
- },
- {
- "start": 29977,
- "end": 29997
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 30002,
- "start": 29997,
- "tag_type": 2
- },
- {
- "start": 30002,
- "end": 30010
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 30016,
- "start": 30010,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "cite",
- "end": 30022,
- "start": 30016,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "cite",
- "end": 30029,
- "start": 30022,
- "tag_type": 2
- },
- {
- "start": 30029,
- "end": 30033
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 30039,
- "start": 30033,
- "tag_type": 2
- },
- {
- "start": 30039,
- "end": 30043
- },
- {
- "attributes": {
- "type": "text/javascript",
- "language": "JavaScript"
- },
- "tag": "script",
- "end": 30096,
- "start": 30043,
- "tag_type": 1
- },
- {
- "start": 30096,
- "end": 30606
- },
- {
- "attributes": {},
- "tag": "script",
- "end": 30615,
- "start": 30606,
- "tag_type": 2
- },
- {
- "start": 30615,
- "end": 30619
- },
- {
- "attributes": {
- "id": "contentContainer"
- },
- "tag": "div",
- "end": 30646,
- "start": 30619,
- "tag_type": 1
- },
- {
- "start": 30646,
- "end": 30654
- },
- {
- "attributes": {
- "class": "outer"
- },
- "tag": "div",
- "end": 30673,
- "start": 30654,
- "tag_type": 1
- },
- {
- "start": 30673,
- "end": 30685
- },
- {
- "attributes": {
- "class": "inner"
- },
- "tag": "div",
- "end": 30704,
- "start": 30685,
- "tag_type": 1
- },
- {
- "start": 30704,
- "end": 30720
- },
- {
- "attributes": {
- "class": "floatWrap"
- },
- "tag": "div",
- "end": 30743,
- "start": 30720,
- "tag_type": 1
- },
- {
- "start": 30743,
- "end": 30763
- },
- {
- "attributes": {
- "id": "middleCol"
- },
- "tag": "div",
- "end": 30783,
- "start": 30763,
- "tag_type": 1
- },
- {
- "start": 30783,
- "end": 30831
- },
- {
- "attributes": {
- "class": "content"
- },
- "tag": "div",
- "end": 30852,
- "start": 30831,
- "tag_type": 1
- },
- {
- "start": 30852,
- "end": 30884
- },
- {
- "attributes": {
- "class": "electronics wrap"
- },
- "tag": "div",
- "end": 30914,
- "start": 30884,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "boxhead"
- },
- "tag": "div",
- "end": 30935,
- "start": 30914,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 30940,
- "start": 30935,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 30945,
- "start": 30940,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "pagehead"
- },
- "tag": "h2",
- "end": 30966,
- "start": 30945,
- "tag_type": 1
- },
- {
- "start": 30966,
- "end": 30977
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 30982,
- "start": 30977,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 30988,
- "start": 30982,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 30994,
- "start": 30988,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 31000,
- "start": 30994,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "box"
- },
- "tag": "div",
- "end": 31017,
- "start": 31000,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "product-2 slice top"
- },
- "tag": "div",
- "end": 31050,
- "start": 31017,
- "tag_type": 1
- },
- {
- "attributes": {
- "cellspacing": "0"
- },
- "tag": "table",
- "end": 31073,
- "start": 31050,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 31077,
- "start": 31073,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 31081,
- "start": 31077,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "image"
- },
- "tag": "div",
- "end": 31100,
- "start": 31081,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 31103,
- "start": 31100,
- "tag_type": 1
- },
- {
- "attributes": {
- "onerror": null,
- "src": "http://images.play.com/covers/8986420m.jpg",
- "alt": "Samsung Series 5 550 37" LE37B550 / HD 1080p / Freeview / LCD TV (Black)",
- "style": "border-width:0px;height:170px;width:170px;"
- },
- "tag": "img",
- "end": 31369,
- "start": 31103,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 31373,
- "start": 31369,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 31379,
- "start": 31373,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "action"
- },
- "tag": "div",
- "end": 31399,
- "start": 31379,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 31405,
- "start": 31399,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "action"
- },
- "tag": "div",
- "end": 31425,
- "start": 31405,
- "tag_type": 1
- },
- {
- "start": 31425,
- "end": 31429
- },
- {
- "attributes": {
- "href": "#",
- "onclick": "javascript:window.open('/Electronics/Electronics/4-/8986420/-/EnlargedImage.html','8986420','width=520,height=520')"
- },
- "tag": "a",
- "end": 31567,
- "start": 31429,
- "tag_type": 1
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteCSS/Play/Live1/img/button/enlargeimage.gif",
- "alt": "Enlarge Image",
- "style": "border-width:0px;height:17px;width:99px;"
- },
- "tag": "img",
- "end": 31719,
- "start": 31567,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 31723,
- "start": 31719,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 31729,
- "start": 31723,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 31734,
- "start": 31729,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "wide"
- },
- "tag": "td",
- "end": 31751,
- "start": 31734,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "info"
- },
- "tag": "div",
- "end": 31769,
- "start": 31751,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 31774,
- "start": 31769,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "h1",
- "end": 31778,
- "start": 31774,
- "tag_type": 1
- },
- {
- "start": 31778,
- "end": 31850
- },
- {
- "attributes": {},
- "tag": "h1",
- "end": 31855,
- "start": 31850,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "artist"
- },
- "tag": "p",
- "end": 31873,
- "start": 31855,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 31877,
- "start": 31873,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "rating"
- },
- "tag": "p",
- "end": 31893,
- "start": 31877,
- "tag_type": 1
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteCSS/Play/Live1/img/spaces/stars50.gif",
- "alt": "Customer rating on Samsung Series 5 550 37" LE37B550 / HD 1080p / Freeview / LCD TV (Black): 5 out of 5 stars",
- "style": "height:14px;width:71px;border-width:0px;"
- },
- "tag": "img",
- "end": 32141,
- "start": 31893,
- "tag_type": 3
- },
- {
- "start": 32141,
- "end": 32144
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/8986420/Samsung-Series-5-550-37-LE37B550-HD-1080p-Freeview-LCD-TV/ProductReviews.html",
- "title": "See all Samsung Series 5 550 37" LE37B550 / HD 1080p / Freeview / LCD TV (Black) reviews"
- },
- "tag": "a",
- "end": 32370,
- "start": 32144,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 32378,
- "start": 32370,
- "tag_type": 1
- },
- {
- "start": 32378,
- "end": 32379
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 32388,
- "start": 32379,
- "tag_type": 2
- },
- {
- "start": 32388,
- "end": 32404
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 32408,
- "start": 32404,
- "tag_type": 2
- },
- {
- "start": 32408,
- "end": 32411
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 32415,
- "start": 32411,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 32421,
- "start": 32415,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 32426,
- "start": 32421,
- "tag_type": 1
- },
- {
- "attributes": {
- "id": "_pageTemplate__product_ctl00__overview_ctl00__dataControl__price__headerSix"
- },
- "tag": "h6",
- "end": 32511,
- "start": 32426,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 32517,
- "start": 32511,
- "tag_type": 1
- },
- {
- "start": 32517,
- "end": 32529
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 32536,
- "start": 32529,
- "tag_type": 2
- },
- {
- "start": 32536,
- "end": 32550
- },
- {
- "attributes": {},
- "tag": "h6",
- "end": 32555,
- "start": 32550,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "saving"
- },
- "tag": "p",
- "end": 32573,
- "start": 32555,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 32579,
- "start": 32573,
- "tag_type": 1
- },
- {
- "start": 32579,
- "end": 32584
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 32592,
- "start": 32584,
- "tag_type": 1
- },
- {
- "start": 32592,
- "end": 32604
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 32613,
- "start": 32604,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 32620,
- "start": 32613,
- "tag_type": 2
- },
- {
- "start": 32620,
- "end": 32623
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 32629,
- "start": 32623,
- "tag_type": 1
- },
- {
- "start": 32629,
- "end": 32639
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 32647,
- "start": 32639,
- "tag_type": 1
- },
- {
- "start": 32647,
- "end": 32665
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 32674,
- "start": 32665,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 32681,
- "start": 32674,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 32685,
- "start": 32681,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "stock"
- },
- "tag": "p",
- "end": 32702,
- "start": 32685,
- "tag_type": 1
- },
- {
- "start": 32702,
- "end": 32706
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 32714,
- "start": 32706,
- "tag_type": 1
- },
- {
- "start": 32714,
- "end": 32722
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 32731,
- "start": 32722,
- "tag_type": 2
- },
- {
- "start": 32731,
- "end": 32735
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 32741,
- "start": 32735,
- "tag_type": 1
- },
- {
- "start": 32741,
- "end": 32778
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 32785,
- "start": 32778,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 32789,
- "start": 32785,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 32795,
- "start": 32789,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "buy"
- },
- "tag": "div",
- "end": 32812,
- "start": 32795,
- "tag_type": 1
- },
- {
- "start": 32812,
- "end": 32833
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/-/8986420/Samsung-Series-5-550-37-LE37B550-HD-1080p-Freeview-LCD-TV/Product.html?searchtype=genre&add=8986420&pid=275282&dpr=275282",
- "class": "buy_button"
- },
- "tag": "a",
- "end": 33037,
- "start": 32833,
- "tag_type": 1
- },
- {
- "start": 33037,
- "end": 33040
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 33044,
- "start": 33040,
- "tag_type": 2
- },
- {
- "start": 33044,
- "end": 33064
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 33070,
- "start": 33064,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "badges"
- },
- "tag": "div",
- "end": 33090,
- "start": 33070,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 33095,
- "start": 33090,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 33101,
- "start": 33095,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 33107,
- "start": 33101,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "note-alt"
- },
- "tag": "p",
- "end": 33127,
- "start": 33107,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 33131,
- "start": 33127,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "bogof"
- },
- "tag": "div",
- "end": 33150,
- "start": 33131,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 33156,
- "start": 33150,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 33162,
- "start": 33156,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 33167,
- "start": 33162,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 33172,
- "start": 33167,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "table",
- "end": 33180,
- "start": 33172,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "trade-link-wrap"
- },
- "tag": "div",
- "end": 33209,
- "start": 33180,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "trade-link"
- },
- "tag": "div",
- "end": 33233,
- "start": 33209,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 33238,
- "start": 33233,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "table",
- "end": 33245,
- "start": 33238,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 33249,
- "start": 33245,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "wide"
- },
- "tag": "td",
- "end": 33266,
- "start": 33249,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 33269,
- "start": 33266,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/8986420/Samsung-Series-5-550-37-LE37B550-HD-1080p-Freeview-LCD-TV/Product.html?ptsl=1&ob=Price&fb=0"
- },
- "tag": "a",
- "end": 33407,
- "start": 33269,
- "tag_type": 1
- },
- {
- "start": 33407,
- "end": 33431
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 33437,
- "start": 33431,
- "tag_type": 1
- },
- {
- "start": 33437,
- "end": 33451
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 33458,
- "start": 33451,
- "tag_type": 2
- },
- {
- "start": 33458,
- "end": 33464
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 33472,
- "start": 33464,
- "tag_type": 1
- },
- {
- "start": 33472,
- "end": 33484
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 33493,
- "start": 33484,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 33497,
- "start": 33493,
- "tag_type": 2
- },
- {
- "attributes": {
- "href": "/HOME/HOME/6-/Help.html?page=TradeGeneralq",
- "class": "huh"
- },
- "tag": "a",
- "end": 33562,
- "start": 33497,
- "tag_type": 1
- },
- {
- "start": 33562,
- "end": 33583
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 33587,
- "start": 33583,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 33591,
- "start": 33587,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 33595,
- "start": 33591,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 33599,
- "start": 33595,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/8986420/Samsung-Series-5-550-37-LE37B550-HD-1080p-Freeview-LCD-TV/Product.html?ptsl=1&ob=Price&fb=1"
- },
- "tag": "a",
- "end": 33737,
- "start": 33599,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 33743,
- "start": 33737,
- "tag_type": 1
- },
- {
- "start": 33743,
- "end": 33748
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 33755,
- "start": 33748,
- "tag_type": 2
- },
- {
- "start": 33755,
- "end": 33761
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 33769,
- "start": 33761,
- "tag_type": 1
- },
- {
- "start": 33769,
- "end": 33778
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 33787,
- "start": 33778,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 33791,
- "start": 33787,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 33796,
- "start": 33791,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 33801,
- "start": 33796,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "more"
- },
- "tag": "div",
- "end": 33819,
- "start": 33801,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 33825,
- "start": 33819,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 33830,
- "start": 33825,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 33835,
- "start": 33830,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "table",
- "end": 33843,
- "start": 33835,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 33849,
- "start": 33843,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 33855,
- "start": 33849,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 33861,
- "start": 33855,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 33867,
- "start": 33861,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "linksave"
- },
- "tag": "div",
- "end": 33889,
- "start": 33867,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 33894,
- "start": 33889,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 33899,
- "start": 33894,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 33904,
- "start": 33899,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "title"
- },
- "tag": "div",
- "end": 33923,
- "start": 33904,
- "tag_type": 1
- },
- {
- "attributes": {
- "cellspacing": "0"
- },
- "tag": "table",
- "end": 33946,
- "start": 33923,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 33950,
- "start": 33946,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 33954,
- "start": 33950,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 33959,
- "start": 33954,
- "tag_type": 1
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteCSS/Play/Live1/img/brand/promo_plus.gif",
- "style": "border-width:0px;"
- },
- "tag": "img",
- "end": 34065,
- "start": 33959,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 34071,
- "start": 34065,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 34076,
- "start": 34071,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "wide"
- },
- "tag": "td",
- "end": 34093,
- "start": 34076,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "h1",
- "end": 34097,
- "start": 34093,
- "tag_type": 1
- },
- {
- "start": 34097,
- "end": 34116
- },
- {
- "attributes": {},
- "tag": "h1",
- "end": 34121,
- "start": 34116,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 34124,
- "start": 34121,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 34132,
- "start": 34124,
- "tag_type": 1
- },
- {
- "start": 34132,
- "end": 34185
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 34194,
- "start": 34185,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 34198,
- "start": 34194,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 34203,
- "start": 34198,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 34207,
- "start": 34203,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "button"
- },
- "tag": "div",
- "end": 34227,
- "start": 34207,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 34232,
- "start": 34227,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 34237,
- "start": 34232,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 34240,
- "start": 34237,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/8986420/-/Product.html?sp=1&dpr=275282",
- "title": "Save 50% On This TV Stand When Purchased With This TV"
- },
- "tag": "a",
- "end": 34383,
- "start": 34240,
- "tag_type": 1
- },
- {
- "start": 34383,
- "end": 34393
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 34397,
- "start": 34393,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 34401,
- "start": 34397,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 34407,
- "start": 34401,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 34413,
- "start": 34407,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 34419,
- "start": 34413,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 34424,
- "start": 34419,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 34429,
- "start": 34424,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "table",
- "end": 34437,
- "start": 34429,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 34443,
- "start": 34437,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 34449,
- "start": 34443,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 34455,
- "start": 34449,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 34461,
- "start": 34455,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "linknote"
- },
- "tag": "p",
- "end": 34481,
- "start": 34461,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 34485,
- "start": 34481,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 34491,
- "start": 34485,
- "tag_type": 2
- },
- {
- "start": 34491,
- "end": 34495
- },
- {
- "attributes": {
- "class": "subhead"
- },
- "tag": "div",
- "end": 34516,
- "start": 34495,
- "tag_type": 1
- },
- {
- "start": 34516,
- "end": 34524
- },
- {
- "attributes": {},
- "tag": "h3",
- "end": 34529,
- "start": 34524,
- "tag_type": 1
- },
- {
- "attributes": {
- "cellpadding": "0",
- "cellspacing": "0"
- },
- "tag": "table",
- "end": 34568,
- "start": 34529,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 34575,
- "start": 34568,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 34579,
- "start": 34575,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "text"
- },
- "tag": "td",
- "end": 34596,
- "start": 34579,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 34602,
- "start": 34596,
- "tag_type": 1
- },
- {
- "start": 34602,
- "end": 34620
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 34627,
- "start": 34620,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 34632,
- "start": 34627,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "tabend"
- },
- "tag": "td",
- "end": 34653,
- "start": 34632,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 34658,
- "start": 34653,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 34666,
- "start": 34658,
- "tag_type": 2
- },
- {
- "start": 34666,
- "end": 34678
- },
- {
- "attributes": {},
- "tag": "table",
- "end": 34686,
- "start": 34678,
- "tag_type": 2
- },
- {
- "start": 34686,
- "end": 34694
- },
- {
- "attributes": {},
- "tag": "h3",
- "end": 34699,
- "start": 34694,
- "tag_type": 2
- },
- {
- "start": 34699,
- "end": 34715
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 34718,
- "start": 34715,
- "tag_type": 1
- },
- {
- "start": 34718,
- "end": 34730
- },
- {
- "attributes": {
- "href": "#"
- },
- "tag": "a",
- "end": 34742,
- "start": 34730,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 34746,
- "start": 34742,
- "tag_type": 2
- },
- {
- "start": 34746,
- "end": 34760
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 34764,
- "start": 34760,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 34770,
- "start": 34764,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "relatedpromos slice"
- },
- "tag": "div",
- "end": 34803,
- "start": 34770,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 34807,
- "start": 34803,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "textbig"
- },
- "tag": "li",
- "end": 34827,
- "start": 34807,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/3-/275282/2-/Promo.html"
- },
- "tag": "a",
- "end": 34886,
- "start": 34827,
- "tag_type": 1
- },
- {
- "start": 34886,
- "end": 34905
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 34909,
- "start": 34905,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 34914,
- "start": 34909,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 34919,
- "start": 34914,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 34925,
- "start": 34919,
- "tag_type": 2
- },
- {
- "start": 34925,
- "end": 34929
- },
- {
- "attributes": {
- "class": "subhead"
- },
- "tag": "div",
- "end": 34950,
- "start": 34929,
- "tag_type": 1
- },
- {
- "start": 34950,
- "end": 34958
- },
- {
- "attributes": {
- "id": "jump-features",
- "name": "jump-features"
- },
- "tag": "h3",
- "end": 34998,
- "start": 34958,
- "tag_type": 1
- },
- {
- "attributes": {
- "cellpadding": "0",
- "cellspacing": "0"
- },
- "tag": "table",
- "end": 35037,
- "start": 34998,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 35044,
- "start": 35037,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 35048,
- "start": 35044,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "text"
- },
- "tag": "td",
- "end": 35065,
- "start": 35048,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 35071,
- "start": 35065,
- "tag_type": 1
- },
- {
- "start": 35071,
- "end": 35085
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 35092,
- "start": 35085,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 35097,
- "start": 35092,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "tabend"
- },
- "tag": "td",
- "end": 35118,
- "start": 35097,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 35123,
- "start": 35118,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 35131,
- "start": 35123,
- "tag_type": 2
- },
- {
- "start": 35131,
- "end": 35143
- },
- {
- "attributes": {},
- "tag": "table",
- "end": 35151,
- "start": 35143,
- "tag_type": 2
- },
- {
- "start": 35151,
- "end": 35159
- },
- {
- "attributes": {},
- "tag": "h3",
- "end": 35164,
- "start": 35159,
- "tag_type": 2
- },
- {
- "start": 35164,
- "end": 35180
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 35183,
- "start": 35180,
- "tag_type": 1
- },
- {
- "start": 35183,
- "end": 35195
- },
- {
- "attributes": {
- "href": "#goto-top"
- },
- "tag": "a",
- "end": 35215,
- "start": 35195,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 35219,
- "start": 35215,
- "tag_type": 2
- },
- {
- "start": 35219,
- "end": 35233
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 35237,
- "start": 35233,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 35243,
- "start": 35237,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "special slice"
- },
- "tag": "div",
- "end": 35270,
- "start": 35243,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 35274,
- "start": 35270,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 35278,
- "start": 35274,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "center",
- "end": 35286,
- "start": 35278,
- "tag_type": 1
- },
- {
- "attributes": {
- "src": "http://images.play.com/banners/SAM550ban.jpg",
- "alt": "diagram"
- },
- "tag": "img",
- "end": 35358,
- "start": 35286,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "center",
- "end": 35367,
- "start": 35358,
- "tag_type": 2
- },
- {
- "start": 35367,
- "end": 35368
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 35373,
- "start": 35368,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 35377,
- "start": 35373,
- "tag_type": 1
- },
- {
- "start": 35377,
- "end": 35378
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 35386,
- "start": 35378,
- "tag_type": 1
- },
- {
- "start": 35386,
- "end": 35546
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 35555,
- "start": 35546,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 35560,
- "start": 35555,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 35564,
- "start": 35560,
- "tag_type": 1
- },
- {
- "start": 35564,
- "end": 35581
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 35586,
- "start": 35581,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 35590,
- "start": 35586,
- "tag_type": 1
- },
- {
- "start": 35590,
- "end": 35614
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 35619,
- "start": 35614,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 35623,
- "start": 35619,
- "tag_type": 1
- },
- {
- "start": 35623,
- "end": 35640
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 35645,
- "start": 35640,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 35649,
- "start": 35645,
- "tag_type": 1
- },
- {
- "start": 35649,
- "end": 35671
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 35676,
- "start": 35671,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 35680,
- "start": 35676,
- "tag_type": 1
- },
- {
- "start": 35680,
- "end": 35718
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 35723,
- "start": 35718,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 35727,
- "start": 35723,
- "tag_type": 1
- },
- {
- "start": 35727,
- "end": 35754
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 35759,
- "start": 35754,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 35763,
- "start": 35759,
- "tag_type": 1
- },
- {
- "start": 35763,
- "end": 35783
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 35788,
- "start": 35783,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 35792,
- "start": 35788,
- "tag_type": 1
- },
- {
- "start": 35792,
- "end": 35793
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 35801,
- "start": 35793,
- "tag_type": 1
- },
- {
- "start": 35801,
- "end": 35806
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 35815,
- "start": 35806,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 35820,
- "start": 35815,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 35824,
- "start": 35820,
- "tag_type": 1
- },
- {
- "start": 35824,
- "end": 35885
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 35890,
- "start": 35885,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 35894,
- "start": 35890,
- "tag_type": 1
- },
- {
- "start": 35894,
- "end": 35920
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 35925,
- "start": 35920,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 35929,
- "start": 35925,
- "tag_type": 1
- },
- {
- "start": 35929,
- "end": 35956
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 35961,
- "start": 35956,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 35965,
- "start": 35961,
- "tag_type": 1
- },
- {
- "start": 35965,
- "end": 35966
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 35974,
- "start": 35966,
- "tag_type": 1
- },
- {
- "start": 35974,
- "end": 35982
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 35991,
- "start": 35982,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 35996,
- "start": 35991,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36000,
- "start": 35996,
- "tag_type": 1
- },
- {
- "start": 36000,
- "end": 36008
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36013,
- "start": 36008,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36017,
- "start": 36013,
- "tag_type": 1
- },
- {
- "start": 36017,
- "end": 36032
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36037,
- "start": 36032,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36041,
- "start": 36037,
- "tag_type": 1
- },
- {
- "start": 36041,
- "end": 36060
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36065,
- "start": 36060,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36069,
- "start": 36065,
- "tag_type": 1
- },
- {
- "start": 36069,
- "end": 36079
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36084,
- "start": 36079,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36088,
- "start": 36084,
- "tag_type": 1
- },
- {
- "start": 36088,
- "end": 36103
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36108,
- "start": 36103,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36112,
- "start": 36108,
- "tag_type": 1
- },
- {
- "start": 36112,
- "end": 36125
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36130,
- "start": 36125,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36134,
- "start": 36130,
- "tag_type": 1
- },
- {
- "start": 36134,
- "end": 36146
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36151,
- "start": 36146,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36155,
- "start": 36151,
- "tag_type": 1
- },
- {
- "start": 36155,
- "end": 36176
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36181,
- "start": 36176,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36185,
- "start": 36181,
- "tag_type": 1
- },
- {
- "start": 36185,
- "end": 36205
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36210,
- "start": 36205,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36214,
- "start": 36210,
- "tag_type": 1
- },
- {
- "start": 36214,
- "end": 36229
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36234,
- "start": 36229,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36238,
- "start": 36234,
- "tag_type": 1
- },
- {
- "start": 36238,
- "end": 36242
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36247,
- "start": 36242,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36251,
- "start": 36247,
- "tag_type": 1
- },
- {
- "start": 36251,
- "end": 36272
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36277,
- "start": 36272,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36281,
- "start": 36277,
- "tag_type": 1
- },
- {
- "start": 36281,
- "end": 36297
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36302,
- "start": 36297,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36306,
- "start": 36302,
- "tag_type": 1
- },
- {
- "start": 36306,
- "end": 36307
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 36315,
- "start": 36307,
- "tag_type": 1
- },
- {
- "start": 36315,
- "end": 36321
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 36330,
- "start": 36321,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36335,
- "start": 36330,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36339,
- "start": 36335,
- "tag_type": 1
- },
- {
- "start": 36339,
- "end": 36348
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36353,
- "start": 36348,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36357,
- "start": 36353,
- "tag_type": 1
- },
- {
- "start": 36357,
- "end": 36376
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36381,
- "start": 36376,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36385,
- "start": 36381,
- "tag_type": 1
- },
- {
- "start": 36385,
- "end": 36386
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 36394,
- "start": 36386,
- "tag_type": 1
- },
- {
- "start": 36394,
- "end": 36410
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 36419,
- "start": 36410,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36424,
- "start": 36419,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36428,
- "start": 36424,
- "tag_type": 1
- },
- {
- "start": 36428,
- "end": 36446
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36451,
- "start": 36446,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36455,
- "start": 36451,
- "tag_type": 1
- },
- {
- "start": 36455,
- "end": 36465
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36470,
- "start": 36465,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36474,
- "start": 36470,
- "tag_type": 1
- },
- {
- "start": 36474,
- "end": 36488
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36493,
- "start": 36488,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36497,
- "start": 36493,
- "tag_type": 1
- },
- {
- "start": 36497,
- "end": 36517
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36522,
- "start": 36517,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36526,
- "start": 36522,
- "tag_type": 1
- },
- {
- "start": 36526,
- "end": 36540
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36545,
- "start": 36540,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36549,
- "start": 36545,
- "tag_type": 1
- },
- {
- "start": 36549,
- "end": 36572
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36577,
- "start": 36572,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36581,
- "start": 36577,
- "tag_type": 1
- },
- {
- "start": 36581,
- "end": 36614
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36619,
- "start": 36614,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36623,
- "start": 36619,
- "tag_type": 1
- },
- {
- "start": 36623,
- "end": 36657
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36662,
- "start": 36657,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36666,
- "start": 36662,
- "tag_type": 1
- },
- {
- "start": 36666,
- "end": 36691
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36696,
- "start": 36691,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36700,
- "start": 36696,
- "tag_type": 1
- },
- {
- "start": 36700,
- "end": 36730
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36735,
- "start": 36730,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36739,
- "start": 36735,
- "tag_type": 1
- },
- {
- "start": 36739,
- "end": 36755
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36760,
- "start": 36755,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36764,
- "start": 36760,
- "tag_type": 1
- },
- {
- "start": 36764,
- "end": 36779
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36784,
- "start": 36779,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36788,
- "start": 36784,
- "tag_type": 1
- },
- {
- "start": 36788,
- "end": 36809
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36814,
- "start": 36809,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36818,
- "start": 36814,
- "tag_type": 1
- },
- {
- "start": 36818,
- "end": 36831
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36836,
- "start": 36831,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36840,
- "start": 36836,
- "tag_type": 1
- },
- {
- "start": 36840,
- "end": 36852
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36857,
- "start": 36852,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36861,
- "start": 36857,
- "tag_type": 1
- },
- {
- "start": 36861,
- "end": 36862
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 36870,
- "start": 36862,
- "tag_type": 1
- },
- {
- "start": 36870,
- "end": 36876
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 36885,
- "start": 36876,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36890,
- "start": 36885,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36894,
- "start": 36890,
- "tag_type": 1
- },
- {
- "start": 36894,
- "end": 36919
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36924,
- "start": 36919,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36928,
- "start": 36924,
- "tag_type": 1
- },
- {
- "start": 36928,
- "end": 36951
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36956,
- "start": 36951,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36960,
- "start": 36956,
- "tag_type": 1
- },
- {
- "start": 36960,
- "end": 36980
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36985,
- "start": 36980,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 36989,
- "start": 36985,
- "tag_type": 1
- },
- {
- "start": 36989,
- "end": 36990
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 36998,
- "start": 36990,
- "tag_type": 1
- },
- {
- "start": 36998,
- "end": 37009
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 37018,
- "start": 37009,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37023,
- "start": 37018,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37027,
- "start": 37023,
- "tag_type": 1
- },
- {
- "start": 37027,
- "end": 37073
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37078,
- "start": 37073,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37082,
- "start": 37078,
- "tag_type": 1
- },
- {
- "start": 37082,
- "end": 37130
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37135,
- "start": 37130,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37139,
- "start": 37135,
- "tag_type": 1
- },
- {
- "start": 37139,
- "end": 37140
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 37148,
- "start": 37140,
- "tag_type": 1
- },
- {
- "start": 37148,
- "end": 37154
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 37163,
- "start": 37154,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37168,
- "start": 37163,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37172,
- "start": 37168,
- "tag_type": 1
- },
- {
- "start": 37172,
- "end": 37200
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37205,
- "start": 37200,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37209,
- "start": 37205,
- "tag_type": 1
- },
- {
- "start": 37209,
- "end": 37240
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37245,
- "start": 37240,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37249,
- "start": 37245,
- "tag_type": 1
- },
- {
- "start": 37249,
- "end": 37250
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 37258,
- "start": 37250,
- "tag_type": 1
- },
- {
- "start": 37258,
- "end": 37267
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 37276,
- "start": 37267,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37281,
- "start": 37276,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37285,
- "start": 37281,
- "tag_type": 1
- },
- {
- "start": 37285,
- "end": 37329
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37334,
- "start": 37329,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37338,
- "start": 37334,
- "tag_type": 1
- },
- {
- "start": 37338,
- "end": 37356
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37361,
- "start": 37356,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37365,
- "start": 37361,
- "tag_type": 1
- },
- {
- "start": 37365,
- "end": 37375
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37380,
- "start": 37375,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37384,
- "start": 37380,
- "tag_type": 1
- },
- {
- "start": 37384,
- "end": 37396
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 37401,
- "start": 37396,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 37406,
- "start": 37401,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 37412,
- "start": 37406,
- "tag_type": 2
- },
- {
- "start": 37412,
- "end": 37416
- },
- {
- "attributes": {
- "class": "subhead"
- },
- "tag": "div",
- "end": 37437,
- "start": 37416,
- "tag_type": 1
- },
- {
- "start": 37437,
- "end": 37445
- },
- {
- "attributes": {
- "id": "jump-review",
- "name": "jump-review"
- },
- "tag": "h3",
- "end": 37481,
- "start": 37445,
- "tag_type": 1
- },
- {
- "attributes": {
- "cellpadding": "0",
- "cellspacing": "0"
- },
- "tag": "table",
- "end": 37520,
- "start": 37481,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 37527,
- "start": 37520,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 37531,
- "start": 37527,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "text"
- },
- "tag": "td",
- "end": 37548,
- "start": 37531,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 37554,
- "start": 37548,
- "tag_type": 1
- },
- {
- "start": 37554,
- "end": 37565
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 37572,
- "start": 37565,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 37577,
- "start": 37572,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "tabend"
- },
- "tag": "td",
- "end": 37598,
- "start": 37577,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 37603,
- "start": 37598,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 37611,
- "start": 37603,
- "tag_type": 2
- },
- {
- "start": 37611,
- "end": 37623
- },
- {
- "attributes": {},
- "tag": "table",
- "end": 37631,
- "start": 37623,
- "tag_type": 2
- },
- {
- "start": 37631,
- "end": 37639
- },
- {
- "attributes": {},
- "tag": "h3",
- "end": 37644,
- "start": 37639,
- "tag_type": 2
- },
- {
- "start": 37644,
- "end": 37660
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 37663,
- "start": 37660,
- "tag_type": 1
- },
- {
- "start": 37663,
- "end": 37675
- },
- {
- "attributes": {
- "href": "#goto-top"
- },
- "tag": "a",
- "end": 37695,
- "start": 37675,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 37699,
- "start": 37695,
- "tag_type": 2
- },
- {
- "start": 37699,
- "end": 37713
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 37717,
- "start": 37713,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 37723,
- "start": 37717,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "review slice"
- },
- "tag": "div",
- "end": 37749,
- "start": 37723,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 37752,
- "start": 37749,
- "tag_type": 1
- },
- {
- "start": 37752,
- "end": 37889
- },
- {
- "attributes": {},
- "tag": "br",
- "end": 37894,
- "start": 37889,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "br",
- "end": 37899,
- "start": 37894,
- "tag_type": 3
- },
- {
- "attributes": {
- "src": "http://images.play.com/banners/SAM550a.jpg",
- "align": "left",
- "hspace": "5",
- "/": null
- },
- "tag": "img",
- "end": 37977,
- "start": 37899,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "br",
- "end": 37982,
- "start": 37977,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 37990,
- "start": 37982,
- "tag_type": 1
- },
- {
- "start": 37990,
- "end": 37998
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 38007,
- "start": 37998,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "br",
- "end": 38012,
- "start": 38007,
- "tag_type": 3
- },
- {
- "start": 38012,
- "end": 38283
- },
- {
- "attributes": {},
- "tag": "br",
- "end": 38288,
- "start": 38283,
- "tag_type": 3
- },
- {
- "attributes": {
- "clear": "ALL"
- },
- "tag": "br",
- "end": 38304,
- "start": 38288,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "br",
- "end": 38309,
- "start": 38304,
- "tag_type": 3
- },
- {
- "attributes": {
- "src": "http://images.play.com/banners/SAM550b.jpg",
- "align": "left",
- "hspace": "5",
- "/": null
- },
- "tag": "img",
- "end": 38387,
- "start": 38309,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "br",
- "end": 38392,
- "start": 38387,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 38400,
- "start": 38392,
- "tag_type": 1
- },
- {
- "start": 38400,
- "end": 38420
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 38429,
- "start": 38420,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "br",
- "end": 38434,
- "start": 38429,
- "tag_type": 3
- },
- {
- "start": 38434,
- "end": 38575
- },
- {
- "attributes": {},
- "tag": "br",
- "end": 38580,
- "start": 38575,
- "tag_type": 3
- },
- {
- "attributes": {
- "clear": "ALL"
- },
- "tag": "br",
- "end": 38596,
- "start": 38580,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "br",
- "end": 38601,
- "start": 38596,
- "tag_type": 3
- },
- {
- "attributes": {
- "src": "http://images.play.com/banners/SAM550c.jpg",
- "align": "left",
- "hspace": "5",
- "/": null
- },
- "tag": "img",
- "end": 38679,
- "start": 38601,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "br",
- "end": 38684,
- "start": 38679,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 38692,
- "start": 38684,
- "tag_type": 1
- },
- {
- "start": 38692,
- "end": 38710
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 38719,
- "start": 38710,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "br",
- "end": 38724,
- "start": 38719,
- "tag_type": 3
- },
- {
- "start": 38724,
- "end": 38909
- },
- {
- "attributes": {},
- "tag": "br",
- "end": 38914,
- "start": 38909,
- "tag_type": 3
- },
- {
- "attributes": {
- "clear": "ALL"
- },
- "tag": "br",
- "end": 38930,
- "start": 38914,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "br",
- "end": 38935,
- "start": 38930,
- "tag_type": 3
- },
- {
- "attributes": {
- "src": "http://images.play.com/banners/SAM550d.jpg",
- "align": "left",
- "hspace": "5",
- "/": null
- },
- "tag": "img",
- "end": 39013,
- "start": 38935,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "br",
- "end": 39018,
- "start": 39013,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 39026,
- "start": 39018,
- "tag_type": 1
- },
- {
- "start": 39026,
- "end": 39033
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 39042,
- "start": 39033,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "br",
- "end": 39047,
- "start": 39042,
- "tag_type": 3
- },
- {
- "start": 39047,
- "end": 39147
- },
- {
- "attributes": {},
- "tag": "br",
- "end": 39152,
- "start": 39147,
- "tag_type": 3
- },
- {
- "attributes": {
- "clear": "ALL"
- },
- "tag": "br",
- "end": 39168,
- "start": 39152,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 39172,
- "start": 39168,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 39178,
- "start": 39172,
- "tag_type": 2
- },
- {
- "start": 39178,
- "end": 39182
- },
- {
- "attributes": {
- "class": "subhead"
- },
- "tag": "div",
- "end": 39203,
- "start": 39182,
- "tag_type": 1
- },
- {
- "start": 39203,
- "end": 39211
- },
- {
- "attributes": {
- "id": "jump-customer-review",
- "name": "jump-customer-review"
- },
- "tag": "h3",
- "end": 39265,
- "start": 39211,
- "tag_type": 1
- },
- {
- "attributes": {
- "cellpadding": "0",
- "cellspacing": "0"
- },
- "tag": "table",
- "end": 39304,
- "start": 39265,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 39311,
- "start": 39304,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 39315,
- "start": 39311,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "text"
- },
- "tag": "td",
- "end": 39332,
- "start": 39315,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 39338,
- "start": 39332,
- "tag_type": 1
- },
- {
- "start": 39338,
- "end": 39354
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 39361,
- "start": 39354,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 39366,
- "start": 39361,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "tabend"
- },
- "tag": "td",
- "end": 39387,
- "start": 39366,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 39392,
- "start": 39387,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 39400,
- "start": 39392,
- "tag_type": 2
- },
- {
- "start": 39400,
- "end": 39412
- },
- {
- "attributes": {},
- "tag": "table",
- "end": 39420,
- "start": 39412,
- "tag_type": 2
- },
- {
- "start": 39420,
- "end": 39428
- },
- {
- "attributes": {},
- "tag": "h3",
- "end": 39433,
- "start": 39428,
- "tag_type": 2
- },
- {
- "start": 39433,
- "end": 39449
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 39452,
- "start": 39449,
- "tag_type": 1
- },
- {
- "start": 39452,
- "end": 39464
- },
- {
- "attributes": {
- "href": null
- },
- "tag": "a",
- "end": 39475,
- "start": 39464,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 39479,
- "start": 39475,
- "tag_type": 2
- },
- {
- "start": 39479,
- "end": 39493
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 39497,
- "start": 39493,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 39503,
- "start": 39497,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "rnr slice"
- },
- "tag": "div",
- "end": 39526,
- "start": 39503,
- "tag_type": 1
- },
- {
- "attributes": {
- "id": "_pageTemplate__product_ctl00__cacheable__customerReviews_ctl00_avarageRating__divAverage",
- "class": "rnr-average"
- },
- "tag": "div",
- "end": 39645,
- "start": 39526,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 39650,
- "start": 39645,
- "tag_type": 1
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteCSS/Play/Live1/img/spaces/stars50_x.gif",
- "alt": "Customer rating on Samsung Series 5 550 37" LE37B550 / HD 1080p / Freeview / LCD TV (Black): 5 out of 5 stars",
- "style": "height:21px;width:106px;border-width:0px;"
- },
- "tag": "img",
- "end": 39901,
- "start": 39650,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 39907,
- "start": 39901,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 39910,
- "start": 39907,
- "tag_type": 1
- },
- {
- "start": 39910,
- "end": 39926
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 39934,
- "start": 39926,
- "tag_type": 1
- },
- {
- "start": 39934,
- "end": 39935
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 39944,
- "start": 39935,
- "tag_type": 2
- },
- {
- "start": 39944,
- "end": 39952
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 39956,
- "start": 39952,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 39962,
- "start": 39956,
- "tag_type": 2
- },
- {
- "attributes": {
- "id": "_pageTemplate__product_ctl00__cacheable__customerReviews_ctl00_divHeaderLinks",
- "class": "rnr-links"
- },
- "tag": "div",
- "end": 40068,
- "start": 39962,
- "tag_type": 1
- },
- {
- "start": 40068,
- "end": 40080
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 40083,
- "start": 40080,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "https://www.play.com/OrdersPost.aspx?&returnURL=http://www.play.com/Product.aspx?searchtype=genre&r=ELEC&p=318&g=404&title=8986420&PRODUCT_TITLE=Samsung-Series-5-550-37-LE37B550-HD-1080p-Freeview-LCD-TV¤cy=257&source=0&action=addreview&subaction=productreviewadd&_productid=8986420&_region=ELEC&_producttitle=Samsung+Series+5+550+37%22+LE37B550+%2f+HD+1080p+%2f+Freeview+%2f+LCD+TV+(Black)&_smallimageavailable=1",
- "title": "Write a review of Samsung Series 5 550 37" LE37B550 / HD 1080p / Freeview / LCD TV (Black)"
- },
- "tag": "a",
- "end": 40616,
- "start": 40083,
- "tag_type": 1
- },
- {
- "start": 40616,
- "end": 40630
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 40634,
- "start": 40630,
- "tag_type": 2
- },
- {
- "start": 40634,
- "end": 40637
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/8986420/Samsung-Series-5-550-37-LE37B550-HD-1080p-Freeview-LCD-TV/ProductReviews.html",
- "title": "See all Samsung Series 5 550 37" LE37B550 / HD 1080p / Freeview / LCD TV (Black) reviews"
- },
- "tag": "a",
- "end": 40863,
- "start": 40637,
- "tag_type": 1
- },
- {
- "start": 40863,
- "end": 40889
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 40893,
- "start": 40889,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 40897,
- "start": 40893,
- "tag_type": 2
- },
- {
- "start": 40897,
- "end": 40905
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 40911,
- "start": 40905,
- "tag_type": 2
- },
- {
- "start": 40911,
- "end": 40927
- },
- {
- "attributes": {
- "class": "rnr-review"
- },
- "tag": "div",
- "end": 40951,
- "start": 40927,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "rnr-header"
- },
- "tag": "div",
- "end": 40975,
- "start": 40951,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "h4",
- "end": 40979,
- "start": 40975,
- "tag_type": 1
- },
- {
- "attributes": {
- "name": "346537"
- },
- "tag": "a",
- "end": 40996,
- "start": 40979,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 41000,
- "start": 40996,
- "tag_type": 2
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteCSS/Play/Live1/img/spaces/stars50.gif",
- "alt": "Customer rating: 5 out of 5 stars",
- "style": "height:14px;width:71px;border-width:0px;"
- },
- "tag": "img",
- "end": 41167,
- "start": 41000,
- "tag_type": 3
- },
- {
- "start": 41167,
- "end": 41185
- },
- {
- "attributes": {},
- "tag": "h4",
- "end": 41190,
- "start": 41185,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "rnr-info"
- },
- "tag": "p",
- "end": 41210,
- "start": 41190,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 41218,
- "start": 41210,
- "tag_type": 1
- },
- {
- "start": 41218,
- "end": 41225
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 41234,
- "start": 41225,
- "tag_type": 2
- },
- {
- "start": 41234,
- "end": 41247
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 41253,
- "start": 41247,
- "tag_type": 1
- },
- {
- "start": 41253,
- "end": 41263
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 41270,
- "start": 41263,
- "tag_type": 2
- },
- {
- "start": 41270,
- "end": 41283
- },
- {
- "attributes": {
- "href": "/HOME/HOME/6-/UserReviews.html?rn=124580&edtm=0"
- },
- "tag": "a",
- "end": 41341,
- "start": 41283,
- "tag_type": 1
- },
- {
- "start": 41341,
- "end": 41377
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 41381,
- "start": 41377,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 41385,
- "start": 41381,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 41391,
- "start": 41385,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "rnr-content"
- },
- "tag": "div",
- "end": 41416,
- "start": 41391,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 41419,
- "start": 41416,
- "tag_type": 1
- },
- {
- "start": 41419,
- "end": 41562
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 41566,
- "start": 41562,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 41572,
- "start": 41566,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "rnr-footer"
- },
- "tag": "div",
- "end": 41596,
- "start": 41572,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 41599,
- "start": 41596,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 41605,
- "start": 41599,
- "tag_type": 1
- },
- {
- "start": 41605,
- "end": 41638
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 41645,
- "start": 41638,
- "tag_type": 2
- },
- {
- "attributes": {
- "href": "https://www.play.com/OrdersPost.aspx?&returnURL=http://www.play.com/Product.aspx?searchtype=genre&r=ELEC&p=318&g=404&title=8986420&PRODUCT_TITLE=Samsung-Series-5-550-37-LE37B550-HD-1080p-Freeview-LCD-TV¤cy=257&source=0&action=addreview&subaction=REVIEW_VOTE&_reviewId=346537&_helpful=y",
- "id": "_pageTemplate__product_ctl00__cacheable__customerReviews_ctl00_listReviews_ctl00_reviewItem__linkYes"
- },
- "tag": "a",
- "end": 42101,
- "start": 41645,
- "tag_type": 1
- },
- {
- "start": 42101,
- "end": 42104
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 42108,
- "start": 42104,
- "tag_type": 2
- },
- {
- "start": 42108,
- "end": 42121
- },
- {
- "attributes": {
- "href": "https://www.play.com/OrdersPost.aspx?&returnURL=http://www.play.com/Product.aspx?searchtype=genre&r=ELEC&p=318&g=404&title=8986420&PRODUCT_TITLE=Samsung-Series-5-550-37-LE37B550-HD-1080p-Freeview-LCD-TV¤cy=257&source=0&action=addreview&subaction=REVIEW_VOTE&_reviewId=346537&_helpful=n",
- "id": "_pageTemplate__product_ctl00__cacheable__customerReviews_ctl00_listReviews_ctl00_reviewItem__linkNo"
- },
- "tag": "a",
- "end": 42576,
- "start": 42121,
- "tag_type": 1
- },
- {
- "start": 42576,
- "end": 42578
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 42582,
- "start": 42578,
- "tag_type": 2
- },
- {
- "start": 42582,
- "end": 42595
- },
- {
- "attributes": {
- "href": "https://www.play.com/OrdersPost.aspx?&returnURL=http://www.play.com/Product.aspx?searchtype=genre&r=ELEC&p=318&g=404&title=8986420&PRODUCT_TITLE=Samsung-Series-5-550-37-LE37B550-HD-1080p-Freeview-LCD-TV¤cy=257&source=0&action=addreview&subaction=report_review&_reviewId=346537",
- "id": "_pageTemplate__product_ctl00__cacheable__customerReviews_ctl00_listReviews_ctl00_reviewItem__ReportReviewLink_lnkReportReview"
- },
- "tag": "a",
- "end": 43063,
- "start": 42595,
- "tag_type": 1
- },
- {
- "start": 43063,
- "end": 43075
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 43079,
- "start": 43075,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 43083,
- "start": 43079,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 43089,
- "start": 43083,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 43095,
- "start": 43089,
- "tag_type": 2
- },
- {
- "start": 43095,
- "end": 43115
- },
- {
- "attributes": {
- "class": "rnr-links"
- },
- "tag": "div",
- "end": 43138,
- "start": 43115,
- "tag_type": 1
- },
- {
- "start": 43138,
- "end": 43150
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 43153,
- "start": 43150,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "https://www.play.com/OrdersPost.aspx?&returnURL=http://www.play.com/Product.aspx?searchtype=genre&r=ELEC&p=318&g=404&title=8986420&PRODUCT_TITLE=Samsung-Series-5-550-37-LE37B550-HD-1080p-Freeview-LCD-TV¤cy=257&source=0&action=addreview&subaction=productreviewadd&_productid=8986420&_region=ELEC&_producttitle=Samsung+Series+5+550+37%22+LE37B550+%2f+HD+1080p+%2f+Freeview+%2f+LCD+TV+(Black)&_smallimageavailable=1",
- "title": "Write a review of Samsung Series 5 550 37" LE37B550 / HD 1080p / Freeview / LCD TV (Black)"
- },
- "tag": "a",
- "end": 43686,
- "start": 43153,
- "tag_type": 1
- },
- {
- "start": 43686,
- "end": 43700
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 43704,
- "start": 43700,
- "tag_type": 2
- },
- {
- "start": 43704,
- "end": 43707
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/8986420/Samsung-Series-5-550-37-LE37B550-HD-1080p-Freeview-LCD-TV/ProductReviews.html",
- "title": "See all Samsung Series 5 550 37" LE37B550 / HD 1080p / Freeview / LCD TV (Black) reviews"
- },
- "tag": "a",
- "end": 43933,
- "start": 43707,
- "tag_type": 1
- },
- {
- "start": 43933,
- "end": 43959
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 43963,
- "start": 43959,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 43967,
- "start": 43963,
- "tag_type": 2
- },
- {
- "start": 43967,
- "end": 43975
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 43981,
- "start": 43975,
- "tag_type": 2
- },
- {
- "start": 43981,
- "end": 43985
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 43991,
- "start": 43985,
- "tag_type": 2
- },
- {
- "start": 43991,
- "end": 43995
- },
- {
- "attributes": {
- "class": "subhead"
- },
- "tag": "div",
- "end": 44016,
- "start": 43995,
- "tag_type": 1
- },
- {
- "start": 44016,
- "end": 44024
- },
- {
- "attributes": {},
- "tag": "h3",
- "end": 44029,
- "start": 44024,
- "tag_type": 1
- },
- {
- "attributes": {
- "cellpadding": "0",
- "cellspacing": "0"
- },
- "tag": "table",
- "end": 44068,
- "start": 44029,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 44075,
- "start": 44068,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 44079,
- "start": 44075,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "text"
- },
- "tag": "td",
- "end": 44096,
- "start": 44079,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 44102,
- "start": 44096,
- "tag_type": 1
- },
- {
- "start": 44102,
- "end": 44129
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 44136,
- "start": 44129,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 44141,
- "start": 44136,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "tabend"
- },
- "tag": "td",
- "end": 44162,
- "start": 44141,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 44167,
- "start": 44162,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 44175,
- "start": 44167,
- "tag_type": 2
- },
- {
- "start": 44175,
- "end": 44187
- },
- {
- "attributes": {},
- "tag": "table",
- "end": 44195,
- "start": 44187,
- "tag_type": 2
- },
- {
- "start": 44195,
- "end": 44203
- },
- {
- "attributes": {},
- "tag": "h3",
- "end": 44208,
- "start": 44203,
- "tag_type": 2
- },
- {
- "start": 44208,
- "end": 44224
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 44227,
- "start": 44224,
- "tag_type": 1
- },
- {
- "start": 44227,
- "end": 44239
- },
- {
- "attributes": {
- "href": null
- },
- "tag": "a",
- "end": 44250,
- "start": 44239,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 44254,
- "start": 44250,
- "tag_type": 2
- },
- {
- "start": 44254,
- "end": 44268
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 44272,
- "start": 44268,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 44278,
- "start": 44272,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "related slice"
- },
- "tag": "div",
- "end": 44305,
- "start": 44278,
- "tag_type": 1
- },
- {
- "attributes": {
- "cellspacing": "0"
- },
- "tag": "table",
- "end": 44329,
- "start": 44305,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 44333,
- "start": 44329,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 44337,
- "start": 44333,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "image"
- },
- "tag": "div",
- "end": 44356,
- "start": 44337,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/8986409/Samsung-Series-5-550-32-LE32B550-HD-1080p-Freeview-LCD-TV/Product.html"
- },
- "tag": "a",
- "end": 44473,
- "start": 44356,
- "tag_type": 1
- },
- {
- "attributes": {
- "onerror": null,
- "src": "http://images.play.com/covers/8986409s.jpg",
- "alt": "Samsung Series 5 550 32" LE32B550 / HD 1080p / Freeview / LCD TV (Black)",
- "style": "height:85px;width:85px;border-width:0px;"
- },
- "tag": "img",
- "end": 44737,
- "start": 44473,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 44741,
- "start": 44737,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 44747,
- "start": 44741,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 44752,
- "start": 44747,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "wide"
- },
- "tag": "td",
- "end": 44769,
- "start": 44752,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "info"
- },
- "tag": "div",
- "end": 44787,
- "start": 44769,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 44791,
- "start": 44787,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 44795,
- "start": 44791,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/8986409/Samsung-Series-5-550-32-LE32B550-HD-1080p-Freeview-LCD-TV/Product.html"
- },
- "tag": "a",
- "end": 44912,
- "start": 44795,
- "tag_type": 1
- },
- {
- "start": 44912,
- "end": 45015
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 45019,
- "start": 45015,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 45024,
- "start": 45019,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 45029,
- "start": 45024,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 45035,
- "start": 45029,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 45040,
- "start": 45035,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 45045,
- "start": 45040,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "table",
- "end": 45053,
- "start": 45045,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 45059,
- "start": 45053,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 45065,
- "start": 45059,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 45071,
- "start": 45065,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "footnote wrap"
- },
- "tag": "div",
- "end": 45098,
- "start": 45071,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "email"
- },
- "tag": "p",
- "end": 45115,
- "start": 45098,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/8986420/-/EmailAFriend.html"
- },
- "tag": "a",
- "end": 45181,
- "start": 45115,
- "tag_type": 1
- },
- {
- "start": 45181,
- "end": 45215
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 45219,
- "start": 45215,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 45223,
- "start": 45219,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 45226,
- "start": 45223,
- "tag_type": 1
- },
- {
- "start": 45226,
- "end": 45255
- },
- {
- "attributes": {
- "style": "cursor:hand",
- "href": "javascript:flagcorrections ('http://www.play.com/Correction.aspx','8986420','')"
- },
- "tag": "a",
- "end": 45365,
- "start": 45255,
- "tag_type": 1
- },
- {
- "start": 45365,
- "end": 45382
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 45386,
- "start": 45382,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 45390,
- "start": 45386,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 45393,
- "start": 45390,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "#goto-top"
- },
- "tag": "a",
- "end": 45413,
- "start": 45393,
- "tag_type": 1
- },
- {
- "start": 45413,
- "end": 45424
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 45428,
- "start": 45424,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 45432,
- "start": 45428,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 45438,
- "start": 45432,
- "tag_type": 2
- },
- {
- "start": 45438,
- "end": 45462
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 45468,
- "start": 45462,
- "tag_type": 2
- },
- {
- "start": 45468,
- "end": 45488
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 45494,
- "start": 45488,
- "tag_type": 2
- },
- {
- "start": 45494,
- "end": 45514
- },
- {
- "attributes": {
- "id": "leftCol"
- },
- "tag": "div",
- "end": 45532,
- "start": 45514,
- "tag_type": 1
- },
- {
- "start": 45532,
- "end": 45556
- },
- {
- "attributes": {
- "class": "column"
- },
- "tag": "div",
- "end": 45576,
- "start": 45556,
- "tag_type": 1
- },
- {
- "start": 45576,
- "end": 45600
- },
- {
- "attributes": {
- "class": "browse wrap"
- },
- "tag": "div",
- "end": 45626,
- "start": 45600,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "boxhead"
- },
- "tag": "div",
- "end": 45647,
- "start": 45626,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 45652,
- "start": 45647,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 45657,
- "start": 45652,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 45661,
- "start": 45657,
- "tag_type": 1
- },
- {
- "start": 45661,
- "end": 45679
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 45684,
- "start": 45679,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 45690,
- "start": 45684,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 45696,
- "start": 45690,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 45702,
- "start": 45696,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "box"
- },
- "tag": "div",
- "end": 45719,
- "start": 45702,
- "tag_type": 1
- },
- {
- "start": 45719,
- "end": 45727
- },
- {
- "attributes": {
- "class": "top"
- },
- "tag": "ul",
- "end": 45743,
- "start": 45727,
- "tag_type": 1
- },
- {
- "start": 45743,
- "end": 45755
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 45759,
- "start": 45755,
- "tag_type": 1
- },
- {
- "start": 45759,
- "end": 45767
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/6-/NewReleases.html"
- },
- "tag": "a",
- "end": 45822,
- "start": 45767,
- "tag_type": 1
- },
- {
- "start": 45822,
- "end": 45834
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 45838,
- "start": 45834,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 45843,
- "start": 45838,
- "tag_type": 2
- },
- {
- "start": 45843,
- "end": 45855
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 45859,
- "start": 45855,
- "tag_type": 1
- },
- {
- "start": 45859,
- "end": 45867
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/3-/TopSellers.html?searchtype=genre"
- },
- "tag": "a",
- "end": 45948,
- "start": 45867,
- "tag_type": 1
- },
- {
- "start": 45948,
- "end": 45959
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 45963,
- "start": 45959,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 45968,
- "start": 45963,
- "tag_type": 2
- },
- {
- "start": 45968,
- "end": 45980
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 45984,
- "start": 45980,
- "tag_type": 1
- },
- {
- "start": 45984,
- "end": 45992
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/3-/ComingSoon.html?searchtype=genre"
- },
- "tag": "a",
- "end": 46073,
- "start": 45992,
- "tag_type": 1
- },
- {
- "start": 46073,
- "end": 46084
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 46088,
- "start": 46084,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 46093,
- "start": 46088,
- "tag_type": 2
- },
- {
- "start": 46093,
- "end": 46105
- },
- {
- "attributes": {
- "class": "bottom"
- },
- "tag": "li",
- "end": 46124,
- "start": 46105,
- "tag_type": 1
- },
- {
- "start": 46124,
- "end": 46132
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/3-/RecentReleases.html?searchtype=genre"
- },
- "tag": "a",
- "end": 46217,
- "start": 46132,
- "tag_type": 1
- },
- {
- "start": 46217,
- "end": 46232
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 46236,
- "start": 46232,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 46241,
- "start": 46236,
- "tag_type": 2
- },
- {
- "start": 46241,
- "end": 46253
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 46258,
- "start": 46253,
- "tag_type": 2
- },
- {
- "start": 46258,
- "end": 46270
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 46274,
- "start": 46270,
- "tag_type": 1
- },
- {
- "start": 46274,
- "end": 46286
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 46291,
- "start": 46286,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/996/1241/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 46373,
- "start": 46291,
- "tag_type": 1
- },
- {
- "start": 46373,
- "end": 46379
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 46383,
- "start": 46379,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 46388,
- "start": 46383,
- "tag_type": 2
- },
- {
- "start": 46388,
- "end": 46400
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 46405,
- "start": 46400,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/253/333/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 46486,
- "start": 46405,
- "tag_type": 1
- },
- {
- "start": 46486,
- "end": 46496
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 46500,
- "start": 46496,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 46505,
- "start": 46500,
- "tag_type": 2
- },
- {
- "start": 46505,
- "end": 46517
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 46522,
- "start": 46517,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/248/328/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 46603,
- "start": 46522,
- "tag_type": 1
- },
- {
- "start": 46603,
- "end": 46627
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 46631,
- "start": 46627,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 46636,
- "start": 46631,
- "tag_type": 2
- },
- {
- "start": 46636,
- "end": 46648
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 46653,
- "start": 46648,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/256/336/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 46734,
- "start": 46653,
- "tag_type": 1
- },
- {
- "start": 46734,
- "end": 46749
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 46753,
- "start": 46749,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 46758,
- "start": 46753,
- "tag_type": 2
- },
- {
- "start": 46758,
- "end": 46770
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 46775,
- "start": 46770,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/261/341/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 46856,
- "start": 46775,
- "tag_type": 1
- },
- {
- "start": 46856,
- "end": 46859
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 46863,
- "start": 46859,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 46868,
- "start": 46863,
- "tag_type": 2
- },
- {
- "start": 46868,
- "end": 46880
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 46885,
- "start": 46880,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/267/347/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 46966,
- "start": 46885,
- "tag_type": 1
- },
- {
- "start": 46966,
- "end": 46978
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 46982,
- "start": 46978,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 46987,
- "start": 46982,
- "tag_type": 2
- },
- {
- "start": 46987,
- "end": 46999
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 47004,
- "start": 46999,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/271/351/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 47085,
- "start": 47004,
- "tag_type": 1
- },
- {
- "start": 47085,
- "end": 47095
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 47099,
- "start": 47095,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 47104,
- "start": 47099,
- "tag_type": 2
- },
- {
- "start": 47104,
- "end": 47116
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 47121,
- "start": 47116,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/275/355/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 47202,
- "start": 47121,
- "tag_type": 1
- },
- {
- "start": 47202,
- "end": 47215
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 47219,
- "start": 47215,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 47224,
- "start": 47219,
- "tag_type": 2
- },
- {
- "start": 47224,
- "end": 47236
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 47241,
- "start": 47236,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/281/363/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 47322,
- "start": 47241,
- "tag_type": 1
- },
- {
- "start": 47322,
- "end": 47333
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 47337,
- "start": 47333,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 47342,
- "start": 47337,
- "tag_type": 2
- },
- {
- "start": 47342,
- "end": 47354
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 47359,
- "start": 47354,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/291/375/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 47440,
- "start": 47359,
- "tag_type": 1
- },
- {
- "start": 47440,
- "end": 47448
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 47452,
- "start": 47448,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 47457,
- "start": 47452,
- "tag_type": 2
- },
- {
- "start": 47457,
- "end": 47469
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 47474,
- "start": 47469,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/295/379/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 47555,
- "start": 47474,
- "tag_type": 1
- },
- {
- "start": 47555,
- "end": 47569
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 47573,
- "start": 47569,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 47578,
- "start": 47573,
- "tag_type": 2
- },
- {
- "start": 47578,
- "end": 47590
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 47595,
- "start": 47590,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/316/402/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 47676,
- "start": 47595,
- "tag_type": 1
- },
- {
- "start": 47676,
- "end": 47683
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 47687,
- "start": 47683,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 47692,
- "start": 47687,
- "tag_type": 2
- },
- {
- "start": 47692,
- "end": 47704
- },
- {
- "attributes": {
- "class": "selected"
- },
- "tag": "li",
- "end": 47725,
- "start": 47704,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/3-/RegionHome.html?searchtype=genre",
- "class": "this"
- },
- "tag": "a",
- "end": 47819,
- "start": 47725,
- "tag_type": 1
- },
- {
- "start": 47819,
- "end": 47829
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 47833,
- "start": 47829,
- "tag_type": 2
- },
- {
- "start": 47833,
- "end": 47841
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 47845,
- "start": 47841,
- "tag_type": 1
- },
- {
- "start": 47845,
- "end": 47857
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 47862,
- "start": 47857,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/319/405/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 47943,
- "start": 47862,
- "tag_type": 1
- },
- {
- "start": 47943,
- "end": 47967
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 47971,
- "start": 47967,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 47976,
- "start": 47971,
- "tag_type": 2
- },
- {
- "start": 47976,
- "end": 47988
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 47993,
- "start": 47988,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/320/406/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 48074,
- "start": 47993,
- "tag_type": 1
- },
- {
- "start": 48074,
- "end": 48089
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 48093,
- "start": 48089,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 48098,
- "start": 48093,
- "tag_type": 2
- },
- {
- "start": 48098,
- "end": 48110
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 48115,
- "start": 48110,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/949/1189/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 48197,
- "start": 48115,
- "tag_type": 1
- },
- {
- "start": 48197,
- "end": 48217
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 48221,
- "start": 48217,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 48226,
- "start": 48221,
- "tag_type": 2
- },
- {
- "start": 48226,
- "end": 48238
- },
- {
- "attributes": {
- "class": "bottom"
- },
- "tag": "li",
- "end": 48257,
- "start": 48238,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/995/407/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 48338,
- "start": 48257,
- "tag_type": 1
- },
- {
- "start": 48338,
- "end": 48349
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 48353,
- "start": 48349,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 48358,
- "start": 48353,
- "tag_type": 2
- },
- {
- "start": 48358,
- "end": 48370
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 48375,
- "start": 48370,
- "tag_type": 2
- },
- {
- "start": 48375,
- "end": 48379
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 48384,
- "start": 48379,
- "tag_type": 2
- },
- {
- "start": 48384,
- "end": 48396
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 48401,
- "start": 48396,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/2168/1435/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 48484,
- "start": 48401,
- "tag_type": 1
- },
- {
- "start": 48484,
- "end": 48492
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 48496,
- "start": 48492,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 48501,
- "start": 48496,
- "tag_type": 2
- },
- {
- "start": 48501,
- "end": 48513
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 48518,
- "start": 48513,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/988/1236/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 48600,
- "start": 48518,
- "tag_type": 1
- },
- {
- "start": 48600,
- "end": 48620
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 48624,
- "start": 48620,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 48629,
- "start": 48624,
- "tag_type": 2
- },
- {
- "start": 48629,
- "end": 48641
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 48646,
- "start": 48641,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/371/471/3-/RegionHome.html?searchtype=genre"
- },
- "tag": "a",
- "end": 48727,
- "start": 48646,
- "tag_type": 1
- },
- {
- "start": 48727,
- "end": 48735
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 48739,
- "start": 48735,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 48744,
- "start": 48739,
- "tag_type": 2
- },
- {
- "start": 48744,
- "end": 48756
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 48761,
- "start": 48756,
- "tag_type": 2
- },
- {
- "start": 48761,
- "end": 48765
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 48769,
- "start": 48765,
- "tag_type": 1
- },
- {
- "start": 48769,
- "end": 48773
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 48777,
- "start": 48773,
- "tag_type": 1
- },
- {
- "start": 48777,
- "end": 48785
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/6-/GenreCategories.html",
- "class": "viewcats"
- },
- "tag": "a",
- "end": 48861,
- "start": 48785,
- "tag_type": 1
- },
- {
- "start": 48861,
- "end": 48888
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 48892,
- "start": 48888,
- "tag_type": 2
- },
- {
- "start": 48892,
- "end": 48896
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 48901,
- "start": 48896,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 48906,
- "start": 48901,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 48912,
- "start": 48906,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 48918,
- "start": 48912,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "wrap"
- },
- "tag": "div",
- "end": 48936,
- "start": 48918,
- "tag_type": 1
- },
- {
- "attributes": {
- "cellspacing": "0"
- },
- "tag": "table",
- "end": 48959,
- "start": 48936,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 48963,
- "start": 48959,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 48967,
- "start": 48963,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 48972,
- "start": 48967,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/campaign.aspx?campaign=4894&cid=4089054&dpr=0",
- "manual_cm_sp": "digibrick.jpg-_-LeftLandingPageBanner1-_-ELEC",
- "manual_cm_re": "Left-_-LandingPageBanner1-_-digibrick.jpg"
- },
- "tag": "a",
- "end": 49151,
- "start": 48972,
- "tag_type": 1
- },
- {
- "attributes": {
- "src": "http://images.play.com/PROMOTIONAL_IMAGES/LANDING_BANNERS/164402.jpg",
- "alt": "Digital Camera Store brick",
- "style": "border-width:0px;"
- },
- "tag": "img",
- "end": 49292,
- "start": 49151,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 49296,
- "start": 49292,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 49302,
- "start": 49296,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 49307,
- "start": 49302,
- "tag_type": 2
- },
- {
- "start": 49307,
- "end": 49327
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 49331,
- "start": 49327,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 49336,
- "start": 49331,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/3-/240913/2-/Promo.html?dpr=240913",
- "manual_cm_sp": "High-Def_35per.jpg-_-LeftLandingPageBanner2-_-ELEC",
- "manual_cm_re": "Left-_-LandingPageBanner2-_-High-Def_35per.jpg"
- },
- "tag": "a",
- "end": 49534,
- "start": 49336,
- "tag_type": 1
- },
- {
- "attributes": {
- "src": "http://images.play.com/PROMOTIONAL_IMAGES/LANDING_BANNERS/31800.jpg",
- "alt": "New Hi Def Technology",
- "style": "border-width:0px;"
- },
- "tag": "img",
- "end": 49669,
- "start": 49534,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 49673,
- "start": 49669,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 49679,
- "start": 49673,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 49684,
- "start": 49679,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 49689,
- "start": 49684,
- "tag_type": 2
- },
- {
- "start": 49689,
- "end": 49697
- },
- {
- "attributes": {},
- "tag": "table",
- "end": 49705,
- "start": 49697,
- "tag_type": 2
- },
- {
- "start": 49705,
- "end": 49709
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 49715,
- "start": 49709,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "hotpick wrap"
- },
- "tag": "div",
- "end": 49742,
- "start": 49715,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "boxhead"
- },
- "tag": "div",
- "end": 49763,
- "start": 49742,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 49768,
- "start": 49763,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 49773,
- "start": 49768,
- "tag_type": 1
- },
- {
- "start": 49773,
- "end": 49777
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/3-/HotPicksList.html?searchtype=genre"
- },
- "tag": "a",
- "end": 49860,
- "start": 49777,
- "tag_type": 1
- },
- {
- "start": 49860,
- "end": 49868
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 49872,
- "start": 49868,
- "tag_type": 1
- },
- {
- "start": 49872,
- "end": 49894
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 49899,
- "start": 49894,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 49903,
- "start": 49899,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 49909,
- "start": 49903,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 49915,
- "start": 49909,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 49921,
- "start": 49915,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "box"
- },
- "tag": "div",
- "end": 49938,
- "start": 49921,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "h5",
- "end": 49942,
- "start": 49938,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/8986397/Samsung-Series-4-450-32-LE32B450-HD-Ready-Freeview-LCD-TV/Product.html"
- },
- "tag": "a",
- "end": 50059,
- "start": 49942,
- "tag_type": 1
- },
- {
- "start": 50059,
- "end": 50136
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 50140,
- "start": 50136,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "h5",
- "end": 50145,
- "start": 50140,
- "tag_type": 2
- },
- {
- "attributes": {
- "cellspacing": "0"
- },
- "tag": "table",
- "end": 50168,
- "start": 50145,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 50172,
- "start": 50168,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 50176,
- "start": 50172,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "image"
- },
- "tag": "div",
- "end": 50195,
- "start": 50176,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/8986397/Samsung-Series-4-450-32-LE32B450-HD-Ready-Freeview-LCD-TV/Product.html",
- "cssclass": "sideimagelink"
- },
- "tag": "a",
- "end": 50337,
- "start": 50195,
- "tag_type": 1
- },
- {
- "attributes": {
- "onerror": null,
- "src": "http://images.play.com/covers/8986397s.jpg",
- "alt": "Samsung Series 4 450 32" LE32B450 / HD Ready / Freeview / LCD TV (Black)",
- "style": "height:60px;width:60px;border-width:0px;",
- "class": "sideimageline"
- },
- "tag": "img",
- "end": 50624,
- "start": 50337,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 50628,
- "start": 50624,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 50634,
- "start": 50628,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 50639,
- "start": 50634,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "wide"
- },
- "tag": "td",
- "end": 50656,
- "start": 50639,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "h6",
- "end": 50660,
- "start": 50656,
- "tag_type": 1
- },
- {
- "start": 50660,
- "end": 50672
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 50678,
- "start": 50672,
- "tag_type": 1
- },
- {
- "start": 50678,
- "end": 50692
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 50699,
- "start": 50692,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "h6",
- "end": 50704,
- "start": 50699,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "saving"
- },
- "tag": "p",
- "end": 50722,
- "start": 50704,
- "tag_type": 1
- },
- {
- "start": 50722,
- "end": 50726
- },
- {
- "attributes": {},
- "tag": "br",
- "end": 50732,
- "start": 50726,
- "tag_type": 3
- },
- {
- "attributes": {
- "class": "rrp"
- },
- "tag": "span",
- "end": 50750,
- "start": 50732,
- "tag_type": 1
- },
- {
- "start": 50750,
- "end": 50762
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 50769,
- "start": 50762,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "br",
- "end": 50775,
- "start": 50769,
- "tag_type": 3
- },
- {
- "start": 50775,
- "end": 50784
- },
- {
- "attributes": {},
- "tag": "br",
- "end": 50790,
- "start": 50784,
- "tag_type": 3
- },
- {
- "attributes": {
- "class": "drop"
- },
- "tag": "span",
- "end": 50809,
- "start": 50790,
- "tag_type": 1
- },
- {
- "start": 50809,
- "end": 50821
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 50828,
- "start": 50821,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 50832,
- "start": 50828,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 50837,
- "start": 50832,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 50842,
- "start": 50837,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "table",
- "end": 50850,
- "start": 50842,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "more"
- },
- "tag": "p",
- "end": 50866,
- "start": 50850,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/3-/HotPicksList.html?searchtype=genre"
- },
- "tag": "a",
- "end": 50949,
- "start": 50866,
- "tag_type": 1
- },
- {
- "start": 50949,
- "end": 50958
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 50964,
- "start": 50958,
- "tag_type": 1
- },
- {
- "start": 50964,
- "end": 50965
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 50972,
- "start": 50965,
- "tag_type": 2
- },
- {
- "start": 50972,
- "end": 50973
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 50977,
- "start": 50973,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 50981,
- "start": 50977,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 50987,
- "start": 50981,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 50993,
- "start": 50987,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "recentlyviewed wrap"
- },
- "tag": "div",
- "end": 51027,
- "start": 50993,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "boxhead"
- },
- "tag": "div",
- "end": 51048,
- "start": 51027,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 51053,
- "start": 51048,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 51058,
- "start": 51053,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 51062,
- "start": 51058,
- "tag_type": 1
- },
- {
- "start": 51062,
- "end": 51083
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 51088,
- "start": 51083,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 51094,
- "start": 51088,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 51100,
- "start": 51094,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 51106,
- "start": 51100,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "box"
- },
- "tag": "div",
- "end": 51123,
- "start": 51106,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "h3",
- "end": 51127,
- "start": 51123,
- "tag_type": 1
- },
- {
- "start": 51127,
- "end": 51146
- },
- {
- "attributes": {},
- "tag": "h3",
- "end": 51151,
- "start": 51146,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 51155,
- "start": 51151,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 51159,
- "start": 51155,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/8986420/Samsung-Series-5-550-37-LE37B550-HD-1080p-Freeview-LCD-TV/Product.html"
- },
- "tag": "a",
- "end": 51276,
- "start": 51159,
- "tag_type": 1
- },
- {
- "start": 51276,
- "end": 51353
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 51357,
- "start": 51353,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 51362,
- "start": 51357,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 51367,
- "start": 51362,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "more"
- },
- "tag": "p",
- "end": 51383,
- "start": 51367,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/8986420/-/Product.html"
- },
- "tag": "a",
- "end": 51444,
- "start": 51383,
- "tag_type": 1
- },
- {
- "start": 51444,
- "end": 51460
- },
- {
- "attributes": {
- "class": "orangepanel"
- },
- "tag": "span",
- "end": 51486,
- "start": 51460,
- "tag_type": 1
- },
- {
- "start": 51486,
- "end": 51487
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 51494,
- "start": 51487,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 51498,
- "start": 51494,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 51502,
- "start": 51498,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 51508,
- "start": 51502,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 51514,
- "start": 51508,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "charts wrap",
- "id": "charts"
- },
- "tag": "div",
- "end": 51551,
- "start": 51514,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "boxhead"
- },
- "tag": "div",
- "end": 51572,
- "start": 51551,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 51577,
- "start": 51572,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 51582,
- "start": 51577,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 51586,
- "start": 51582,
- "tag_type": 1
- },
- {
- "start": 51586,
- "end": 51592
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 51597,
- "start": 51592,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 51603,
- "start": 51597,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 51609,
- "start": 51603,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 51615,
- "start": 51609,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "box"
- },
- "tag": "div",
- "end": 51632,
- "start": 51615,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 51636,
- "start": 51632,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 51640,
- "start": 51636,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/6-/TopSellers.html"
- },
- "tag": "a",
- "end": 51694,
- "start": 51640,
- "tag_type": 1
- },
- {
- "start": 51694,
- "end": 51705
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 51709,
- "start": 51705,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 51713,
- "start": 51709,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "charts-topsellers"
- },
- "tag": "li",
- "end": 51743,
- "start": 51713,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "h3",
- "end": 51747,
- "start": 51743,
- "tag_type": 1
- },
- {
- "start": 51747,
- "end": 51758
- },
- {
- "attributes": {},
- "tag": "h3",
- "end": 51763,
- "start": 51758,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 51768,
- "start": 51763,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 51772,
- "start": 51768,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/DVD/DVD/6-/TopSellers.html"
- },
- "tag": "a",
- "end": 51810,
- "start": 51772,
- "tag_type": 1
- },
- {
- "start": 51810,
- "end": 51813
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 51817,
- "start": 51813,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 51822,
- "start": 51817,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 51826,
- "start": 51822,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Music/CD/6-/TopSellers.html"
- },
- "tag": "a",
- "end": 51865,
- "start": 51826,
- "tag_type": 1
- },
- {
- "start": 51865,
- "end": 51870
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 51874,
- "start": 51870,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 51879,
- "start": 51874,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 51883,
- "start": 51879,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Books/Books/6-/TopSellers.html"
- },
- "tag": "a",
- "end": 51925,
- "start": 51883,
- "tag_type": 1
- },
- {
- "start": 51925,
- "end": 51930
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 51934,
- "start": 51930,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 51939,
- "start": 51934,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 51943,
- "start": 51939,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Tickets/TicketsEvent/6-/TopSellers.html"
- },
- "tag": "a",
- "end": 51994,
- "start": 51943,
- "tag_type": 1
- },
- {
- "start": 51994,
- "end": 52001
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 52005,
- "start": 52001,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52010,
- "start": 52005,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52014,
- "start": 52010,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Books/AudioBooks/6-/TopSellers.html"
- },
- "tag": "a",
- "end": 52061,
- "start": 52014,
- "tag_type": 1
- },
- {
- "start": 52061,
- "end": 52071
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 52075,
- "start": 52071,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52080,
- "start": 52075,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52084,
- "start": 52080,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Books/Calendars/6-/TopSellers.html"
- },
- "tag": "a",
- "end": 52130,
- "start": 52084,
- "tag_type": 1
- },
- {
- "start": 52130,
- "end": 52139
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 52143,
- "start": 52139,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52148,
- "start": 52143,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52152,
- "start": 52148,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Games/Xbox/6-/TopSellers.html"
- },
- "tag": "a",
- "end": 52193,
- "start": 52152,
- "tag_type": 1
- },
- {
- "start": 52193,
- "end": 52203
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 52207,
- "start": 52203,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52212,
- "start": 52207,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52216,
- "start": 52212,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Games/DS/6-/TopSellers.html"
- },
- "tag": "a",
- "end": 52255,
- "start": 52216,
- "tag_type": 1
- },
- {
- "start": 52255,
- "end": 52263
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 52267,
- "start": 52263,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52272,
- "start": 52267,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52276,
- "start": 52272,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Games/PlayStation2/6-/TopSellers.html"
- },
- "tag": "a",
- "end": 52325,
- "start": 52276,
- "tag_type": 1
- },
- {
- "start": 52325,
- "end": 52334
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 52338,
- "start": 52334,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52343,
- "start": 52338,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52347,
- "start": 52343,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Games/GameBoyAdvanced/6-/TopSellers.html"
- },
- "tag": "a",
- "end": 52399,
- "start": 52347,
- "tag_type": 1
- },
- {
- "start": 52399,
- "end": 52408
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 52412,
- "start": 52408,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52417,
- "start": 52412,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52421,
- "start": 52417,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Games/GameCube/6-/TopSellers.html"
- },
- "tag": "a",
- "end": 52466,
- "start": 52421,
- "tag_type": 1
- },
- {
- "start": 52466,
- "end": 52480
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 52484,
- "start": 52480,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52489,
- "start": 52484,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52493,
- "start": 52489,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Games/PC/6-/TopSellers.html"
- },
- "tag": "a",
- "end": 52532,
- "start": 52493,
- "tag_type": 1
- },
- {
- "start": 52532,
- "end": 52540
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 52544,
- "start": 52540,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52549,
- "start": 52544,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 52554,
- "start": 52549,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52559,
- "start": 52554,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52563,
- "start": 52559,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/6-/PreOrderChart.html"
- },
- "tag": "a",
- "end": 52620,
- "start": 52563,
- "tag_type": 1
- },
- {
- "start": 52620,
- "end": 52631
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 52635,
- "start": 52631,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 52639,
- "start": 52635,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "charts-comingsoon"
- },
- "tag": "li",
- "end": 52669,
- "start": 52639,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "h3",
- "end": 52673,
- "start": 52669,
- "tag_type": 1
- },
- {
- "start": 52673,
- "end": 52684
- },
- {
- "attributes": {},
- "tag": "h3",
- "end": 52689,
- "start": 52684,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52694,
- "start": 52689,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52698,
- "start": 52694,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/DVD/DVD/6-/PreOrderChart.html"
- },
- "tag": "a",
- "end": 52739,
- "start": 52698,
- "tag_type": 1
- },
- {
- "start": 52739,
- "end": 52742
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 52746,
- "start": 52742,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52751,
- "start": 52746,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52755,
- "start": 52751,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Music/CD/6-/PreOrderChart.html"
- },
- "tag": "a",
- "end": 52797,
- "start": 52755,
- "tag_type": 1
- },
- {
- "start": 52797,
- "end": 52802
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 52806,
- "start": 52802,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52811,
- "start": 52806,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52815,
- "start": 52811,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Music/MP3-Download/6-/PreOrderChart.html"
- },
- "tag": "a",
- "end": 52867,
- "start": 52815,
- "tag_type": 1
- },
- {
- "start": 52867,
- "end": 52884
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 52888,
- "start": 52884,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52893,
- "start": 52888,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52897,
- "start": 52893,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Music/MP3-Download-Album/6-/PreOrderChart.html"
- },
- "tag": "a",
- "end": 52955,
- "start": 52897,
- "tag_type": 1
- },
- {
- "start": 52955,
- "end": 52974
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 52978,
- "start": 52974,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52983,
- "start": 52978,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 52987,
- "start": 52983,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Music/MP3-Download-Track/6-/PreOrderChart.html"
- },
- "tag": "a",
- "end": 53045,
- "start": 52987,
- "tag_type": 1
- },
- {
- "start": 53045,
- "end": 53064
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 53068,
- "start": 53064,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53073,
- "start": 53068,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53077,
- "start": 53073,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Books/Books/6-/PreOrderChart.html"
- },
- "tag": "a",
- "end": 53122,
- "start": 53077,
- "tag_type": 1
- },
- {
- "start": 53122,
- "end": 53127
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 53131,
- "start": 53127,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53136,
- "start": 53131,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53140,
- "start": 53136,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Books/AudioBooks/6-/PreOrderChart.html"
- },
- "tag": "a",
- "end": 53190,
- "start": 53140,
- "tag_type": 1
- },
- {
- "start": 53190,
- "end": 53200
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 53204,
- "start": 53200,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53209,
- "start": 53204,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53213,
- "start": 53209,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Books/Calendars/6-/PreOrderChart.html"
- },
- "tag": "a",
- "end": 53262,
- "start": 53213,
- "tag_type": 1
- },
- {
- "start": 53262,
- "end": 53271
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 53275,
- "start": 53271,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53280,
- "start": 53275,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53284,
- "start": 53280,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Games/Xbox/6-/PreOrderChart.html"
- },
- "tag": "a",
- "end": 53328,
- "start": 53284,
- "tag_type": 1
- },
- {
- "start": 53328,
- "end": 53338
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 53342,
- "start": 53338,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53347,
- "start": 53342,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53351,
- "start": 53347,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Games/Xbox360/6-/PreOrderChart.html"
- },
- "tag": "a",
- "end": 53398,
- "start": 53351,
- "tag_type": 1
- },
- {
- "start": 53398,
- "end": 53412
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 53416,
- "start": 53412,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53421,
- "start": 53416,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53425,
- "start": 53421,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Games/PlayStation2/6-/PreOrderChart.html"
- },
- "tag": "a",
- "end": 53477,
- "start": 53425,
- "tag_type": 1
- },
- {
- "start": 53477,
- "end": 53486
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 53490,
- "start": 53486,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53495,
- "start": 53490,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53499,
- "start": 53495,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Games/PSP/6-/PreOrderChart.html"
- },
- "tag": "a",
- "end": 53542,
- "start": 53499,
- "tag_type": 1
- },
- {
- "start": 53542,
- "end": 53551
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 53555,
- "start": 53551,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53560,
- "start": 53555,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53564,
- "start": 53560,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Games/DS/6-/PreOrderChart.html"
- },
- "tag": "a",
- "end": 53606,
- "start": 53564,
- "tag_type": 1
- },
- {
- "start": 53606,
- "end": 53614
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 53618,
- "start": 53614,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53623,
- "start": 53618,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53627,
- "start": 53623,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Games/GameBoyAdvanced/6-/PreOrderChart.html"
- },
- "tag": "a",
- "end": 53682,
- "start": 53627,
- "tag_type": 1
- },
- {
- "start": 53682,
- "end": 53691
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 53695,
- "start": 53691,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53700,
- "start": 53695,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53704,
- "start": 53700,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Games/GameCube/6-/PreOrderChart.html"
- },
- "tag": "a",
- "end": 53752,
- "start": 53704,
- "tag_type": 1
- },
- {
- "start": 53752,
- "end": 53766
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 53770,
- "start": 53766,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53775,
- "start": 53770,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53779,
- "start": 53775,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Games/PC/6-/PreOrderChart.html"
- },
- "tag": "a",
- "end": 53821,
- "start": 53779,
- "tag_type": 1
- },
- {
- "start": 53821,
- "end": 53829
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 53833,
- "start": 53829,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53838,
- "start": 53833,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53842,
- "start": 53838,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Gadgets/Gadgets/6-/PreOrderChart.html"
- },
- "tag": "a",
- "end": 53891,
- "start": 53842,
- "tag_type": 1
- },
- {
- "start": 53891,
- "end": 53898
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 53902,
- "start": 53898,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53907,
- "start": 53902,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 53912,
- "start": 53907,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53917,
- "start": 53912,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 53921,
- "start": 53917,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/6-/RecentReleases.html"
- },
- "tag": "a",
- "end": 53979,
- "start": 53921,
- "tag_type": 1
- },
- {
- "start": 53979,
- "end": 53994
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 53998,
- "start": 53994,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 54002,
- "start": 53998,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "charts-newreleases"
- },
- "tag": "li",
- "end": 54033,
- "start": 54002,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "h3",
- "end": 54037,
- "start": 54033,
- "tag_type": 1
- },
- {
- "start": 54037,
- "end": 54049
- },
- {
- "attributes": {},
- "tag": "h3",
- "end": 54054,
- "start": 54049,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54059,
- "start": 54054,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54063,
- "start": 54059,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/DVD/DVD/6-/RecentReleases.html"
- },
- "tag": "a",
- "end": 54105,
- "start": 54063,
- "tag_type": 1
- },
- {
- "start": 54105,
- "end": 54108
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 54112,
- "start": 54108,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54117,
- "start": 54112,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54121,
- "start": 54117,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Music/CD/6-/RecentReleases.html"
- },
- "tag": "a",
- "end": 54164,
- "start": 54121,
- "tag_type": 1
- },
- {
- "start": 54164,
- "end": 54169
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 54173,
- "start": 54169,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54178,
- "start": 54173,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54182,
- "start": 54178,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Books/Books/6-/RecentReleases.html"
- },
- "tag": "a",
- "end": 54228,
- "start": 54182,
- "tag_type": 1
- },
- {
- "start": 54228,
- "end": 54233
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 54237,
- "start": 54233,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54242,
- "start": 54237,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54246,
- "start": 54242,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Books/AudioBooks/6-/RecentReleases.html"
- },
- "tag": "a",
- "end": 54297,
- "start": 54246,
- "tag_type": 1
- },
- {
- "start": 54297,
- "end": 54307
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 54311,
- "start": 54307,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54316,
- "start": 54311,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54320,
- "start": 54316,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Games/Xbox/6-/RecentReleases.html"
- },
- "tag": "a",
- "end": 54365,
- "start": 54320,
- "tag_type": 1
- },
- {
- "start": 54365,
- "end": 54375
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 54379,
- "start": 54375,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54384,
- "start": 54379,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54388,
- "start": 54384,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Games/PlayStation2/6-/RecentReleases.html"
- },
- "tag": "a",
- "end": 54441,
- "start": 54388,
- "tag_type": 1
- },
- {
- "start": 54441,
- "end": 54450
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 54454,
- "start": 54450,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54459,
- "start": 54454,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54463,
- "start": 54459,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Games/GameBoyAdvanced/6-/RecentReleases.html"
- },
- "tag": "a",
- "end": 54519,
- "start": 54463,
- "tag_type": 1
- },
- {
- "start": 54519,
- "end": 54528
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 54532,
- "start": 54528,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54537,
- "start": 54532,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54541,
- "start": 54537,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Games/GameCube/6-/RecentReleases.html"
- },
- "tag": "a",
- "end": 54590,
- "start": 54541,
- "tag_type": 1
- },
- {
- "start": 54590,
- "end": 54604
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 54608,
- "start": 54604,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54613,
- "start": 54608,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54617,
- "start": 54613,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Games/PC/6-/RecentReleases.html"
- },
- "tag": "a",
- "end": 54660,
- "start": 54617,
- "tag_type": 1
- },
- {
- "start": 54660,
- "end": 54668
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 54672,
- "start": 54668,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54677,
- "start": 54672,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54681,
- "start": 54677,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Gadgets/Gadgets/6-/RecentReleases.html"
- },
- "tag": "a",
- "end": 54731,
- "start": 54681,
- "tag_type": 1
- },
- {
- "start": 54731,
- "end": 54738
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 54742,
- "start": 54738,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54747,
- "start": 54742,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 54752,
- "start": 54747,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54757,
- "start": 54752,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54761,
- "start": 54757,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/-/8986420/Samsung-Series-5-550-37-LE37B550-HD-1080p-Freeview-LCD-TV/Product.html?searchtype=genre"
- },
- "tag": "a",
- "end": 54904,
- "start": 54761,
- "tag_type": 1
- },
- {
- "start": 54904,
- "end": 54911
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 54915,
- "start": 54911,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 54919,
- "start": 54915,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "charts-top100"
- },
- "tag": "li",
- "end": 54945,
- "start": 54919,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "h3",
- "end": 54949,
- "start": 54945,
- "tag_type": 1
- },
- {
- "start": 54949,
- "end": 54956
- },
- {
- "attributes": {},
- "tag": "h3",
- "end": 54961,
- "start": 54956,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54966,
- "start": 54961,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 54970,
- "start": 54966,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/DVD/DVD/6-/Top100.html"
- },
- "tag": "a",
- "end": 55004,
- "start": 54970,
- "tag_type": 1
- },
- {
- "start": 55004,
- "end": 55007
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 55011,
- "start": 55007,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55016,
- "start": 55011,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55020,
- "start": 55016,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Music/CD/6-/Top100.html"
- },
- "tag": "a",
- "end": 55055,
- "start": 55020,
- "tag_type": 1
- },
- {
- "start": 55055,
- "end": 55060
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 55064,
- "start": 55060,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55069,
- "start": 55064,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55073,
- "start": 55069,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Games/Xbox/6-/Top100.html"
- },
- "tag": "a",
- "end": 55110,
- "start": 55073,
- "tag_type": 1
- },
- {
- "start": 55110,
- "end": 55120
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 55124,
- "start": 55120,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55129,
- "start": 55124,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55133,
- "start": 55129,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Games/PlayStation2/6-/Top100.html"
- },
- "tag": "a",
- "end": 55178,
- "start": 55133,
- "tag_type": 1
- },
- {
- "start": 55178,
- "end": 55187
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 55191,
- "start": 55187,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55196,
- "start": 55191,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55200,
- "start": 55196,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Games/GameBoyAdvanced/6-/Top100.html"
- },
- "tag": "a",
- "end": 55248,
- "start": 55200,
- "tag_type": 1
- },
- {
- "start": 55248,
- "end": 55257
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 55261,
- "start": 55257,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55266,
- "start": 55261,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55270,
- "start": 55266,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Games/GameCube/6-/Top100.html"
- },
- "tag": "a",
- "end": 55311,
- "start": 55270,
- "tag_type": 1
- },
- {
- "start": 55311,
- "end": 55325
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 55329,
- "start": 55325,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55334,
- "start": 55329,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55338,
- "start": 55334,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Games/PC/6-/Top100.html"
- },
- "tag": "a",
- "end": 55373,
- "start": 55338,
- "tag_type": 1
- },
- {
- "start": 55373,
- "end": 55381
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 55385,
- "start": 55381,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55390,
- "start": 55385,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 55395,
- "start": 55390,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 55400,
- "start": 55395,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 55405,
- "start": 55400,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 55411,
- "start": 55405,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 55417,
- "start": 55411,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "help wrap"
- },
- "tag": "div",
- "end": 55441,
- "start": 55417,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "boxhead"
- },
- "tag": "div",
- "end": 55462,
- "start": 55441,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 55467,
- "start": 55462,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 55472,
- "start": 55467,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 55476,
- "start": 55472,
- "tag_type": 1
- },
- {
- "start": 55476,
- "end": 55489
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 55494,
- "start": 55489,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 55500,
- "start": 55494,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 55506,
- "start": 55500,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 55512,
- "start": 55506,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "box"
- },
- "tag": "div",
- "end": 55529,
- "start": 55512,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/HOME/HOME/6-/Help.html?page=helpdesk",
- "title": "Play.com Helpdesk"
- },
- "tag": "a",
- "end": 55603,
- "start": 55529,
- "tag_type": 1
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteCSS/Play/Live1/img/brand/helpdesk.gif",
- "style": "border-style:None;height:56px;width:163px;border-width:0px;",
- "title": "Play.com Helpdesk"
- },
- "tag": "img",
- "end": 55775,
- "start": 55603,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 55779,
- "start": 55775,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 55785,
- "start": 55779,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 55791,
- "start": 55785,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "sidebanner wrap"
- },
- "tag": "div",
- "end": 55820,
- "start": 55791,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 55825,
- "start": 55820,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/8821116/-/Product.html?page=title&dpr=0",
- "manual_cm_re": "Left-_-SideBanner1-_-ELEC_freeAlbumDownload_double.jpg"
- },
- "tag": "a",
- "end": 55977,
- "start": 55825,
- "tag_type": 1
- },
- {
- "attributes": {
- "src": "http://images.play.com/PROMOTIONAL_IMAGES/SIDE_BANNERS/253462.jpg",
- "alt": "Free album download - Double",
- "style": "border-width:0px;"
- },
- "tag": "img",
- "end": 56117,
- "start": 55977,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 56121,
- "start": 56117,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 56127,
- "start": 56121,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 56133,
- "start": 56127,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "sidebanner wrap"
- },
- "tag": "div",
- "end": 56162,
- "start": 56133,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 56167,
- "start": 56162,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Campaign.html?campaign=6453&cid=2839989&dpr=0",
- "manual_cm_sp": "ELEC_SonyHeadphones.jpg-_-LeftSideBanner3-_-ELEC",
- "manual_cm_re": "Left-_-SideBanner3-_-ELEC_SonyHeadphones.jpg"
- },
- "tag": "a",
- "end": 56352,
- "start": 56167,
- "tag_type": 1
- },
- {
- "attributes": {
- "src": "http://images.play.com/PROMOTIONAL_IMAGES/SIDE_BANNERS/208001.jpg",
- "alt": "Sony Headphones",
- "style": "border-width:0px;"
- },
- "tag": "img",
- "end": 56479,
- "start": 56352,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 56483,
- "start": 56479,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 56489,
- "start": 56483,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 56495,
- "start": 56489,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "sidebanner wrap"
- },
- "tag": "div",
- "end": 56524,
- "start": 56495,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 56529,
- "start": 56524,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/3-/255882/2-/Promo.html?dpr=255882",
- "manual_cm_sp": "ELEC_ToshibaDVD_GBP.jpg_GBP-_-LeftSideBanner4-_-ELEC",
- "manual_cm_re": "Left-_-SideBanner4-_-ELEC_ToshibaDVD_GBP.jpg_GBP"
- },
- "tag": "a",
- "end": 56731,
- "start": 56529,
- "tag_type": 1
- },
- {
- "attributes": {
- "src": "http://images.play.com/PROMOTIONAL_IMAGES/SIDE_BANNERS/181202_GBP.jpg",
- "alt": "Toshiba DVD Players",
- "style": "border-width:0px;"
- },
- "tag": "img",
- "end": 56866,
- "start": 56731,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 56870,
- "start": 56866,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 56876,
- "start": 56870,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 56882,
- "start": 56876,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "sidebanner wrap"
- },
- "tag": "div",
- "end": 56911,
- "start": 56882,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 56916,
- "start": 56911,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/3-/166828/2-/Promo.html?dpr=166828",
- "manual_cm_sp": "ELEC_LogitechRemotes.gif-_-LeftSideBanner5-_-ELEC",
- "manual_cm_re": "Left-_-SideBanner5-_-ELEC_LogitechRemotes.gif"
- },
- "tag": "a",
- "end": 57112,
- "start": 56916,
- "tag_type": 1
- },
- {
- "attributes": {
- "src": "http://images.play.com/PROMOTIONAL_IMAGES/SIDE_BANNERS/218403.gif",
- "alt": "Logitech Remotes",
- "style": "border-width:0px;"
- },
- "tag": "img",
- "end": 57240,
- "start": 57112,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 57244,
- "start": 57240,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 57250,
- "start": 57244,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 57256,
- "start": 57250,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "playstores wrap"
- },
- "tag": "div",
- "end": 57286,
- "start": 57256,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "boxhead"
- },
- "tag": "div",
- "end": 57307,
- "start": 57286,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 57312,
- "start": 57307,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 57317,
- "start": 57312,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 57321,
- "start": 57317,
- "tag_type": 1
- },
- {
- "start": 57321,
- "end": 57332
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 57337,
- "start": 57332,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 57343,
- "start": 57337,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 57349,
- "start": 57343,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 57355,
- "start": 57349,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "box"
- },
- "tag": "div",
- "end": 57372,
- "start": 57355,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 57377,
- "start": 57372,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/HOME/HOME/6-/Campaign.html?campaign=6383&cid=5044118"
- },
- "tag": "a",
- "end": 57441,
- "start": 57377,
- "tag_type": 1
- },
- {
- "attributes": {
- "src": "http://images.play.com/newimages/store_disney.gif",
- "style": "border-width:0px;"
- },
- "tag": "img",
- "end": 57530,
- "start": 57441,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 57534,
- "start": 57530,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 57540,
- "start": 57534,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 57545,
- "start": 57540,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/6-/Campaign.html?campaign=2450&cid=9602708"
- },
- "tag": "a",
- "end": 57623,
- "start": 57545,
- "tag_type": 1
- },
- {
- "attributes": {
- "src": "http://images.play.com/newimages/store_sony.gif",
- "style": "border-width:0px;"
- },
- "tag": "img",
- "end": 57710,
- "start": 57623,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 57714,
- "start": 57710,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 57720,
- "start": 57714,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 57725,
- "start": 57720,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/HOME/HOME/6-/Campaign.html?campaign=621&cid=6096431"
- },
- "tag": "a",
- "end": 57788,
- "start": 57725,
- "tag_type": 1
- },
- {
- "attributes": {
- "src": "http://images.play.com/newimages/store_dummies.gif",
- "style": "border-width:0px;"
- },
- "tag": "img",
- "end": 57878,
- "start": 57788,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 57882,
- "start": 57878,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 57888,
- "start": 57882,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 57893,
- "start": 57888,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/HOME/HOME/6-/Campaign.html?campaign=6001&cid=3425819"
- },
- "tag": "a",
- "end": 57957,
- "start": 57893,
- "tag_type": 1
- },
- {
- "attributes": {
- "src": "http://images.play.com/newimages/store_nintendo.jpg",
- "style": "border-width:0px;"
- },
- "tag": "img",
- "end": 58048,
- "start": 57957,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 58052,
- "start": 58048,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 58058,
- "start": 58052,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 58063,
- "start": 58058,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/HOME/HOME/6-/Campaign.html?campaign=2030&cid=6256562"
- },
- "tag": "a",
- "end": 58127,
- "start": 58063,
- "tag_type": 1
- },
- {
- "attributes": {
- "src": "http://images.play.com/newimages/ea_store.gif",
- "style": "border-width:0px;"
- },
- "tag": "img",
- "end": 58212,
- "start": 58127,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 58216,
- "start": 58212,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 58222,
- "start": 58216,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 58227,
- "start": 58222,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/HOME/HOME/6-/Campaign.html?campaign=2720&cid=6896143"
- },
- "tag": "a",
- "end": 58291,
- "start": 58227,
- "tag_type": 1
- },
- {
- "attributes": {
- "src": "http://images.play.com/newimages/store_hbo.gif",
- "style": "border-width:0px;"
- },
- "tag": "img",
- "end": 58377,
- "start": 58291,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 58381,
- "start": 58377,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 58387,
- "start": 58381,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 58393,
- "start": 58387,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 58399,
- "start": 58393,
- "tag_type": 2
- },
- {
- "start": 58399,
- "end": 58407
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 58413,
- "start": 58407,
- "tag_type": 2
- },
- {
- "start": 58413,
- "end": 58417
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 58423,
- "start": 58417,
- "tag_type": 2
- },
- {
- "start": 58423,
- "end": 58427
- },
- {
- "attributes": {
- "class": "clear"
- },
- "tag": "div",
- "end": 58446,
- "start": 58427,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 58452,
- "start": 58446,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 58458,
- "start": 58452,
- "tag_type": 2
- },
- {
- "start": 58458,
- "end": 58478
- },
- {
- "attributes": {
- "id": "rightCol"
- },
- "tag": "div",
- "end": 58497,
- "start": 58478,
- "tag_type": 1
- },
- {
- "start": 58497,
- "end": 58521
- },
- {
- "attributes": {
- "class": "column"
- },
- "tag": "div",
- "end": 58541,
- "start": 58521,
- "tag_type": 1
- },
- {
- "start": 58541,
- "end": 58561
- },
- {
- "attributes": {
- "class": "shortbanner wrap"
- },
- "tag": "div",
- "end": 58591,
- "start": 58561,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 58596,
- "start": 58591,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/campaign.aspx?campaign=6688&cid=5685422&dpr=0",
- "manual_cm_sp": "ELEC_valpak.jpg-_-RightShortBanner1-_-ELEC",
- "manual_cm_re": "Right-_-ShortBanner1-_-ELEC_valpak.jpg"
- },
- "tag": "a",
- "end": 58769,
- "start": 58596,
- "tag_type": 1
- },
- {
- "attributes": {
- "src": "http://images.play.com/PROMOTIONAL_IMAGES/SHORT_BANNERS/220656.jpg",
- "alt": "Valpak - short banner",
- "style": "border-width:0px;"
- },
- "tag": "img",
- "end": 58903,
- "start": 58769,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 58907,
- "start": 58903,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 58913,
- "start": 58907,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 58919,
- "start": 58913,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "shortbanner wrap"
- },
- "tag": "div",
- "end": 58949,
- "start": 58919,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 58954,
- "start": 58949,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/3-/2074/2-/Promo.html?dpr=2074",
- "manual_cm_sp": "ELEC_I-Pod-Speakers.jpg-_-RightShortBanner2-_-ELEC",
- "manual_cm_re": "Right-_-ShortBanner2-_-ELEC_I-Pod-Speakers.jpg"
- },
- "tag": "a",
- "end": 59148,
- "start": 58954,
- "tag_type": 1
- },
- {
- "attributes": {
- "src": "http://images.play.com/PROMOTIONAL_IMAGES/SHORT_BANNERS/10287.jpg",
- "alt": "iPod speakers Save Up To 50%",
- "style": "border-width:0px;"
- },
- "tag": "img",
- "end": 59288,
- "start": 59148,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 59292,
- "start": 59288,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 59298,
- "start": 59292,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 59304,
- "start": 59298,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "countdown wrap"
- },
- "tag": "div",
- "end": 59333,
- "start": 59304,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "boxhead"
- },
- "tag": "div",
- "end": 59354,
- "start": 59333,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 59359,
- "start": 59354,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 59364,
- "start": 59359,
- "tag_type": 1
- },
- {
- "start": 59364,
- "end": 59368
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/3-/CountDownList.html?searchtype=genre"
- },
- "tag": "a",
- "end": 59452,
- "start": 59368,
- "tag_type": 1
- },
- {
- "start": 59452,
- "end": 59460
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 59464,
- "start": 59460,
- "tag_type": 1
- },
- {
- "start": 59464,
- "end": 59473
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 59478,
- "start": 59473,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 59482,
- "start": 59478,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 59488,
- "start": 59482,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 59494,
- "start": 59488,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 59500,
- "start": 59494,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "box"
- },
- "tag": "div",
- "end": 59517,
- "start": 59500,
- "tag_type": 1
- },
- {
- "attributes": {
- "cellspacing": "0"
- },
- "tag": "table",
- "end": 59540,
- "start": 59517,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 59544,
- "start": 59540,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 59548,
- "start": 59544,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "image"
- },
- "tag": "div",
- "end": 59567,
- "start": 59548,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/-/8839534/Sony-Bravia-S-Series-26-26S5500-HD-Ready-Freeview-Widescreen-LCD-TV/Product.html?searchtype=genre"
- },
- "tag": "a",
- "end": 59720,
- "start": 59567,
- "tag_type": 1
- },
- {
- "attributes": {
- "onerror": null,
- "src": "http://images.play.com/covers/8839534s.jpg",
- "alt": "Sony Bravia S Series 26" 26S5500 HD Ready Freeview Widescreen LCD TV",
- "style": "height:60px;width:60px;border-width:0px;",
- "class": "sideimageline"
- },
- "tag": "img",
- "end": 60003,
- "start": 59720,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 60007,
- "start": 60003,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 60013,
- "start": 60007,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 60018,
- "start": 60013,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 60022,
- "start": 60018,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "days"
- },
- "tag": "div",
- "end": 60040,
- "start": 60022,
- "tag_type": 1
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteCSS/Play/Live1/img/countdown/28.gif",
- "style": "border-width:0px;",
- "border": "0"
- },
- "tag": "img",
- "end": 60153,
- "start": 60040,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 60159,
- "start": 60153,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 60164,
- "start": 60159,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 60169,
- "start": 60164,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 60173,
- "start": 60169,
- "tag_type": 1
- },
- {
- "attributes": {
- "colspan": "2"
- },
- "tag": "td",
- "end": 60187,
- "start": 60173,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "h5",
- "end": 60191,
- "start": 60187,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/-/8839534/Sony-Bravia-S-Series-26-26S5500-HD-Ready-Freeview-Widescreen-LCD-TV/Product.html?searchtype=genre"
- },
- "tag": "a",
- "end": 60344,
- "start": 60191,
- "tag_type": 1
- },
- {
- "start": 60344,
- "end": 60417
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 60421,
- "start": 60417,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "h5",
- "end": 60426,
- "start": 60421,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 60431,
- "start": 60426,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 60436,
- "start": 60431,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 60440,
- "start": 60436,
- "tag_type": 1
- },
- {
- "attributes": {
- "colspan": "2"
- },
- "tag": "td",
- "end": 60454,
- "start": 60440,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "h6",
- "end": 60458,
- "start": 60454,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "h6",
- "end": 60462,
- "start": 60458,
- "tag_type": 1
- },
- {
- "start": 60462,
- "end": 60474
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 60480,
- "start": 60474,
- "tag_type": 1
- },
- {
- "start": 60480,
- "end": 60494
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 60501,
- "start": 60494,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "h6",
- "end": 60506,
- "start": 60501,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "h6",
- "end": 60511,
- "start": 60506,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 60516,
- "start": 60511,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 60521,
- "start": 60516,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "table",
- "end": 60529,
- "start": 60521,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "more"
- },
- "tag": "p",
- "end": 60545,
- "start": 60529,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/3-/CountDownList.html?searchtype=genre"
- },
- "tag": "a",
- "end": 60629,
- "start": 60545,
- "tag_type": 1
- },
- {
- "start": 60629,
- "end": 60638
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 60644,
- "start": 60638,
- "tag_type": 1
- },
- {
- "start": 60644,
- "end": 60645
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 60652,
- "start": 60645,
- "tag_type": 2
- },
- {
- "start": 60652,
- "end": 60653
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 60657,
- "start": 60653,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 60661,
- "start": 60657,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 60667,
- "start": 60661,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 60673,
- "start": 60667,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "topsellers wrap"
- },
- "tag": "div",
- "end": 60703,
- "start": 60673,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "boxhead"
- },
- "tag": "div",
- "end": 60724,
- "start": 60703,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 60729,
- "start": 60724,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 60734,
- "start": 60729,
- "tag_type": 1
- },
- {
- "start": 60734,
- "end": 60738
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/3-/TopSellers.html?searchtype=genre"
- },
- "tag": "a",
- "end": 60819,
- "start": 60738,
- "tag_type": 1
- },
- {
- "start": 60819,
- "end": 60827
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 60831,
- "start": 60827,
- "tag_type": 1
- },
- {
- "start": 60831,
- "end": 60854
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 60859,
- "start": 60854,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 60863,
- "start": 60859,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 60869,
- "start": 60863,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 60875,
- "start": 60869,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 60881,
- "start": 60875,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "box"
- },
- "tag": "div",
- "end": 60898,
- "start": 60881,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "ol",
- "end": 60902,
- "start": 60898,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 60906,
- "start": 60902,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/8839538/Sony-Bravia-S-Series-32-32S5500-HD-Ready-Freeview-Widescreen-LCD-TV/Product.html",
- "class": "chart01",
- "title": "Price: \u00a3379.99 Free Delivery"
- },
- "tag": "a",
- "end": 61086,
- "start": 60906,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "title"
- },
- "tag": "span",
- "end": 61106,
- "start": 61086,
- "tag_type": 1
- },
- {
- "start": 61106,
- "end": 61212
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 61219,
- "start": 61212,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 61223,
- "start": 61219,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 61228,
- "start": 61223,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 61232,
- "start": 61228,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/8986397/Samsung-Series-4-450-32-LE32B450-HD-Ready-Freeview-LCD-TV/Product.html",
- "class": "chart02",
- "title": "Price: \u00a3334.99 Free Delivery"
- },
- "tag": "a",
- "end": 61402,
- "start": 61232,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "title"
- },
- "tag": "span",
- "end": 61422,
- "start": 61402,
- "tag_type": 1
- },
- {
- "start": 61422,
- "end": 61499
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 61506,
- "start": 61499,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 61510,
- "start": 61506,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 61515,
- "start": 61510,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 61519,
- "start": 61515,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/9159265/Humax-FoxSat-HDR-Freesat-320GB-HDD-DTR-HD-Recorder/Product.html",
- "class": "chart03",
- "title": "Price: \u00a3249.99 Free Delivery"
- },
- "tag": "a",
- "end": 61682,
- "start": 61519,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "title"
- },
- "tag": "span",
- "end": 61702,
- "start": 61682,
- "tag_type": 1
- },
- {
- "start": 61702,
- "end": 61752
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 61759,
- "start": 61752,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 61763,
- "start": 61759,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 61768,
- "start": 61763,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 61772,
- "start": 61768,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/6904657/Vivanco-Universal-Sky-Remote-Control-Sky-Sky+/Product.html",
- "class": "chart04",
- "title": "Price: \u00a34.99 Free Delivery"
- },
- "tag": "a",
- "end": 61928,
- "start": 61772,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "title"
- },
- "tag": "span",
- "end": 61948,
- "start": 61928,
- "tag_type": 1
- },
- {
- "start": 61948,
- "end": 61995
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 62002,
- "start": 61995,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 62006,
- "start": 62002,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 62011,
- "start": 62006,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 62015,
- "start": 62011,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/5985149/Synn-LTS4201-B-Glass-Stand-for-TVs-Up-To-42-/Product.html",
- "class": "chart05",
- "title": "Price: \u00a399.99 Free Delivery"
- },
- "tag": "a",
- "end": 62171,
- "start": 62015,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "title"
- },
- "tag": "span",
- "end": 62191,
- "start": 62171,
- "tag_type": 1
- },
- {
- "start": 62191,
- "end": 62257
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 62264,
- "start": 62257,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 62268,
- "start": 62264,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 62273,
- "start": 62268,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 62277,
- "start": 62273,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/9404087/LG-22-M227WD-HD-1080p-Freeview-Widescreen-LCD-TV/Product.html",
- "class": "chart06",
- "title": "Price: \u00a3199.99 Free Delivery"
- },
- "tag": "a",
- "end": 62438,
- "start": 62277,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "title"
- },
- "tag": "span",
- "end": 62458,
- "start": 62438,
- "tag_type": 1
- },
- {
- "start": 62458,
- "end": 62512
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 62519,
- "start": 62512,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 62523,
- "start": 62519,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 62528,
- "start": 62523,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 62532,
- "start": 62528,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/1112311/Linx-1-2m-Luxury-24k-Gold-Plated-HDMI-Cable/Product.html",
- "class": "chart07",
- "title": "Price: \u00a38.99 Free Delivery"
- },
- "tag": "a",
- "end": 62686,
- "start": 62532,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "title"
- },
- "tag": "span",
- "end": 62706,
- "start": 62686,
- "tag_type": 1
- },
- {
- "start": 62706,
- "end": 62750
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 62757,
- "start": 62750,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 62761,
- "start": 62757,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 62766,
- "start": 62761,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 62770,
- "start": 62766,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/5447796/Samsung-20-T200-HD-Ready-Freeview-Widescreen-LCD-TV/Product.html",
- "class": "chart08",
- "title": "Price: \u00a3169.99 Free Delivery"
- },
- "tag": "a",
- "end": 62934,
- "start": 62770,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "title"
- },
- "tag": "span",
- "end": 62954,
- "start": 62934,
- "tag_type": 1
- },
- {
- "start": 62954,
- "end": 63031
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 63038,
- "start": 63031,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 63042,
- "start": 63038,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 63047,
- "start": 63042,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 63051,
- "start": 63047,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/3271416/Linx-TVM021-TV-Stand-Up-To-37-/Product.html",
- "class": "chart09",
- "title": "Price: \u00a329.99 Free Delivery"
- },
- "tag": "a",
- "end": 63193,
- "start": 63051,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "title"
- },
- "tag": "span",
- "end": 63213,
- "start": 63193,
- "tag_type": 1
- },
- {
- "start": 63213,
- "end": 63248
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 63255,
- "start": 63248,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 63259,
- "start": 63255,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 63264,
- "start": 63259,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 63268,
- "start": 63264,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/9481062/Toshiba-Regza-AV-Series-32-32AV615DB-HD-Ready-Freeview-LCD-TV/Product.html",
- "class": "chart10",
- "title": "Price: \u00a3339.99 Free Delivery"
- },
- "tag": "a",
- "end": 63442,
- "start": 63268,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "title"
- },
- "tag": "span",
- "end": 63462,
- "start": 63442,
- "tag_type": 1
- },
- {
- "start": 63462,
- "end": 63581
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 63588,
- "start": 63581,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 63592,
- "start": 63588,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 63597,
- "start": 63592,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "ol",
- "end": 63602,
- "start": 63597,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "more"
- },
- "tag": "p",
- "end": 63618,
- "start": 63602,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/3-/TopSellers.html?searchtype=genre"
- },
- "tag": "a",
- "end": 63699,
- "start": 63618,
- "tag_type": 1
- },
- {
- "start": 63699,
- "end": 63716
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 63722,
- "start": 63716,
- "tag_type": 1
- },
- {
- "start": 63722,
- "end": 63728
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 63735,
- "start": 63728,
- "tag_type": 2
- },
- {
- "start": 63735,
- "end": 63736
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 63740,
- "start": 63736,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 63744,
- "start": 63740,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 63750,
- "start": 63744,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 63756,
- "start": 63750,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "comingsoon wrap"
- },
- "tag": "div",
- "end": 63786,
- "start": 63756,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "boxhead"
- },
- "tag": "div",
- "end": 63807,
- "start": 63786,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 63812,
- "start": 63807,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 63817,
- "start": 63812,
- "tag_type": 1
- },
- {
- "start": 63817,
- "end": 63821
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/3-/ComingSoon.html?searchtype=genre"
- },
- "tag": "a",
- "end": 63902,
- "start": 63821,
- "tag_type": 1
- },
- {
- "start": 63902,
- "end": 63910
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 63914,
- "start": 63910,
- "tag_type": 1
- },
- {
- "start": 63914,
- "end": 63925
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 63930,
- "start": 63925,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 63934,
- "start": 63930,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 63940,
- "start": 63934,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 63946,
- "start": 63940,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 63952,
- "start": 63946,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "box"
- },
- "tag": "div",
- "end": 63969,
- "start": 63952,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 63973,
- "start": 63969,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 63977,
- "start": 63973,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/10502045/Accessory-Agents-10-37-Low-Profile-Wall-Bracket/Product.html",
- "class": "arrow",
- "title": "Price: \u00a314.99 Free Delivery"
- },
- "tag": "a",
- "end": 64135,
- "start": 63977,
- "tag_type": 1
- },
- {
- "start": 64135,
- "end": 64196
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 64200,
- "start": 64196,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 64205,
- "start": 64200,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 64209,
- "start": 64205,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/8839704/Sony-Bravia-Z-Series-40-40Z5500-HD-1080p-Freeview-Widescreen-LCD-TV/Product.html",
- "class": "arrow",
- "title": "Price: \u00a31399.99 Free Delivery"
- },
- "tag": "a",
- "end": 64388,
- "start": 64209,
- "tag_type": 1
- },
- {
- "start": 64388,
- "end": 64494
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 64498,
- "start": 64494,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 64503,
- "start": 64498,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 64507,
- "start": 64503,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/8839534/Sony-Bravia-S-Series-26-26S5500-HD-Ready-Freeview-Widescreen-LCD-TV/Product.html",
- "class": "arrow",
- "title": "Price: \u00a3399.99 Free Delivery"
- },
- "tag": "a",
- "end": 64685,
- "start": 64507,
- "tag_type": 1
- },
- {
- "start": 64685,
- "end": 64758
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 64762,
- "start": 64758,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 64767,
- "start": 64762,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 64771,
- "start": 64767,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/10772232/Samsung-22-LE22B350-Widescreen-LCD-TV/Product.html",
- "class": "arrow",
- "title": "Price: \u00a3199.99 Free Delivery"
- },
- "tag": "a",
- "end": 64920,
- "start": 64771,
- "tag_type": 1
- },
- {
- "start": 64920,
- "end": 64963
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 64967,
- "start": 64963,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 64972,
- "start": 64967,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 64976,
- "start": 64972,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/8839719/Sony-Bravia-Z-Series-52-52Z5500-HD-1080p-Freeview-Widescreen-LCD-TV/Product.html",
- "class": "arrow",
- "title": "Price: \u00a32199.99 Free Delivery"
- },
- "tag": "a",
- "end": 65155,
- "start": 64976,
- "tag_type": 1
- },
- {
- "start": 65155,
- "end": 65261
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 65265,
- "start": 65261,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 65270,
- "start": 65265,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 65274,
- "start": 65270,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/9223463/Panasonic-Viera-NeoPDP-G15-Series-46-TX-P46G15-HD-1080p-Freesat-Freeview-Plasma-TV/Product.html",
- "class": "arrow",
- "title": "Price: \u00a31299.99 Free Delivery"
- },
- "tag": "a",
- "end": 65468,
- "start": 65274,
- "tag_type": 1
- },
- {
- "start": 65468,
- "end": 65562
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 65566,
- "start": 65562,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 65571,
- "start": 65566,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 65575,
- "start": 65571,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/10333427/Samsung-Series-7-7020-32-UE32B7020-HD-1080p-Freeview-Ultra-Slim-LED-TV/Product.html",
- "class": "arrow",
- "title": "Price: \u00a3999.99 Free Delivery"
- },
- "tag": "a",
- "end": 65757,
- "start": 65575,
- "tag_type": 1
- },
- {
- "start": 65757,
- "end": 65856
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 65860,
- "start": 65856,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 65865,
- "start": 65860,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 65869,
- "start": 65865,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/9924416/Toshiba-DV-Series-19-DV616DB-HD-Ready-Freeview-Integrated-DVD-LCD-TV/Product.html",
- "class": "arrow",
- "title": "Price: \u00a3269.99 Free Delivery"
- },
- "tag": "a",
- "end": 66048,
- "start": 65869,
- "tag_type": 1
- },
- {
- "start": 66048,
- "end": 66136
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 66140,
- "start": 66136,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 66145,
- "start": 66140,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 66149,
- "start": 66145,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/9769759/Toshiba-Regza-ZV-Series-42-42ZV635-HD-1080p-Freeview-LCD-TV/Product.html",
- "class": "arrow",
- "title": "Price: \u00a3899.99 Free Delivery"
- },
- "tag": "a",
- "end": 66319,
- "start": 66149,
- "tag_type": 1
- },
- {
- "start": 66319,
- "end": 66388
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 66392,
- "start": 66388,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 66397,
- "start": 66392,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 66401,
- "start": 66397,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/4-/10772167/Samsung-Series-5-530-32-LE32B530-HD-1080p-Freeview-LCD-TV/Product.html",
- "class": "arrow",
- "title": "Price: \u00a3449.99 Free Delivery"
- },
- "tag": "a",
- "end": 66570,
- "start": 66401,
- "tag_type": 1
- },
- {
- "start": 66570,
- "end": 66637
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 66641,
- "start": 66637,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "li",
- "end": 66646,
- "start": 66641,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "ul",
- "end": 66651,
- "start": 66646,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "more"
- },
- "tag": "p",
- "end": 66667,
- "start": 66651,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/-/318/404/3-/ComingSoon.html?searchtype=genre"
- },
- "tag": "a",
- "end": 66748,
- "start": 66667,
- "tag_type": 1
- },
- {
- "start": 66748,
- "end": 66760
- },
- {
- "attributes": {
- "class": "orangepanel"
- },
- "tag": "span",
- "end": 66786,
- "start": 66760,
- "tag_type": 1
- },
- {
- "start": 66786,
- "end": 66787
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 66794,
- "start": 66787,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 66798,
- "start": 66794,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 66802,
- "start": 66798,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 66808,
- "start": 66802,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 66814,
- "start": 66808,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "sidebanner wrap"
- },
- "tag": "div",
- "end": 66843,
- "start": 66814,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 66848,
- "start": 66843,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/DVD/Blu-ray/6-/Campaign.html?campaign=7147&cid=1528342&dpr=0",
- "manual_cm_sp": "BLU_blu-ray_month_from799_doubles_GBP.jpg_GBP-_-RightSideBanner1-_-ELEC",
- "manual_cm_re": "Right-_-SideBanner1-_-BLU_blu-ray_month_from799_doubles_GBP.jpg_GBP"
- },
- "tag": "a",
- "end": 67094,
- "start": 66848,
- "tag_type": 1
- },
- {
- "attributes": {
- "src": "http://images.play.com/PROMOTIONAL_IMAGES/SIDE_BANNERS/249662_GBP.jpg",
- "alt": "Blu-ray from \u00a37.99",
- "style": "border-width:0px;"
- },
- "tag": "img",
- "end": 67228,
- "start": 67094,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 67232,
- "start": 67228,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 67238,
- "start": 67232,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 67244,
- "start": 67238,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "sidebanner wrap"
- },
- "tag": "div",
- "end": 67273,
- "start": 67244,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 67278,
- "start": 67273,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/3-/301482/2-/Promo.html?dpr=301482",
- "manual_cm_sp": "ELEC_SonyLCDTVs_GBP.gif_GBP-_-RightSideBanner2-_-ELEC",
- "manual_cm_re": "Right-_-SideBanner2-_-ELEC_SonyLCDTVs_GBP.gif_GBP"
- },
- "tag": "a",
- "end": 67482,
- "start": 67278,
- "tag_type": 1
- },
- {
- "attributes": {
- "src": "http://images.play.com/PROMOTIONAL_IMAGES/SIDE_BANNERS/225463_GBP.gif",
- "alt": "Sony LCD TV's - Double",
- "style": "border-width:0px;"
- },
- "tag": "img",
- "end": 67620,
- "start": 67482,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 67624,
- "start": 67620,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 67630,
- "start": 67624,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 67636,
- "start": 67630,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "sidebanner wrap"
- },
- "tag": "div",
- "end": 67665,
- "start": 67636,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 67670,
- "start": 67665,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/3-/255083/2-/Promo.html?dpr=255083",
- "manual_cm_sp": "ELEC_Blu-ray-Players_GBP.jpg_GBP-_-RightSideBanner3-_-ELEC",
- "manual_cm_re": "Right-_-SideBanner3-_-ELEC_Blu-ray-Players_GBP.jpg_GBP"
- },
- "tag": "a",
- "end": 67884,
- "start": 67670,
- "tag_type": 1
- },
- {
- "attributes": {
- "src": "http://images.play.com/PROMOTIONAL_IMAGES/SIDE_BANNERS/181200_GBP.jpg",
- "alt": "Blu-ray players from \u00a3199.99",
- "style": "border-width:0px;"
- },
- "tag": "img",
- "end": 68028,
- "start": 67884,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 68032,
- "start": 68028,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 68038,
- "start": 68032,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 68044,
- "start": 68038,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "sidebanner wrap"
- },
- "tag": "div",
- "end": 68073,
- "start": 68044,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 68078,
- "start": 68073,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Electronics/Electronics/3-/351362/2-/Promo.html?dpr=351362",
- "manual_cm_sp": "ELEC_Flip_GBP.gif_GBP-_-RightSideBanner4-_-ELEC",
- "manual_cm_re": "Right-_-SideBanner4-_-ELEC_Flip_GBP.gif_GBP"
- },
- "tag": "a",
- "end": 68270,
- "start": 68078,
- "tag_type": 1
- },
- {
- "attributes": {
- "src": "http://images.play.com/PROMOTIONAL_IMAGES/SIDE_BANNERS/250490_GBP.gif",
- "alt": "Flip Camcorders - From Only \u00a379.99",
- "style": "border-width:0px;"
- },
- "tag": "img",
- "end": 68420,
- "start": 68270,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 68424,
- "start": 68420,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 68430,
- "start": 68424,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 68436,
- "start": 68430,
- "tag_type": 2
- },
- {
- "start": 68436,
- "end": 68456
- },
- {
- "attributes": {
- "class": "secureshopping wrap"
- },
- "tag": "div",
- "end": 68490,
- "start": 68456,
- "tag_type": 1
- },
- {
- "attributes": {
- "class": "boxhead"
- },
- "tag": "div",
- "end": 68511,
- "start": 68490,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 68516,
- "start": 68511,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 68521,
- "start": 68516,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 68525,
- "start": 68521,
- "tag_type": 1
- },
- {
- "start": 68525,
- "end": 68540
- },
- {
- "attributes": {},
- "tag": "h2",
- "end": 68545,
- "start": 68540,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 68551,
- "start": 68545,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 68557,
- "start": 68551,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 68563,
- "start": 68557,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "box"
- },
- "tag": "div",
- "end": 68580,
- "start": 68563,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "javascript:siteseal()",
- "border": "0"
- },
- "tag": "a",
- "end": 68623,
- "start": 68580,
- "tag_type": 1
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteCSS/Play/Live1/img/brand/verisign.gif",
- "border": "0",
- "width": "94",
- "height": "52"
- },
- "tag": "img",
- "end": 68733,
- "start": 68623,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 68737,
- "start": 68733,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 68743,
- "start": 68737,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 68749,
- "start": 68743,
- "tag_type": 2
- },
- {
- "start": 68749,
- "end": 68769
- },
- {
- "attributes": {
- "class": "sidebanner wrap"
- },
- "tag": "div",
- "end": 68798,
- "start": 68769,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 68803,
- "start": 68798,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/HOME/HOME/6-/GiftVouchers.html?dpr=0",
- "manual_cm_sp": "giftvoucher_sb.jpg-_-SideBanner1-_-ELEC",
- "manual_cm_re": "-_-SideBanner1-_-giftvoucher_sb.jpg"
- },
- "tag": "a",
- "end": 68957,
- "start": 68803,
- "tag_type": 1
- },
- {
- "attributes": {
- "src": "http://images.play.com/PROMOTIONAL_IMAGES/SIDE_BANNERS/229863.jpg",
- "alt": "Buy Gift Vouchers",
- "style": "border-width:0px;"
- },
- "tag": "img",
- "end": 69086,
- "start": 68957,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 69090,
- "start": 69086,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 69096,
- "start": 69090,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 69102,
- "start": 69096,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "sidebanner wrap"
- },
- "tag": "div",
- "end": 69131,
- "start": 69102,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 69136,
- "start": 69131,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/Campaign.html?campaign=6748&cid=5106868&dpr=0",
- "manual_cm_sp": "ccard_sb.jpg-_-SideBanner2-_-ELEC",
- "manual_cm_re": "-_-SideBanner2-_-ccard_sb.jpg"
- },
- "tag": "a",
- "end": 69291,
- "start": 69136,
- "tag_type": 1
- },
- {
- "attributes": {
- "src": "http://images.play.com/PROMOTIONAL_IMAGES/SIDE_BANNERS/238668.jpg",
- "alt": "Play.com Credit Card",
- "style": "border-width:0px;"
- },
- "tag": "img",
- "end": 69423,
- "start": 69291,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 69427,
- "start": 69423,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 69433,
- "start": 69427,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 69439,
- "start": 69433,
- "tag_type": 2
- },
- {
- "start": 69439,
- "end": 69463
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 69469,
- "start": 69463,
- "tag_type": 2
- },
- {
- "start": 69469,
- "end": 69489
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 69495,
- "start": 69489,
- "tag_type": 2
- },
- {
- "start": 69495,
- "end": 69515
- },
- {
- "attributes": {
- "class": "clear"
- },
- "tag": "div",
- "end": 69534,
- "start": 69515,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 69540,
- "start": 69534,
- "tag_type": 2
- },
- {
- "start": 69540,
- "end": 69560
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 69566,
- "start": 69560,
- "tag_type": 2
- },
- {
- "start": 69566,
- "end": 69574
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 69580,
- "start": 69574,
- "tag_type": 2
- },
- {
- "start": 69580,
- "end": 69584
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 69590,
- "start": 69584,
- "tag_type": 2
- },
- {
- "start": 69590,
- "end": 69598
- },
- {
- "attributes": {
- "type": "text/javascript",
- "language": "JavaScript"
- },
- "tag": "script",
- "end": 69651,
- "start": 69598,
- "tag_type": 1
- },
- {
- "start": 69651,
- "end": 69675
- },
- {
- "attributes": {},
- "tag": "script",
- "end": 69684,
- "start": 69675,
- "tag_type": 2
- },
- {
- "start": 69684,
- "end": 69692
- },
- {
- "attributes": {
- "class": "footer"
- },
- "tag": "div",
- "end": 69712,
- "start": 69692,
- "tag_type": 1
- },
- {
- "start": 69712,
- "end": 69720
- },
- {
- "attributes": {
- "class": "links"
- },
- "tag": "p",
- "end": 69737,
- "start": 69720,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/"
- },
- "tag": "a",
- "end": 69749,
- "start": 69737,
- "tag_type": 1
- },
- {
- "start": 69749,
- "end": 69753
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 69757,
- "start": 69753,
- "tag_type": 2
- },
- {
- "start": 69757,
- "end": 69770
- },
- {
- "attributes": {
- "href": "/DVD/DVD/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 69808,
- "start": 69770,
- "tag_type": 1
- },
- {
- "start": 69808,
- "end": 69811
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 69815,
- "start": 69811,
- "tag_type": 2
- },
- {
- "start": 69815,
- "end": 69828
- },
- {
- "attributes": {
- "href": "/DVD/Blu-ray/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 69870,
- "start": 69828,
- "tag_type": 1
- },
- {
- "start": 69870,
- "end": 69877
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 69881,
- "start": 69877,
- "tag_type": 2
- },
- {
- "start": 69881,
- "end": 69894
- },
- {
- "attributes": {
- "href": "/Music/CD/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 69933,
- "start": 69894,
- "tag_type": 1
- },
- {
- "start": 69933,
- "end": 69938
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 69942,
- "start": 69938,
- "tag_type": 2
- },
- {
- "start": 69942,
- "end": 69955
- },
- {
- "attributes": {
- "href": "/Tickets/TicketsEvent/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 70006,
- "start": 69955,
- "tag_type": 1
- },
- {
- "start": 70006,
- "end": 70013
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 70017,
- "start": 70013,
- "tag_type": 2
- },
- {
- "start": 70017,
- "end": 70030
- },
- {
- "attributes": {
- "href": "/Games/Games/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 70072,
- "start": 70030,
- "tag_type": 1
- },
- {
- "start": 70072,
- "end": 70077
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 70081,
- "start": 70077,
- "tag_type": 2
- },
- {
- "start": 70081,
- "end": 70094
- },
- {
- "attributes": {
- "href": "/Books/Books/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 70136,
- "start": 70094,
- "tag_type": 1
- },
- {
- "start": 70136,
- "end": 70141
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 70145,
- "start": 70141,
- "tag_type": 2
- },
- {
- "start": 70145,
- "end": 70158
- },
- {
- "attributes": {
- "href": "/Clothing/Clothing/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 70206,
- "start": 70158,
- "tag_type": 1
- },
- {
- "start": 70206,
- "end": 70214
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 70218,
- "start": 70214,
- "tag_type": 2
- },
- {
- "start": 70218,
- "end": 70231
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 70239,
- "start": 70231,
- "tag_type": 1
- },
- {
- "start": 70239,
- "end": 70250
- },
- {
- "attributes": {},
- "tag": "strong",
- "end": 70259,
- "start": 70250,
- "tag_type": 2
- },
- {
- "start": 70259,
- "end": 70272
- },
- {
- "attributes": {
- "href": "/PC/PCs/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 70309,
- "start": 70272,
- "tag_type": 1
- },
- {
- "start": 70309,
- "end": 70318
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 70322,
- "start": 70318,
- "tag_type": 2
- },
- {
- "start": 70322,
- "end": 70335
- },
- {
- "attributes": {
- "href": "/Gadgets/Gadgets/6-/RegionHome.html"
- },
- "tag": "a",
- "end": 70381,
- "start": 70335,
- "tag_type": 1
- },
- {
- "start": 70381,
- "end": 70388
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 70392,
- "start": 70388,
- "tag_type": 2
- },
- {
- "start": 70392,
- "end": 70405
- },
- {
- "attributes": {
- "href": "/Mobiles/Mobile/6-/MobileHome.html"
- },
- "tag": "a",
- "end": 70450,
- "start": 70405,
- "tag_type": 1
- },
- {
- "start": 70450,
- "end": 70456
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 70460,
- "start": 70456,
- "tag_type": 2
- },
- {
- "start": 70460,
- "end": 70473
- },
- {
- "attributes": {
- "href": "/HOME/HOME/6-/LandingPage.html?page=playtrade"
- },
- "tag": "a",
- "end": 70529,
- "start": 70473,
- "tag_type": 1
- },
- {
- "start": 70529,
- "end": 70544
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 70548,
- "start": 70544,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 70552,
- "start": 70548,
- "tag_type": 2
- },
- {
- "start": 70552,
- "end": 70560
- },
- {
- "attributes": {
- "class": "cards"
- },
- "tag": "div",
- "end": 70579,
- "start": 70560,
- "tag_type": 1
- },
- {
- "start": 70579,
- "end": 70600
- },
- {
- "attributes": {
- "cellpadding": "0"
- },
- "tag": "table",
- "end": 70623,
- "start": 70600,
- "tag_type": 1
- },
- {
- "start": 70623,
- "end": 70635
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 70642,
- "start": 70635,
- "tag_type": 1
- },
- {
- "start": 70642,
- "end": 70658
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 70662,
- "start": 70658,
- "tag_type": 1
- },
- {
- "start": 70662,
- "end": 70682
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 70686,
- "start": 70682,
- "tag_type": 1
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteCSS/Play/Live1/img/footer/cards.gif",
- "alt": "We accept these cards: Delta, MasterCard, Solo, Switch, Maestro, Visa, Electron",
- "style": "border-width:0px;"
- },
- "tag": "img",
- "end": 70874,
- "start": 70686,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 70879,
- "start": 70874,
- "tag_type": 2
- },
- {
- "start": 70879,
- "end": 70899
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 70903,
- "start": 70899,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/HOME/HOME/6-/Campaign.html?campaign=6748&cid=5106868",
- "title": "Play.com Credit Card"
- },
- "tag": "a",
- "end": 70996,
- "start": 70903,
- "tag_type": 1
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteCSS/Play/Live1/img/footer/play-credit-cards.gif",
- "alt": "Play.com Credit Card",
- "style": "border-width:0px;"
- },
- "tag": "img",
- "end": 71137,
- "start": 70996,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 71141,
- "start": 71137,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 71146,
- "start": 71141,
- "tag_type": 2
- },
- {
- "start": 71146,
- "end": 71162
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 71167,
- "start": 71162,
- "tag_type": 2
- },
- {
- "start": 71167,
- "end": 71179
- },
- {
- "attributes": {},
- "tag": "tbody",
- "end": 71187,
- "start": 71179,
- "tag_type": 2
- },
- {
- "start": 71187,
- "end": 71195
- },
- {
- "attributes": {},
- "tag": "table",
- "end": 71203,
- "start": 71195,
- "tag_type": 2
- },
- {
- "start": 71203,
- "end": 71207
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 71213,
- "start": 71207,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "contact"
- },
- "tag": "div",
- "end": 71234,
- "start": 71213,
- "tag_type": 1
- },
- {
- "attributes": {
- "cellspacing": "0"
- },
- "tag": "table",
- "end": 71257,
- "start": 71234,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 71261,
- "start": 71257,
- "tag_type": 1
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 71265,
- "start": 71261,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/HOME/HOME/6-/Help.html?page=helpdesk",
- "title": "Play.com Helpdesk"
- },
- "tag": "a",
- "end": 71339,
- "start": 71265,
- "tag_type": 1
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteCSS/Play/Live1/img/footer/helpdesk.gif",
- "alt": "Play.com Helpdesk",
- "style": "border-width:0px;"
- },
- "tag": "img",
- "end": 71468,
- "start": 71339,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 71472,
- "start": 71468,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 71477,
- "start": 71472,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 71481,
- "start": 71477,
- "tag_type": 1
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteCSS/Play/Live1/img/footer/pipe.gif",
- "style": "height:32px;width:23px;border-width:0px;"
- },
- "tag": "img",
- "end": 71605,
- "start": 71481,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 71610,
- "start": 71605,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 71614,
- "start": 71610,
- "tag_type": 1
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteCSS/Play/Live1/img/footer/phone.gif",
- "alt": "Customer Services: 0845 800 1020",
- "style": "border-width:0px;"
- },
- "tag": "img",
- "end": 71755,
- "start": 71614,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "td",
- "end": 71760,
- "start": 71755,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "tr",
- "end": 71765,
- "start": 71760,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "table",
- "end": 71773,
- "start": 71765,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 71779,
- "start": 71773,
- "tag_type": 2
- },
- {
- "attributes": {
- "class": "legal"
- },
- "tag": "p",
- "end": 71796,
- "start": 71779,
- "tag_type": 1
- },
- {
- "attributes": {
- "href": "/HOME/HOME/6-/Help.html?page=priv"
- },
- "tag": "a",
- "end": 71840,
- "start": 71796,
- "tag_type": 1
- },
- {
- "start": 71840,
- "end": 71854
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 71858,
- "start": 71854,
- "tag_type": 2
- },
- {
- "start": 71858,
- "end": 71861
- },
- {
- "attributes": {
- "href": "/HOME/HOME/6-/Help.html?page=terms"
- },
- "tag": "a",
- "end": 71906,
- "start": 71861,
- "tag_type": 1
- },
- {
- "start": 71906,
- "end": 71928
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 71932,
- "start": 71928,
- "tag_type": 2
- },
- {
- "start": 71932,
- "end": 71935
- },
- {
- "attributes": {
- "style": "color: #000;"
- },
- "tag": "span",
- "end": 71962,
- "start": 71935,
- "tag_type": 1
- },
- {
- "start": 71962,
- "end": 71997
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 72004,
- "start": 71997,
- "tag_type": 2
- },
- {
- "start": 72004,
- "end": 72007
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 72013,
- "start": 72007,
- "tag_type": 1
- },
- {
- "start": 72013,
- "end": 72033
- },
- {
- "attributes": {},
- "tag": "span",
- "end": 72040,
- "start": 72033,
- "tag_type": 2
- },
- {
- "start": 72040,
- "end": 72041
- },
- {
- "attributes": {
- "href": "http://www.PlayUSA.com"
- },
- "tag": "a",
- "end": 72074,
- "start": 72041,
- "tag_type": 1
- },
- {
- "start": 72074,
- "end": 72075
- },
- {
- "attributes": {
- "src": "http://images.play.com/SiteCSS/Play/Live1/img/footer/playincorporated.gif",
- "alt": "Play Incorporated",
- "style": "height:16px;width:55px;border-width:0px;"
- },
- "tag": "img",
- "end": 72235,
- "start": 72075,
- "tag_type": 3
- },
- {
- "attributes": {},
- "tag": "a",
- "end": 72239,
- "start": 72235,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "p",
- "end": 72243,
- "start": 72239,
- "tag_type": 2
- },
- {
- "start": 72243,
- "end": 72251
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 72257,
- "start": 72251,
- "tag_type": 2
- },
- {
- "start": 72257,
- "end": 72301
- },
- {
- "attributes": {},
- "tag": "div",
- "end": 72307,
- "start": 72301,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "body",
- "end": 72314,
- "start": 72307,
- "tag_type": 2
- },
- {
- "attributes": {},
- "tag": "html",
- "end": 72321,
- "start": 72314,
- "tag_type": 2
- },
- {
- "start": 72321,
- "end": 72325
- }
-]
diff --git a/scrapy/tests/test_contrib_ibl/samples/samples_pageparsing_0.html b/scrapy/tests/test_contrib_ibl/samples/samples_pageparsing_0.html
deleted file mode 100644
index 6851f009a..000000000
--- a/scrapy/tests/test_contrib_ibl/samples/samples_pageparsing_0.html
+++ /dev/null
@@ -1,632 +0,0 @@
-
-
-
-TEMPUR Deluxe-HD™ Mattress | Tempur
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
To get your Free Information Pack
click here
-
-
-
Testimonials
-
My husband and I just spent our first night on our new TEMPUR Mattress, and we are thrilled at the terrific night's rest we both had.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- *Term & Conditions
- *FAQ 60Night
- © 2008 TEMPUR UK Ltd. All Rights Reserved
-
- . PRIVACY POLICY
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/scrapy/tests/test_contrib_ibl/samples/samples_pageparsing_0.json b/scrapy/tests/test_contrib_ibl/samples/samples_pageparsing_0.json
deleted file mode 100644
index b94b12faf..000000000
--- a/scrapy/tests/test_contrib_ibl/samples/samples_pageparsing_0.json
+++ /dev/null
@@ -1,78 +0,0 @@
-[
- {
- "surrounds_attribute": "name",
- "annotation_text": null,
- "match_common_prefix": false,
- "surrounds_variant": null,
- "variant_id": null,
- "tag_attributes": [],
- "end_index": 133,
- "start_index": 132,
- "metadata": {}
- },
- {
- "surrounds_attribute": null,
- "annotation_text": null,
- "match_common_prefix": false,
- "surrounds_variant": null,
- "variant_id": null,
- "tag_attributes": [
- [
- "src",
- "image_urls"
- ]
- ],
- "end_index": 142,
- "start_index": 141,
- "metadata": {}
- },
- {
- "surrounds_attribute": null,
- "annotation_text": null,
- "match_common_prefix": false,
- "surrounds_variant": null,
- "variant_id": null,
- "tag_attributes": [
- [
- "src",
- "image_urls"
- ]
- ],
- "end_index": 149,
- "start_index": 148,
- "metadata": {}
- },
- {
- "surrounds_attribute": "description",
- "annotation_text": null,
- "match_common_prefix": false,
- "surrounds_variant": null,
- "variant_id": null,
- "tag_attributes": [],
- "end_index": 207,
- "start_index": 161,
- "metadata": {}
- },
- {
- "surrounds_attribute": "price",
- "annotation_text": null,
- "match_common_prefix": false,
- "surrounds_variant": null,
- "variant_id": null,
- "tag_attributes": [],
- "end_index": 258,
- "start_index": 257,
- "metadata": {}
- },
- {
- "surrounds_attribute": "features",
- "annotation_text": null,
- "match_common_prefix": false,
- "surrounds_variant": null,
- "variant_id": null,
- "tag_attributes": [],
- "end_index": 421,
- "start_index": 324,
- "metadata": {}
- }
-]
diff --git a/scrapy/tests/test_contrib_ibl/test_extraction.py b/scrapy/tests/test_contrib_ibl/test_extraction.py
deleted file mode 100644
index f79c9dc78..000000000
--- a/scrapy/tests/test_contrib_ibl/test_extraction.py
+++ /dev/null
@@ -1,955 +0,0 @@
-"""
-tests for page parsing
-
-Page parsing effectiveness is measured through the evaluation system. These
-tests should focus on specific bits of functionality work correctly.
-"""
-from twisted.trial.unittest import TestCase, SkipTest
-from scrapy.contrib.ibl.htmlpage import HtmlPage
-from scrapy.contrib.ibl.descriptor import (FieldDescriptor as A,
- ItemDescriptor)
-from scrapy.contrib.ibl.extractors import (contains_any_numbers,
- image_url)
-
-try:
- import numpy
- __doctests__ = ['scrapy.contrib.ibl.extraction.%s' % x for x in \
- ['regionextract', 'similarity', 'pageobjects']]
-except ImportError:
- numpy = None
-
-if numpy:
- from scrapy.contrib.ibl.extraction import InstanceBasedLearningExtractor
-
-# simple page with all features
-
-ANNOTATED_PAGE1 = u"""
-
-COMPANY - Item Title
-introduction
-
-
-
-This is such a nice item Everybody likes it.
-
-
-
-click here for other items
-
-"""
-
-EXTRACT_PAGE1 = u"""
-
-Scrapy - Nice Product
-introduction
-
-
-
wonderful product
-
-
-
-"""
-
-# single tag with multiple items extracted
-ANNOTATED_PAGE2 = u"""
-xx
-xxx
-
-"""
-EXTRACT_PAGE2 = u"""product 1 is great """
-
-# matching must match the second attribute in order to find the first
-ANNOTATED_PAGE3 = u"""
-xx
-xx
-"""
-EXTRACT_PAGE3 = u"""
-description
-delivery
-this is not the description
-"""
-
-# test inferring repeated elements
-ANNOTATED_PAGE4 = u"""
-
-"""
-
-EXTRACT_PAGE4 = u"""
-
-feature1 ignore this
-feature2
-feature3
-
-"""
-
-# test variant handling with identical repeated variant
-ANNOTATED_PAGE5 = u"""
-description
-
-
-colour 1
-price 1
-
-
-colour 2
-price 2
-
-
-"""
-
-EXTRACT_PAGE5 = u"""
-description
-
-
-colour 1
-price 1
-
-
-colour 2
-price 2
-
-
-colour 3
-price 3
-
-
-"""
-
-# test variant handling with irregular structure and some non-variant
-# attributes
-ANNOTATED_PAGE6 = u"""
-description
-name 1
-name 3
-name 2
-"""
-EXTRACT_PAGE6 = u"""
-description
-name 1
-name 3
-name 2
-"""
-
-# test repeating variants at the table column level
-ANNOTATED_PAGE7 = u"""
-
-
-colour 1
-colour 2
-
-
-price 1
-price 2
-
-
-"""
-
-EXTRACT_PAGE7 = u"""
-
-
-colour 1
-colour 2
-colour 3
-
-
-price 1
-price 2
-price 3
-
-
-"""
-
-ANNOTATED_PAGE8 = u"""
-
-A product
-
-
-
-"""
-
-EXTRACT_PAGE8 = u"""
-
-A product
-
-
A very nice product for all intelligent people
-
-
-
-
-"""
-
-ANNOTATED_PAGE9 = ANNOTATED_PAGE8
-
-EXTRACT_PAGE9 = u"""
-
-
-A product
-
-
A very nice product for all intelligent people
-
-
-
-
-"""
-
-ANNOTATED_PAGE11 = u"""
-
-
-
-SL342
-
-
-Nice product for ladies
-
-£s;85.00
-
-
-
-£s;100.00
-
-
-"""
-
-EXTRACT_PAGE11 = u"""
-
-
-SL342
-
-Nice product for ladies
-
-£s;85.00
-
-£s;100.00
-
-"""
-
-ANNOTATED_PAGE12 = u"""
-
-A product
-
-
-"""
-
-EXTRACT_PAGE12a = u"""
-
-A product
-
-
A very nice product for all intelligent people
-
-
-12.00
ID 15
-(VAT exc.)
-
-
-"""
-
-EXTRACT_PAGE12b = u"""
-
-A product
-
-
A very nice product for all intelligent people
-
-
-12.00
ID 15
-(VAT exc.)
-
-
-Features
-Feature A
-Feature B
-
-
-
-"""
-
-# Ex1: nested annotation with token sequence replica outside exterior annotation
-# and a possible sequence pattern can be extracted only with
-# correct handling of nested annotations
-ANNOTATED_PAGE13a = u"""
-
-
-
-
-A product
-$50.00
-This product is excelent. Buy it!
-
-
-
-
-
See other products:
-Product b
-
-
-
-
-"""
-
-EXTRACT_PAGE13a = u"""
-
-
-
-
A product
-$50.00
-This product is excelent. Buy it!
-
-
-
-
-
-
See other products:
-Product B
-
-
-
-"""
-
-# Ex2: annotation with token sequence replica inside a previous nested annotation
-# and a possible sequence pattern can be extracted only with
-# correct handling of nested annotations
-ANNOTATED_PAGE13b = u"""
-
-
-
-
A product
-Previous price: $50.00
-This product is excelent. Buy it!
-
-
-
-
-
Save 10%!!
-$45.00
-
-
-
-"""
-
-EXTRACT_PAGE13b = u"""
-
-
-
-
A product
-$50.00
-This product is excelent. Buy it!
-
-
-
-
-
-
Save 10%!!
-$45.00
-
-
-
-
-"""
-
-ANNOTATED_PAGE14 = u"""
-
-
-
-
-"""
-
-EXTRACT_PAGE14 = u"""
-
-
-"""
-
-ANNOTATED_PAGE15 = u"""
-
-
-
-Description
-90.00
-
-
-"""
-
-EXTRACT_PAGE15 = u"""
-
-
-Description
-80.00
-
-
-"""
-
-ANNOTATED_PAGE16 = u"""
-
-
-Description
-
-name
-
-80.00
-
-
-"""
-
-EXTRACT_PAGE16 = u"""
-
-product name
-90.00
-
-"""
-
-ANNOTATED_PAGE17 = u"""
-
-
-
-This product is excelent. Buy it!
-
-
-
-
-
-See other products:
-Product b
-
-
-
-"""
-
-EXTRACT_PAGE17 = u"""
-
-
-
-This product is excelent. Buy it!
-
-
-
-
-See other products:
-Product B
-
-
-
-"""
-
-ANNOTATED_PAGE18 = u"""
-
-
-Item Id
-
-Description
-
-
-"""
-
-EXTRACT_PAGE18 = u"""
-
-
-Item Id
-
-Description
-
-
-"""
-
-ANNOTATED_PAGE19 = u"""
-
-
-
Product name
-
60.00
-
-
description
-
-
-"""
-
-EXTRACT_PAGE19a = u"""
-
-
-
Product name
-
60.00
-
-
description
-
-
-"""
-
-EXTRACT_PAGE19b = u"""
-
-
-
Range
-
from 20.00
-
-
-
-
-
-"""
-
-ANNOTATED_PAGE20 = u"""
-
-Product Name
-
-
-Twin : $270 - November 2010
-Queen : $330 - In stock
-
-
-"""
-
-EXTRACT_PAGE20 = u"""
-
-Product Name
-
-
-Twin: $270 - November 2010
-Queen: $330 - Movember 2010
-
-
-"""
-
-ANNOTATED_PAGE21 = u"""
-
-
-
-
-
-tables
-
-
-"""
-
-EXTRACT_PAGE21 = u"""
-
-
-
-
-
-chairs
-
-"""
-
-ANNOTATED_PAGE22 = u"""
-
-
-
-
-
-
-product 1
-$67
-
-
-
-
-product 2
-$70
-
-
-
-
-product 3
-$73
-
-
-
-
-product 4
-$80
-
-
-
-
-
-tables
-
-
-"""
-
-EXTRACT_PAGE22 = u"""
-
-
-
-
-
-
-product 1
-$70
-
-
-
-
-product 2
-$80
-
-
-
-
-product 3
-$90
-
-
-
-
-product 4
-$100
-
-
-
-
-
-chairs
-
-"""
-
-ANNOTATED_PAGE23 = u"""
-
-Product
-
-
-Variant 1560
-
-
-Variant 2570
-
-
-Variant 3580
-
-
-
-"""
-
-EXTRACT_PAGE23 = u"""
-
-Product
-
-
-Variant 1300
-
-
-Variant 2320
-
-
-Variant 3340
-
-
-
-"""
-
-SAMPLE_DESCRIPTOR1 = ItemDescriptor('test', 'product test', [
- A('name', "Product name", required=True),
- A('price', "Product price, including any discounts and tax or vat",
- contains_any_numbers, True),
- A('image_urls', "URLs for one or more images", image_url, True),
- A('description', "The full description of the product", allow_markup=True),
- ]
-)
-
-# A list of (test name, [templates], page, extractors, expected_result)
-TEST_DATA = [
- # extract from a similar page
- ('similar page extraction', [ANNOTATED_PAGE1], EXTRACT_PAGE1, None,
- {u'title': [u'Nice Product'], u'description': [u'wonderful product'],
- u'image_url': [u'nice_product.jpg']}
- ),
- # strip the first 5 characters from the title
- ('extractor test', [ANNOTATED_PAGE1], EXTRACT_PAGE1,
- ItemDescriptor('test', 'product test',
- [A('title', "something about a title", lambda x: x[5:])]),
- {u'title': [u'Product'], u'description': [u'wonderful product'],
- u'image_url': [u'nice_product.jpg']}
- ),
- # compilicated tag (multiple attributes and annotation)
- ('multiple attributes and annotation', [ANNOTATED_PAGE2], EXTRACT_PAGE2, None,
- {'name': [u'product 1'], 'image_url': [u'http://example.com/product1.jpg'],
- 'description': [u'product 1 is great']}
- ),
- # can only work out correct placement by matching the second attribute first
- ('ambiguous description', [ANNOTATED_PAGE3], EXTRACT_PAGE3, None,
- {'description': [u'description'], 'delivery': [u'delivery']}
- ),
- # infer a repeated structure
- ('repeated elements', [ANNOTATED_PAGE4], EXTRACT_PAGE4, None,
- {'features': [u'feature1', u'feature2', u'feature3']}
- ),
- # identical variants with a repeated structure
- ('repeated identical variants', [ANNOTATED_PAGE5], EXTRACT_PAGE5, None,
- {
- 'description': [u'description'],
- 'variants': [
- {u'colour': [u'colour 1'], u'price': [u'price 1']},
- {u'colour': [u'colour 2'], u'price': [u'price 2']},
- {u'colour': [u'colour 3'], u'price': [u'price 3']}
- ]
- }
- ),
- # variants with an irregular structure
- ('irregular variants', [ANNOTATED_PAGE6], EXTRACT_PAGE6, None,
- {
- 'description': [u'description'],
- 'variants': [
- {u'name': [u'name 1']},
- {u'name': [u'name 3']},
- {u'name': [u'name 2']}
- ]
- }
- ),
-
- # discovering repeated variants in table columns
-# ('variants in table columns', [ANNOTATED_PAGE7], EXTRACT_PAGE7, None,
-# {'variants': [
-# {u'colour': [u'colour 1'], u'price': [u'price 1']},
-# {u'colour': [u'colour 2'], u'price': [u'price 2']},
-# {u'colour': [u'colour 3'], u'price': [u'price 3']}
-# ]}
-# ),
-
-
- # ignored regions
- (
- 'ignored_regions', [ANNOTATED_PAGE8], EXTRACT_PAGE8, None,
- {
- 'description': [u'\n A very nice product for all intelligent people \n\n'],
- 'price': [u'\n12.00\n(VAT exc.)'],
- }
- ),
- # shifted ignored regions (detected by region similarity)
- (
- 'shifted_ignored_regions', [ANNOTATED_PAGE9], EXTRACT_PAGE9, None,
- {
- 'description': [u'\n A very nice product for all intelligent people \n\n'],
- 'price': [u'\n12.00\n(VAT exc.)'],
- }
- ),
- (# special case with partial annotations
- 'special_partial_annotation', [ANNOTATED_PAGE11], EXTRACT_PAGE11, None,
- {
- 'name': [u'SL342'],
- 'description': [u'\nSL342\n \nNice product for ladies\n \n£s;85.00\n'],
- 'price': [u'£s;85.00'],
- 'price_before_discount': [u'£s;100.00'],
- }
- ),
- (# with ignore-beneath feature
- 'ignore-beneath', [ANNOTATED_PAGE12], EXTRACT_PAGE12a, None,
- {
- 'description': [u'\n A very nice product for all intelligent people \n'],
- }
- ),
- (# ignore-beneath with extra tags
- 'ignore-beneath with extra tags', [ANNOTATED_PAGE12], EXTRACT_PAGE12b, None,
- {
- 'description': [u'\n A very nice product for all intelligent people \n'],
- }
- ),
- ('nested annotation with replica outside', [ANNOTATED_PAGE13a], EXTRACT_PAGE13a, None,
- {'description': [u'\n A product \n $50.00 \nThis product is excelent. Buy it!\n \n'],
- 'price': ["$50.00"],
- 'name': [u'A product']}
- ),
- ('outside annotation with nested replica', [ANNOTATED_PAGE13b], EXTRACT_PAGE13b, None,
- {'description': [u'\n A product \n $50.00 \nThis product is excelent. Buy it!\n'],
- 'price': ["$45.00"],
- 'name': [u'A product']}
- ),
- ('consistency check', [ANNOTATED_PAGE14], EXTRACT_PAGE14, None,
- {},
- ),
- ('consecutive nesting', [ANNOTATED_PAGE15], EXTRACT_PAGE15, None,
- {'description': [u'Description\n\n'],
- 'price': [u'80.00']},
- ),
- ('nested inside not found', [ANNOTATED_PAGE16], EXTRACT_PAGE16, None,
- {'price': [u'90.00'],
- 'name': [u'product name']},
- ),
- ('ignored region helps to find attributes', [ANNOTATED_PAGE17], EXTRACT_PAGE17, None,
- {'description': [u'\nThis product is excelent. Buy it!\n']},
- ),
- ('ignored region in partial annotation', [ANNOTATED_PAGE18], EXTRACT_PAGE18, None,
- {u'site_id': [u'Item Id'],
- u'description': [u'\nDescription\n']},
- ),
- ('extra required attribute product', [ANNOTATED_PAGE19], EXTRACT_PAGE19a,
- SAMPLE_DESCRIPTOR1,
- {u'price': [u'60.00'],
- u'description': [u'description'],
- u'image_urls': [['http://example.com/image.jpg']],
- u'name': [u'Product name']},
- ),
- ('extra required attribute no product', [ANNOTATED_PAGE19], EXTRACT_PAGE19b,
- SAMPLE_DESCRIPTOR1,
- None,
- ),
- ('repeated partial annotations with variants', [ANNOTATED_PAGE20], EXTRACT_PAGE20, None,
- {u'variants': [
- {'price': ['270'], 'name': ['Twin']},
- {'price': ['330'], 'name': ['Queen']},
- ]},
- ),
- ('variants with swatches', [ANNOTATED_PAGE21], EXTRACT_PAGE21, None,
- {u'category': [u'chairs'],
- u'image_urls': [u'image.jpg'],
- u'variants': [
- {'swatches': ['swatch1.jpg']},
- {'swatches': ['swatch2.jpg']},
- {'swatches': ['swatch3.jpg']},
- {'swatches': ['swatch4.jpg']},
- ]
- },
- ),
- ('variants with swatches complete', [ANNOTATED_PAGE22], EXTRACT_PAGE22, None,
- {u'category': [u'chairs'],
- u'variants': [
- {u'swatches': [u'swatch1.jpg'],
- u'price': [u'$70'],
- u'name': [u'product 1']},
- {u'swatches': [u'swatch2.jpg'],\
- u'price': [u'$80'],
- u'name': [u'product 2']},
- {u'swatches': [u'swatch3.jpg'],
- u'price': [u'$90'],
- u'name': [u'product 3']},
- {u'swatches': [u'swatch4.jpg'],
- u'price': [u'$100'],
- u'name': [u'product 4']}
- ],
- u'image_urls': [u'image.jpg']},
- ),
- ('repeated (variants) with ignore annotations', [ANNOTATED_PAGE23], EXTRACT_PAGE23, None,
- {'variants': [
- {u'price': [u'300'], u'name': [u'Variant 1']},
- {u'price': [u'320'], u'name': [u'Variant 2']},
- {u'price': [u'340'], u'name': [u'Variant 3']}
- ]},
- ),
-]
-
-class TestExtraction(TestCase):
-
- def setUp(self):
- if not numpy:
- raise SkipTest("numpy not available")
-
- def _run_extraction(self, name, templates, page, extractors, expected_output):
- self.trace = None
- template_pages = [HtmlPage(None, {}, t) for t in templates]
- extractor = InstanceBasedLearningExtractor(template_pages, extractors, True)
- actual_output, _ = extractor.extract(HtmlPage(None, {}, page))
- if not actual_output:
- if expected_output is None:
- return
- assert False, "failed to extract data for test '%s'" % name
- actual_output = actual_output[0]
- self.trace = ["Extractor:\n%s" % extractor] + actual_output.pop('trace', [])
- expected_names = set(expected_output.keys())
- actual_names = set(actual_output.keys())
-
- missing_in_output = filter(None, expected_names - actual_names)
- error = "attributes '%s' were expected but were not present in test '%s'" % \
- ("', '".join(missing_in_output), name)
- assert len(missing_in_output) == 0, error
-
- unexpected = actual_names - expected_names
- error = "unexpected attributes %s in test '%s'" % \
- (', '.join(unexpected), name)
- assert len(unexpected) == 0, error
-
- for k, v in expected_output.items():
- extracted = actual_output[k]
- assert v == extracted, "in test '%s' for attribute '%s', " \
- "expected value '%s' but got '%s'" % (name, k, v, extracted)
-
- def test_expected_outputs(self):
- try:
- for data in TEST_DATA:
- self._run_extraction(*data)
- except AssertionError:
- if self.trace:
- print "Trace:"
- for line in self.trace:
- print "\n---\n%s" % line
- raise
diff --git a/scrapy/tests/test_contrib_ibl/test_extractors.py b/scrapy/tests/test_contrib_ibl/test_extractors.py
deleted file mode 100644
index 16d8aa342..000000000
--- a/scrapy/tests/test_contrib_ibl/test_extractors.py
+++ /dev/null
@@ -1,5 +0,0 @@
-try:
- import numpy
- __doctests__ = ['scrapy.contrib.ibl.extractors']
-except ImportError:
- pass
diff --git a/scrapy/tests/test_contrib_ibl/test_htmlpage.py b/scrapy/tests/test_contrib_ibl/test_htmlpage.py
deleted file mode 100644
index cdba56853..000000000
--- a/scrapy/tests/test_contrib_ibl/test_htmlpage.py
+++ /dev/null
@@ -1,139 +0,0 @@
-"""
-htmlpage.py tests
-"""
-import os
-from unittest import TestCase
-
-from scrapy.utils.py26 import json
-from scrapy.tests.test_contrib_ibl import path
-from scrapy.contrib.ibl.htmlpage import parse_html, HtmlTag, HtmlDataFragment
-from scrapy.tests.test_contrib_ibl.test_htmlpage_data import *
-from scrapy.utils.python import unicode_to_str, str_to_unicode
-
-SAMPLES_FILE_PREFIX = os.path.join(path, "samples/samples_htmlpage")
-
-def _encode_element(el):
- """
- jsonize parse element
- """
- if isinstance(el, HtmlTag):
- return {"tag": el.tag, "attributes": el.attributes,
- "start": el.start, "end": el.end, "tag_type": el.tag_type}
- if isinstance(el, HtmlDataFragment):
- return {"start": el.start, "end": el.end}
- raise TypeError
-
-def _decode_element(dct):
- """
- dejsonize parse element
- """
- if "tag" in dct:
- return HtmlTag(dct["tag_type"], dct["tag"], \
- dct["attributes"], dct["start"], dct["end"])
- if "start" in dct:
- return HtmlDataFragment(dct["start"], dct["end"])
- return dct
-
-def add_sample(source):
- """
- Method for adding samples to test samples file
- (use from console)
- """
- count = 0
- while os.path.exists("%s_%d.json" % (SAMPLES_FILE_PREFIX, count)):
- count += 1
-
- open("%s_%d.html" % (SAMPLES_FILE_PREFIX, count), "wb").write(unicode_to_str(source))
- parsed = list(parse_html(source))
- open("%s_%d.json" % (SAMPLES_FILE_PREFIX, count), "wb")\
- .write(json.dumps(parsed, default=_encode_element, indent=8))
-
-class TestParseHtml(TestCase):
- """Test for parse_html"""
- def _test_sample(self, source, expected_parsed, samplecount=None):
- parsed = parse_html(source)
- count_element = 0
- count_expected = 0
- for element in parsed:
- if type(element) == HtmlTag:
- count_element += 1
- expected = expected_parsed.pop(0)
- if type(expected) == HtmlTag:
- count_expected += 1
- element_text = source[element.start:element.end]
- expected_text = source[expected.start:expected.end]
- if element.start != expected.start or element.end != expected.end:
- errstring = "[%s,%s] %s != [%s,%s] %s" % (element.start, \
- element.end, element_text, expected.start, \
- expected.end, expected_text)
- if samplecount is not None:
- errstring += " (sample %d)" % samplecount
- assert False, errstring
- if type(element) != type(expected):
- errstring = "(%s) %s != (%s) %s for text\n%s" % (count_element, \
- repr(type(element)), count_expected, repr(type(expected)), element_text)
- if samplecount is not None:
- errstring += " (sample %d)" % samplecount
- assert False, errstring
- if type(element) == HtmlTag:
- self.assertEqual(element.tag, expected.tag)
- self.assertEqual(element.attributes, expected.attributes)
- self.assertEqual(element.tag_type, expected.tag_type)
- if expected_parsed:
- errstring = "Expected %s" % repr(expected_parsed)
- if samplecount is not None:
- errstring += " (sample %d)" % samplecount
- assert False, errstring
-
- def test_parse(self):
- """simple parse_html test"""
- parsed = [_decode_element(d) for d in PARSED]
- sample = {"source": PAGE, "parsed": parsed}
- self._test_sample(PAGE, parsed)
-
- def test_site_samples(self):
- """test parse_html from real cases"""
- count = 0
- fname = "%s_%d.json" % (SAMPLES_FILE_PREFIX, count)
- while os.path.exists(fname):
- source = str_to_unicode(open("%s_%d.html" % (SAMPLES_FILE_PREFIX, count), "rb").read())
- parsed = json.loads(str_to_unicode(open(fname, "rb").read()),\
- object_hook=_decode_element)
- self._test_sample(source, parsed, count)
- count += 1
- fname = "%s_%d.json" % (SAMPLES_FILE_PREFIX, count)
-
- def test_bad(self):
- """test parsing of bad html layout"""
- parsed = [_decode_element(d) for d in PARSED2]
- self._test_sample(PAGE2, parsed)
-
- def test_comments(self):
- """test parsing of tags inside comments"""
- parsed = [_decode_element(d) for d in PARSED3]
- self._test_sample(PAGE3, parsed)
-
- def test_script_text(self):
- """test parsing of tags inside scripts"""
- parsed = [_decode_element(d) for d in PARSED4]
- self._test_sample(PAGE4, parsed)
-
- def test_sucessive(self):
- """test parsing of sucesive cleaned elements"""
- parsed = [_decode_element(d) for d in PARSED5]
- self._test_sample(PAGE5, parsed)
-
- def test_sucessive2(self):
- """test parsing of sucesive cleaned elements (variant 2)"""
- parsed = [_decode_element(d) for d in PARSED6]
- self._test_sample(PAGE6, parsed)
-
- def test_special_cases(self):
- """some special cases tests"""
- parsed = list(parse_html(" "))
- self.assertEqual(parsed[0].attributes, {'content': 'no-cache', 'http-equiv': 'Pragma'})
- parsed = list(parse_html(""))
- self.assertEqual(parsed[0].attributes, {'xmlns': 'http://www.w3.org/1999/xhtml', 'xml:lang': 'en', 'lang': 'en'})
- parsed = list(parse_html(" "))
- self.assertEqual(parsed[0].attributes, {'src': 'http://images.play.com/banners/SAM550a.jpg', \
- 'align': 'left', 'hspace': '5', '/': None})
diff --git a/scrapy/tests/test_contrib_ibl/test_htmlpage_data.py b/scrapy/tests/test_contrib_ibl/test_htmlpage_data.py
deleted file mode 100644
index 62cd6b526..000000000
--- a/scrapy/tests/test_contrib_ibl/test_htmlpage_data.py
+++ /dev/null
@@ -1,248 +0,0 @@
-PAGE = u"""
-
-
-