我的
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
我很确定这会正常工作,但想检查一下几件事:
return
而不是 yield
,因为我不想继续运行该方法。这样可以吗?还有其他意见也欢迎留言!!
我认为
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