Failed to scrape data using scrapy

I tried to extract the corresponding matrices’ data into the following format from here via scrapy:

[[['1', '0', '0', '0'], ['0', '1', '0', '0'], ['0', '0', '1', '0']], [['0', '-1', '0', '0'], ['1', '-1', '0', '0'], ['0', '0', '1', '0']], [['-1', '0', '0', '0'], ['0', '-1', '0', '0'], ['0', '0', '1', '1/2']], [['0', '1', '0', '0'], ['1', '0', '0', '0'], ['0', '0', '-1', '0']], [['-1', '0', '0', '0'], ['0', '-1', '0', '0'], ['0', '0', '-1', '0']]]

The code is as follows:

$ cat crystal_spider.py 
import scrapy

class CrystalSpider(scrapy.Spider):
    name = 'crystal'
    allowed_domains = ['www.cryst.ehu.es']
    start_urls = ['https://www.cryst.ehu.es/cgi-bin/subperiodic/programs/nph-sub_gen?gnum=75&what=gen&subtype=rod&ite=show']

    def parse(self, response):
        # 解析晶格矩阵数据
        matrix_data = []
        table = response.xpath('//pre')[1].xpath('.//table')[0]
        rows = table.xpath('.//tr')
        for row in rows:
            cells = row.xpath('.//td')
            row_data = []
            for cell in cells:
                text = cell.xpath('.//text()').get()
                if text is not None:
                    row_data.append(text.strip())
            if row_data:
                matrix_data.append(row_data)
        yield {'matrix_data': matrix_data}
        
        # 解析晶体数据
        matrix = []
        table = response.xpath('//pre')[2].xpath('.//table')[0]
        rows = table.xpath('.//tr')
        for row in rows:
            cells = row.xpath('.//td')
            row_data = []
            for cell in cells:
                text = cell.xpath('.//text()').get()
                if text is not None:
                    row_data.append(text.strip())
            if row_data:
                matrix.append(row_data)
        yield {'matrix': matrix}

However, the following error occurred while running it:

$ pyenv shell datasci
$ scrapy runspider crystal_spider.py -o crystal_data.json
2023-02-25 15:35:04 [scrapy.utils.log] INFO: Scrapy 2.8.0 started (bot: crystal)
2023-02-25 15:35:04 [scrapy.utils.log] INFO: Versions: lxml 4.9.2.0, libxml2 2.9.14, cssselect 1.2.0, parsel 1.7.0, w3lib 2.1.1, Twisted 22.10.0, Python 3.11.1 (main, Dec 22 2022, 17:06:07) [GCC 12.2.0], pyOpenSSL 23.0.0 (OpenSSL 3.0.8 7 Feb 2023), cryptography 39.0.1, Platform Linux-5.19.0-21-generic-x86_64-with-glibc2.36
2023-02-25 15:35:04 [scrapy.crawler] INFO: Overridden settings:
{'BOT_NAME': 'crystal',
 'FEED_EXPORT_ENCODING': 'utf-8',
 'NEWSPIDER_MODULE': 'crystal.spiders',
 'REQUEST_FINGERPRINTER_IMPLEMENTATION': '2.7',
 'ROBOTSTXT_OBEY': True,
 'SPIDER_LOADER_WARN_ONLY': True,
 'SPIDER_MODULES': ['crystal.spiders'],
 'TWISTED_REACTOR': 'twisted.internet.asyncioreactor.AsyncioSelectorReactor'}
2023-02-25 15:35:04 [asyncio] DEBUG: Using selector: EpollSelector
2023-02-25 15:35:04 [scrapy.utils.log] DEBUG: Using reactor: twisted.internet.asyncioreactor.AsyncioSelectorReactor
2023-02-25 15:35:04 [scrapy.utils.log] DEBUG: Using asyncio event loop: asyncio.unix_events._UnixSelectorEventLoop
2023-02-25 15:35:04 [scrapy.extensions.telnet] INFO: Telnet Password: c737e37db5e7f523
2023-02-25 15:35:05 [scrapy.middleware] INFO: Enabled extensions:
['scrapy.extensions.corestats.CoreStats',
 'scrapy.extensions.telnet.TelnetConsole',
 'scrapy.extensions.memusage.MemoryUsage',
 'scrapy.extensions.feedexport.FeedExporter',
 'scrapy.extensions.logstats.LogStats']
2023-02-25 15:35:05 [scrapy.middleware] INFO: Enabled downloader middlewares:
['scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware',
 'scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware',
 'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware',
 'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware',
 'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware',
 'scrapy.downloadermiddlewares.retry.RetryMiddleware',
 'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware',
 'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware',
 'scrapy.downloadermiddlewares.redirect.RedirectMiddleware',
 'scrapy.downloadermiddlewares.cookies.CookiesMiddleware',
 'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware',
 'scrapy.downloadermiddlewares.stats.DownloaderStats']
2023-02-25 15:35:05 [scrapy.middleware] INFO: Enabled spider middlewares:
['scrapy.spidermiddlewares.httperror.HttpErrorMiddleware',
 'scrapy.spidermiddlewares.offsite.OffsiteMiddleware',
 'scrapy.spidermiddlewares.referer.RefererMiddleware',
 'scrapy.spidermiddlewares.urllength.UrlLengthMiddleware',
 'scrapy.spidermiddlewares.depth.DepthMiddleware']
2023-02-25 15:35:05 [scrapy.middleware] INFO: Enabled item pipelines:
[]
2023-02-25 15:35:05 [scrapy.core.engine] INFO: Spider opened
2023-02-25 15:35:05 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2023-02-25 15:35:05 [scrapy.extensions.telnet] INFO: Telnet console listening on 127.0.0.1:6023
2023-02-25 15:35:06 [scrapy.core.engine] DEBUG: Crawled (404) <GET https://www.cryst.ehu.es/robots.txt> (referer: None)
2023-02-25 15:35:06 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://www.cryst.ehu.es/cgi-bin/subperiodic/programs/nph-sub_gen?gnum=75&what=gen&subtype=rod&ite=show> (referer: None) ['partial']
2023-02-25 15:35:06 [scrapy.core.scraper] ERROR: Spider error processing <GET https://www.cryst.ehu.es/cgi-bin/subperiodic/programs/nph-sub_gen?gnum=75&what=gen&subtype=rod&ite=show> (referer: None)
Traceback (most recent call last):
  File "/home/werner/.pyenv/versions/datasci/lib/python3.11/site-packages/scrapy/utils/defer.py", line 257, in iter_errback
    yield next(it)
          ^^^^^^^^
  File "/home/werner/.pyenv/versions/datasci/lib/python3.11/site-packages/scrapy/utils/python.py", line 312, in __next__
    return next(self.data)
           ^^^^^^^^^^^^^^^
  File "/home/werner/.pyenv/versions/datasci/lib/python3.11/site-packages/scrapy/utils/python.py", line 312, in __next__
    return next(self.data)
           ^^^^^^^^^^^^^^^
  File "/home/werner/.pyenv/versions/datasci/lib/python3.11/site-packages/scrapy/core/spidermw.py", line 104, in process_sync
    for r in iterable:
  File "/home/werner/.pyenv/versions/datasci/lib/python3.11/site-packages/scrapy/spidermiddlewares/offsite.py", line 28, in <genexpr>
    return (r for r in result or () if self._filter(r, spider))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/werner/.pyenv/versions/datasci/lib/python3.11/site-packages/scrapy/core/spidermw.py", line 104, in process_sync
    for r in iterable:
  File "/home/werner/.pyenv/versions/datasci/lib/python3.11/site-packages/scrapy/spidermiddlewares/referer.py", line 353, in <genexpr>
    return (self._set_referer(r, response) for r in result or ())
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/werner/.pyenv/versions/datasci/lib/python3.11/site-packages/scrapy/core/spidermw.py", line 104, in process_sync
    for r in iterable:
  File "/home/werner/.pyenv/versions/datasci/lib/python3.11/site-packages/scrapy/spidermiddlewares/urllength.py", line 27, in <genexpr>
    return (r for r in result or () if self._filter(r, spider))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/werner/.pyenv/versions/datasci/lib/python3.11/site-packages/scrapy/core/spidermw.py", line 104, in process_sync
    for r in iterable:
  File "/home/werner/.pyenv/versions/datasci/lib/python3.11/site-packages/scrapy/spidermiddlewares/depth.py", line 31, in <genexpr>
    return (r for r in result or () if self._filter(r, response, spider))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/werner/.pyenv/versions/datasci/lib/python3.11/site-packages/scrapy/core/spidermw.py", line 104, in process_sync
    for r in iterable:
  File "/home/werner/crystal/crystal/spiders/crystal_spider.py", line 11, in parse
    table = response.xpath('//pre')[1].xpath('.//table')[0]
            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^
  File "/home/werner/.pyenv/versions/datasci/lib/python3.11/site-packages/parsel/selector.py", line 131, in __getitem__
    o = super().__getitem__(pos)
        ^^^^^^^^^^^^^^^^^^^^^^^^
IndexError: list index out of range
2023-02-25 15:35:06 [scrapy.core.engine] INFO: Closing spider (finished)
2023-02-25 15:35:06 [scrapy.statscollectors] INFO: Dumping Scrapy stats:
{'downloader/request_bytes': 552,
 'downloader/request_count': 2,
 'downloader/request_method_count/GET': 2,
 'downloader/response_bytes': 6247,
 'downloader/response_count': 2,
 'downloader/response_status_count/200': 1,
 'downloader/response_status_count/404': 1,
 'elapsed_time_seconds': 1.638689,
 'finish_reason': 'finished',
 'finish_time': datetime.datetime(2023, 2, 25, 7, 35, 6, 780217),
 'log_count/DEBUG': 5,
 'log_count/ERROR': 1,
 'log_count/INFO': 10,
 'memusage/max': 70328320,
 'memusage/startup': 70328320,
 'response_received_count': 2,
 'robotstxt/request_count': 1,
 'robotstxt/response_count': 1,
 'robotstxt/response_status_count/404': 1,
 'scheduler/dequeued': 1,
 'scheduler/dequeued/memory': 1,
 'scheduler/enqueued': 1,
 'scheduler/enqueued/memory': 1,
 'spider_exceptions/IndexError': 1,
 'start_time': datetime.datetime(2023, 2, 25, 7, 35, 5, 141528)}
2023-02-25 15:35:06 [scrapy.core.engine] INFO: Spider closed (finished)

Any tips for fixing this problem will be appreciated.

Regards,
Zhao

It looks like the problem is with:

table = response.xpath('//pre')[1].xpath('.//table')[0]

You’re assuming that response.xpath('//pre')[1].xpath('.//table') returns something that has at least 1 entry, but it looks like sometimes it’s empty and has no entries.

I tried with the following code snippet:

import scrapy

class CrystalSpider(scrapy.Spider):
    name = 'crystal'

    def start_requests(self):
        urls = [
            'https://en.wikipedia.org/wiki/Diamond_cubic'
        ]
        for url in urls:
            yield scrapy.Request(url=url, callback=self.parse)

    def parse(self, response):
        # 解析晶格矩阵数据
        matrix_data = []
        pre_tags = response.xpath('//pre')
        if len(pre_tags) >= 2:
            second_pre = pre_tags[1]
            tables = second_pre.xpath('.//table')
            if len(tables) > 0:
                table = tables[0]
                rows = table.xpath('.//tr')
                for row in rows:
                    cells = row.xpath('.//td')
                    row_data = []
                    for cell in cells:
                        text = cell.xpath('.//text()').get()
                        if text is not None:
                            row_data.append(text.strip())
                    if row_data:
                        matrix_data.append(row_data)
                yield {'matrix_data': matrix_data}
            else:
                print('Error: no <table> element found in second <pre> tag')
        else:
            print('Error: fewer than two <pre> tags found')

        # Debug output
        print(f"Matrix data: {matrix_data}")

        # 解析晶体数据
        matrix = []
        pre_tags = response.xpath('//pre')
        if len(pre_tags) >= 3:
            third_pre = pre_tags[2]
            tables = third_pre.xpath('.//table')
            if len(tables) > 0:
                table = tables[0]
                rows = table.xpath('.//tr')
                for row in rows:
                    cells = row.xpath('.//td')
                    row_data = []
                    for cell in cells:
                        text = cell.xpath('.//text()').get()
                        if text is not None:
                            row_data.append(text.strip())
                    if row_data:
                        matrix.append(row_data)
                yield {'matrix': matrix}
            else:
                print('Error: no <table> element found in third <pre> tag')
        else:
            print('Error: fewer than three <pre> tags found')

        # Debug output
        print(f"Matrix: {matrix}")

The result is still empty, as shown below:

$ scrapy runspider crystal_spider.py -o crystal_data.json
2023-02-26 08:42:06 [scrapy.utils.log] INFO: Scrapy 2.8.0 started (bot: scrapybot)
2023-02-26 08:42:06 [scrapy.utils.log] INFO: Versions: lxml 4.9.2.0, libxml2 2.9.14, cssselect 1.2.0, parsel 1.7.0, w3lib 2.1.1, Twisted 22.10.0, Python 3.11.1 (main, Dec 22 2022, 17:06:07) [GCC 12.2.0], pyOpenSSL 23.0.0 (OpenSSL 3.0.8 7 Feb 2023), cryptography 39.0.1, Platform Linux-5.19.0-21-generic-x86_64-with-glibc2.36
2023-02-26 08:42:06 [scrapy.crawler] INFO: Overridden settings:
{'SPIDER_LOADER_WARN_ONLY': True}
2023-02-26 08:42:06 [py.warnings] WARNING: /home/werner/.pyenv/versions/datasci/lib/python3.11/site-packages/scrapy/utils/request.py:232: ScrapyDeprecationWarning: '2.6' is a deprecated value for the 'REQUEST_FINGERPRINTER_IMPLEMENTATION' setting.

It is also the default value. In other words, it is normal to get this warning if you have not defined a value for the 'REQUEST_FINGERPRINTER_IMPLEMENTATION' setting. This is so for backward compatibility reasons, but it will change in a future version of Scrapy.

See the documentation of the 'REQUEST_FINGERPRINTER_IMPLEMENTATION' setting for information on how to handle this deprecation.
  return cls(crawler)

2023-02-26 08:42:06 [scrapy.utils.log] DEBUG: Using reactor: twisted.internet.epollreactor.EPollReactor
2023-02-26 08:42:06 [scrapy.extensions.telnet] INFO: Telnet Password: b409b47632dc71c3
2023-02-26 08:42:06 [scrapy.middleware] INFO: Enabled extensions:
['scrapy.extensions.corestats.CoreStats',
 'scrapy.extensions.telnet.TelnetConsole',
 'scrapy.extensions.memusage.MemoryUsage',
 'scrapy.extensions.feedexport.FeedExporter',
 'scrapy.extensions.logstats.LogStats']
2023-02-26 08:42:06 [scrapy.middleware] INFO: Enabled downloader middlewares:
['scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware',
 'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware',
 'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware',
 'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware',
 'scrapy.downloadermiddlewares.retry.RetryMiddleware',
 'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware',
 'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware',
 'scrapy.downloadermiddlewares.redirect.RedirectMiddleware',
 'scrapy.downloadermiddlewares.cookies.CookiesMiddleware',
 'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware',
 'scrapy.downloadermiddlewares.stats.DownloaderStats']
2023-02-26 08:42:06 [scrapy.middleware] INFO: Enabled spider middlewares:
['scrapy.spidermiddlewares.httperror.HttpErrorMiddleware',
 'scrapy.spidermiddlewares.offsite.OffsiteMiddleware',
 'scrapy.spidermiddlewares.referer.RefererMiddleware',
 'scrapy.spidermiddlewares.urllength.UrlLengthMiddleware',
 'scrapy.spidermiddlewares.depth.DepthMiddleware']
2023-02-26 08:42:06 [scrapy.middleware] INFO: Enabled item pipelines:
[]
2023-02-26 08:42:06 [scrapy.core.engine] INFO: Spider opened
2023-02-26 08:42:06 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2023-02-26 08:42:06 [scrapy.extensions.telnet] INFO: Telnet console listening on 127.0.0.1:6023
2023-02-26 08:43:06 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2023-02-26 08:44:06 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2023-02-26 08:44:07 [scrapy.downloadermiddlewares.retry] DEBUG: Retrying <GET https://en.wikipedia.org/wiki/Diamond_cubic> (failed 1 times): [<twisted.python.failure.Failure twisted.internet.error.ConnectionLost: Connection to the other side was lost in a non-clean fashion: Connection lost.>]