如果解析方法出现错误,如何重新抓取页面?

问题描述 投票:0回答:1

我的

parse
方法中的第一个操作是从 HTML 中包含的 JSON 字符串中提取字典。我注意到有时会收到错误,因为网页无法正确显示,因此不包含 JSON 字符串。如果我重新运行蜘蛛,那么同一页面会显示正常,并继续下去,直到出现另一个随机 JSON 错误。

我想检查一下错误处理是否正确:

def parse(self, response):
    json_str = response.xpath("<xpath_to_json>").get()
    try:
        items = json.loads(json_str)["items"]
    except JSONDecodeError:
        return response.follow(url=response.url, callback=self.parse)
    for i in items:
        # do stuff

我很确定这会正常工作,但想检查一下几件事:

  1. 如果这遇到了一个没有 JSON 的“真正糟糕”的页面,蜘蛛是否会陷入循环,或者 scrapy 在尝试给定 URL 一定次数后会放弃?
  2. 我使用了
    return
    而不是
    yield
    ,因为我不想继续运行该方法。这样可以吗?

还有其他意见也欢迎留言!!

python scrapy
1个回答
0
投票

我认为

return
在您的情况下遇到解码错误应该没问题,因为抓取器不会迭代抓取的结果。我认为通常
response.follow
Request
会过滤掉重复的请求,因此您在调用它们时需要包含
dont_filter=True
。要配置
n
重试次数,这不是最干净的方法,但您可以保留一个字典来跟踪某些 url 的重试尝试计数作为
self
属性(下面代码中的
self.retry_count
),每次增加它被解析并在达到限制数量时停止。

import json
from json import JSONDecodeError
import scrapy


class TestSpider(scrapy.Spider):
    name = "test"

    def start_requests(self):
        urls = [
            "https://quotes.toscrape.com/page/1/",
            "https://quotes.toscrape.com/page/2/"
        ]
        for url in urls:
            self.retry_count = {k:0 for k in urls}
            self.retry_limit = 3
            yield scrapy.Request(url=url, callback=self.parse, dont_filter=True)

    def parse(self, response):
        self.retry_count[response.url] += 1
        json_str = "{\"items\": 1" # intentionally trigger json decode error
        print(f'===== RUN {response.url}; Attempt: {self.retry_count} =====')
        try:
            items = json.loads(json_str)["items"]
        except JSONDecodeError as ex:
            print("==== ERROR ====")
            if self.retry_count[response.url] == self.retry_limit:
                raise ex
            else:
                return response.follow(url=response.url, callback=self.parse, dont_filter=True)
        
        self.retry_count[response.url] = 0 # reset attempt as parse successful

© www.soinside.com 2019 - 2024. All rights reserved.