关于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引用DLL文件的方法
May 11 Python
尝试使用Python多线程抓取代理服务器IP地址的示例
Nov 09 Python
python实现对指定输入的字符串逆序输出的6种方法
Apr 26 Python
python实现Windows电脑定时关机
Jun 20 Python
Python WSGI的深入理解
Aug 01 Python
python实现多张图片拼接成大图
Jan 15 Python
一篇文章搞定Python操作文件与目录
Aug 13 Python
Python如何把多个PDF文件合并代码实例
Feb 13 Python
python实现Pyecharts实现动态地图(Map、Geo)
Mar 25 Python
python中sort sorted reverse reversed函数的区别说明
May 11 Python
基于python实现监听Rabbitmq系统日志代码示例
Nov 28 Python
python 自动化偷懒的四个实用操作
Apr 11 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
PHP chmod 函数与批量修改文件目录权限
2010/05/10 PHP
PHP原生函数一定好吗?
2014/12/08 PHP
php将HTML表格每行每列转为数组实现采集表格数据的方法
2015/04/03 PHP
PHP SPL标准库之数据结构堆(SplHeap)简单使用实例
2015/05/12 PHP
用JavaScript页面不刷新时全选择,全删除(GridView)
2009/04/14 Javascript
checkbox全选/取消全选以及checkbox遍历jQuery实现代码
2009/12/02 Javascript
js判断变量初始化的三种形式及推荐用的形式
2014/07/22 Javascript
JavaScript实现在数组中查找不同顺序排列的字符串
2014/09/26 Javascript
javascript制作网页图片上实现下雨效果
2015/02/26 Javascript
JavaScript使用encodeURI()和decodeURI()获取字符串值的方法
2015/08/04 Javascript
JS实现的N多简单无缝滚动代码(包含图文效果)
2015/11/06 Javascript
js判断某个字符出现的次数的简单实例
2016/06/03 Javascript
Bootstrap CSS布局之代码
2016/12/17 Javascript
js 实现复选框只能选择一项的示例代码
2018/01/23 Javascript
浅谈node.js 命令行工具(cli)
2018/05/10 Javascript
微信小程序缓存支持二次开发封装实现解析
2019/12/16 Javascript
[42:52]Optic vs Serenity 2018国际邀请赛淘汰赛BO3 第二场 8.22
2018/08/23 DOTA
Python中optparse模块使用浅析
2015/01/01 Python
Python简单实现自动删除目录下空文件夹的方法
2017/08/29 Python
Python数据处理numpy.median的实例讲解
2018/04/02 Python
Flask框架配置与调试操作示例
2018/07/23 Python
python开发准备工作之配置虚拟环境(非常重要)
2019/02/11 Python
对numpy下的轴交换transpose和swapaxes的示例解读
2019/06/26 Python
详解Python 多线程 Timer定时器/延迟执行、Event事件
2019/06/27 Python
解决Pycharm的项目目录突然消失的问题
2020/01/20 Python
Python PIL库图片灰化处理
2020/04/07 Python
Html5实现单张、多张图片上传功能
2019/04/28 HTML / CSS
俄罗斯玩具、儿童用品、儿童服装和鞋子网上商店:MyToys.ru
2019/10/14 全球购物
交通事故调解协议书
2014/04/16 职场文书
九寨沟导游词
2015/02/02 职场文书
毕业论文指导老师意见
2015/06/04 职场文书
2015年校本培训工作总结
2015/07/24 职场文书
技术入股协议书
2016/03/22 职场文书
2016年“9.22”世界无车日活动小结
2016/04/05 职场文书
golang DNS服务器的简单实现操作
2021/04/30 Golang
oracle覆盖导入dmp文件的2种方法
2021/05/21 Oracle