热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

scrapy注意事项汇总

callback执行异常处理如果Request请求成功后,在解析文本时异常,如下所示:defparse_details(self,response):item['m

callback执行异常处理

如果Request请求成功后,在解析文本时异常,如下所示:

def parse_details(self, response):
...
item['metres'] = round(float(
response.xpath('/html/body/section[1]/div/div[3]/ul/li[1]/span[1]/text()').extract_first().rstrip(
'万公里')) * 10000000)
...
yield item
response.xpath('/html/body/section[1]/div/div[3]/ul/li[1]/span[1]/text()').extract_first().rstrip(
AttributeError: 'NoneType' object has no attribute 'rstrip'

如果是代码错误或者页面改版,重新适配即可,但如果是由于限流规则导致被转发到限流页面,就需要捕获异常进行补救,求解之路如下:

1、DOWNLOADER_MIDDLEWARES中process_exception

本意是请求失败后更换代理,但是未生效,因为process_exception处理的是Request异常,例如:请求超时、请求拒绝、请求未响应等,但上述错误是请求成功后解析造成的,理解错误,陷入误区

2、自行捕获异常,更换代理重试

try:
...
item['metres'] = round(float(
response.xpath('/html/body/section[1]/div/div[3]/ul/li[1]/span[1]/text()').extract_first().rstrip(
'万公里')) * 10000000)
...
except Exception as reason:
retry_times = response.meta.get('retry_times', 0)
if retry_times <3:
yield scrapy.Request(url=xxx, meta={'url': xxx, 'is_new_proxy': True, 'retry_times': retry_times + 1}, callback=self.parse, dont_filter=True)

需要再meta中设置以下属性:



  • url:限流后请求有可能被重置,response.request.url可能变为重置后的地址

  • is_new_proxy: 声明需要新的代理,在DOWNLOADER_MIDDLEWARES的process_request中作为获取代理的入参

  • retry_times:避免无限重试

    注意:需要设置dont_filter=True,避免重复url被过滤掉

3、使用SPIDER_MIDDLEWARES中process_spider_exception

process_spider_exception(self, response, exception, spider)会捕获callback中抛出的异常,可以在这里添加异常处理策略,例如:邮件报警、短信提示等,可以与自行捕获异常配合使用


scrapy.Request不生效



  • scrapy.Request时未设置dont_filter=True,重复url会被自动过滤

  • url不在allowed_domains中


反爬取应对策略



  • scrapy参数调整,两个方向:限制并发数、模拟停顿

  • 代理IP和User-Agent,DOWNLOADER_MIDDLEWARES中设置,如下:

def __init__(self, delay, user_agent_list):
self.delay = delay
self.user_agent_list = user_agent_list
@classmethod
def from_crawler(cls, crawler):
# This method is used by Scrapy to create your spiders.
# RANDOM_DELAY、USER_AGENT_LIST为spider的custom_settings中配置项
delay = crawler.spider.settings.get("RANDOM_DELAY", 0)
user_agent_list = crawler.spider.settings.get("USER_AGENT_LIST", [])
if not isinstance(delay, int):
raise ValueError("RANDOM_DELAY need a int")
s = cls(delay, user_agent_list)
crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
return s
def process_request(self, request, spider):
# Called for each request that goes through the downloader
# 设置随机停顿
if self.delay > 0:
delay = random.randint(0, self.delay)
time.sleep(delay)
# 设置User-Agent
if len(self.user_agent_list) > 0:
request.headers['User-Agent'] = random.choice(self.user_agent_list)
if spider.name not in self.SPIDERS_USE_PROXY:
return None
# 设置代理
try:
proxy = get_one_proxy(spider.name, request.meta.get('is_new_proxy', False))
request.meta['proxy'] = proxy
request.meta['change_proxy_times'] = 1
except ProxyError:
pass
return None
def get_one_proxy(app, is_new_proxy):
# 特殊情况下,强制获取一个新的代理并放入代理池中
if is_new_proxy:
new_proxy = refresh_and_get_one_proxy(app)
proxy_http_list.append(new_proxy)
return new_proxy
# 默认初始化N个代理,每次随机选择一个,重试时也是随机换一个
while len(proxy_http_list) proxy_http_list.append(refresh_and_get_one_proxy(app))
return random.choice(proxy_http_list)


推荐阅读
author-avatar
希瑟小姐
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有