关于python scrapy中添加cookie踩坑记录


Posted in Python onNovember 17, 2020

问题发现:

前段时间项目中,为了防止被封号(提供的可用账号太少),对于能不登录就可以抓取的内容采用不带cookie的策略,只有必要的内容才带上cookie去访问。

本来想着很简单:在每个抛出来的Request的meta中带上一个标志位,通过在CookieMiddleware中查看这个标志位,决定是否是给这个Request是否装上Cookie。

实现的代码大致如下:

class CookieMiddleware(object):
  """
  每次请求都随机从账号池中选择一个账号去访问
  """

  def __init__(self):
    client = pymongo.MongoClient(MONGO_URI)
    self.account_collection = client[MONGO_DATABASE][ACCOUNT_COLLECTION]

  def process_request(self, request, spider):
    if 'target' in request.meta: 
      logging.debug('进入到process_request了')
      flag = request.meta['target']
      if flag != 'no':
        all_count = self.account_collection.find({'status': 'success'}).count()
        if all_count == 0:
          raise Exception('当前账号池为空')
        random_index = random.randint(0, all_count - 1)
        random_account = self.account_collection.find({'status': 'success'})[random_index]
        
        request.cookies = json.loads(random_account['cookie'])
      else:
        logging.debug('对XXX的请求不做处理')
    else:
      all_count = self.account_collection.find({'status': 'success'}).count()
      if all_count == 0:
        raise Exception('当前账号池为空')
      random_index = random.randint(0, all_count - 1)
      random_account = self.account_collection.find({'status': 'success'})[random_index]
      
      request.cookies = json.loads(random_account['cookie'])

在settings.py中的配置如下:

DOWNLOADER_MIDDLEWARES = {
  'eyny.middlewares.CookieMiddleware': 550,
}

到这里可能有些大佬已经能够看出端倪了,和我一样认为这么写没啥问题的同志们继续往下看。

在这么编写完之后,我正常开启了项目,还适当调高了并发量,然后第二天发现账号被封了。在debug过程中看到在抓取不需要携带cookie的url的时候,依然携带了cookie,并且cookie是被放在了header中,经过我花费了两个多小时查看框架源码之后,终于发现了原因。

原因&解决方案:

在scrapy的settings目录下的default_settings.py文件中,初始声明了一些DOWNLOADER_MIDDLEWARES_BASE,这些middlewares的声明如下:

DOWNLOADER_MIDDLEWARES_BASE = {
  # Engine side
  'scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware': 100,
  'scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware': 300,
  'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware': 350,
  'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware': 400,
  'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': 500,
  'scrapy.downloadermiddlewares.retry.RetryMiddleware': 550,
  'scrapy.downloadermiddlewares.ajaxcrawl.AjaxCrawlMiddleware': 560,
  'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware': 580,
  'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 590,
  'scrapy.downloadermiddlewares.redirect.RedirectMiddleware': 600,
  'scrapy.downloadermiddlewares.cookies.CookiesMiddleware': 700,
  'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 750,
  'scrapy.downloadermiddlewares.stats.DownloaderStats': 850,
  'scrapy.downloadermiddlewares.httpcache.HttpCacheMiddleware': 900,
  # Downloader side
}

可以看到在DOWNLOADER_MIDDLEWARES_BASE中也声明了一个CookiesMiddleware,而且是700,也就是说比我们写的CookieMiddleware(500)要靠后执行,而且在debug过程中也看到,在执行完我们编写的CookieMiddleware之后,header中没有携带cookie,但是在执行完scrapy.downloadermiddlewares.cookies.CookiesMiddleware: 700之后,在header中看到了cookie,这说明cookie是scrapy帮我们自动加了。

我们打开scrapy.downloadermiddlewares.cookies.CookiesMiddleware的实现源码,主要关注process_request方法:

class CookiesMiddleware(object):
  """This middleware enables working with sites that need cookies"""

  def __init__(self, debug=False):
    self.jars = defaultdict(CookieJar)
    self.debug = debug

  @classmethod
  def from_crawler(cls, crawler):
    if not crawler.settings.getbool('COOKIES_ENABLED'):
      raise NotConfigured
    return cls(crawler.settings.getbool('COOKIES_DEBUG'))

  def process_request(self, request, spider):
    if request.meta.get('dont_merge_cookies', False):
      return

    cookiejarkey = request.meta.get("cookiejar")
    jar = self.jars[cookiejarkey]
    cookies = self._get_request_cookies(jar, request)
    for cookie in cookies:
      jar.set_cookie_if_ok(cookie, request)

    # set Cookie header
    request.headers.pop('Cookie', None)
    jar.add_cookie_header(request)
    self._debug_cookie(request, spider)

	def process_response(self, request, response, spider):
    if request.meta.get('dont_merge_cookies', False):
      return response

    # extract cookies from Set-Cookie and drop invalid/expired cookies
    cookiejarkey = request.meta.get("cookiejar")
    jar = self.jars[cookiejarkey]
    jar.extract_cookies(response, request)
    self._debug_set_cookie(response, spider)

    return response

在上面的代码中,最中要的是process_request方法中的内容,可以看到首先从request.meta中查看有没有dont_merge_cookies属性,如果没有或者为false,就不运行剩下的方法,卧槽,这就是我们要找的方法呀!是不是好简单…

特别注意如果要使用dont_merge_cookies=true,那么需要我们自己将cookie加入到header中,通过**request.cookies = json.loads(random_account[‘cookie'])**方式添加的cookie,scrapy也不再会帮我们合并到header 中了。

解决方案我们的解决方法就是在request的meta中加入dont_merge_cookies属性,并设置为true,在CookieMiddleware中,我们将cookie添加在header中,而不是赋值给request.cookies

问题解决了,但是这么简单是不是很不爽,所以就继续想看看是为什么scrapy可以自动给我们加上cookie,这个接下来就需要读下面的代码了。

总结

到此这篇关于关于python scrapy中添加cookie踩坑记录的文章就介绍到这了,更多相关scrapy cookie问题内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
python实现猜数字游戏(无重复数字)示例分享
Mar 29 Python
pycharm 使用心得(一)安装和首次使用
Jun 05 Python
举例讲解Python程序与系统shell交互的方式
Apr 09 Python
python和flask中返回JSON数据的方法
Mar 26 Python
使用python对文件中的单词进行提取的方法示例
Dec 21 Python
Pandas读取并修改excel的示例代码
Feb 17 Python
django-crontab实现服务端的定时任务的示例代码
Feb 17 Python
python中68个内置函数的总结与介绍
Feb 24 Python
python实现四人制扑克牌游戏
Apr 22 Python
Python如何用wx模块创建文本编辑器
Jun 07 Python
如何在keras中添加自己的优化器(如adam等)
Jun 19 Python
零基础小白多久能学会python
Jun 22 Python
python中strip(),lstrip(),rstrip()函数的使用讲解
Nov 17 #Python
PyTorch预训练Bert模型的示例
Nov 17 #Python
python 下载文件的多种方法汇总
Nov 17 #Python
python跨文件使用全局变量的实现
Nov 17 #Python
Python中logging日志的四个等级和使用
Nov 17 #Python
Python爬虫破解登陆哔哩哔哩的方法
Nov 17 #Python
appium+python自动化配置(adk、jdk、node.js)
Nov 17 #Python
You might like
十大催泪虐心动漫电影,有几部你还没看
2020/03/04 日漫
第十五节--Zend引擎的发展
2006/11/16 PHP
php实现网站插件机制的方法
2009/11/10 PHP
PHP 透明水印生成代码
2012/08/27 PHP
PHP通过插入mysql数据来实现多机互锁实例
2014/11/05 PHP
PHP使用Mysqli类库实现完美分页效果的方法
2016/04/07 PHP
PHP生成制作验证码的简单实例
2016/06/12 PHP
thinkphp表单上传文件并将文件路径保存到数据库中
2016/07/28 PHP
PHP实现接收二进制流转换成图片的方法
2017/01/10 PHP
PHP基于PDO实现的SQLite操作类【包含增删改查及事务等操作】
2017/06/21 PHP
ThinkPHP5.0框架控制器继承基类和自定义类示例
2018/05/25 PHP
PHP convert_uudecode()函数讲解
2019/02/14 PHP
Thinkphp5框架实现获取数据库数据到视图的方法
2019/08/14 PHP
Array.slice()与Array.splice()的返回值类型
2006/10/09 Javascript
键盘控制事件应用教程大全
2006/11/24 Javascript
jQuery 表单验证扩展(三)
2010/10/20 Javascript
jQuery中创建实例与原型继承揭秘
2011/12/21 Javascript
javascript怎么禁用浏览器后退按钮
2014/03/27 Javascript
AngularJS中实现显示或隐藏动画效果的方式总结
2015/12/31 Javascript
12个非常实用的JavaScript小技巧【推荐】
2016/05/18 Javascript
微信小程序 下拉菜单的实现
2017/04/06 Javascript
详解使用angular-cli发布i18n多国语言Angular应用
2017/05/20 Javascript
JavaScript之promise_动力节点Java学院整理
2017/07/03 Javascript
Angular4绑定html内容出现警告的处理方法
2017/11/03 Javascript
详解如何模拟实现node中的Events模块(通俗易懂版)
2019/04/15 Javascript
layui对工具条进行选择性的显示方法
2019/09/19 Javascript
Python中的yield浅析
2014/06/16 Python
将Python代码嵌入C++程序进行编写的实例
2015/07/31 Python
解析Python中while true的使用
2015/10/13 Python
Python Flask-web表单使用详解
2017/11/18 Python
详解Python 字符串相似性的几种度量方法
2019/08/29 Python
解决Keras使用GPU资源耗尽的问题
2020/06/22 Python
tensorflow/core/platform/cpu_feature_guard.cc:140] Your CPU supports instructions that this T
2020/06/22 Python
Python 用__new__方法实现单例的操作
2020/12/11 Python
蛋糕店的商业计划书范文
2014/01/27 职场文书
新学期主题班会
2015/08/17 职场文书