scrapy 如果parse方法出错,如何重新抓取页面?

nom7f22z  于 2023-10-20  发布在  其他
关注(0)|答案(1)|浏览(193)

我的parse方法中的第一个操作是从HTML中包含的JSON字符串中提取字典。我注意到,我有时会得到一个错误,因为网页不能正确显示,因此不包含JSON字符串。如果我删除spider,那么同一个页面显示正常,并继续运行,直到另一个随机的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

我很确定这将工作OK,但想检查检查几件事:
1.如果这命中了一个没有JSON的“真正糟糕”的页面,蜘蛛会陷入循环,还是在尝试了一定次数的给定URL后给予?
1.我使用了return而不是yield,因为我不想继续运行该方法。这样行吗?
任何其他意见也欢迎!!

njthzxwz

njthzxwz1#

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

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

相关问题