关于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的WEB框架Flask中使用多个配置文件的解决方法
Apr 18 Python
Python脚本实现格式化css文件
Apr 08 Python
Python模拟脉冲星伪信号频率实例代码
Jan 03 Python
详解python中的线程
Feb 10 Python
详解如何在python中读写和存储matlab的数据文件(*.mat)
Feb 24 Python
python图像处理入门(一)
Apr 04 Python
python中@property和property函数常见使用方法示例
Oct 21 Python
基于Python实现拆分和合并GIF动态图
Oct 22 Python
python 操作hive pyhs2方式
Dec 21 Python
Python换行与不换行的输出实例
Feb 19 Python
python matplotlib.pyplot.plot()参数用法
Apr 14 Python
django models里数据表插入数据id自增操作
Jul 15 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 isset()与empty()的使用区别详解
2010/08/29 PHP
php中防止恶意刷新页面的代码小结
2012/10/31 PHP
php下载文件源代码(强制任意文件格式下载)
2014/05/09 PHP
php+ajax实现图片文件上传功能实例
2014/06/17 PHP
phplot生成图片类用法详解
2015/01/06 PHP
PHP处理CSV表格文件的常用操作方法总结
2016/07/01 PHP
php array_walk_recursive 使用自定的函数处理数组中的每一个元素
2016/11/16 PHP
用Javascript同时提交多个Web表单的方法
2009/12/26 Javascript
打开新窗口关闭当前页面不弹出关闭提示js代码
2013/03/18 Javascript
js将json格式内容转换成对象的方法
2013/11/01 Javascript
异步JS框架的作用以及实现方法
2015/10/29 Javascript
JS实现图片局部放大或缩小的方法
2016/08/20 Javascript
详解堆的javascript实现方法
2016/11/29 Javascript
easyui 中的datagrid跨页勾选问题的实现方法
2017/01/18 Javascript
前端主流框架vue学习笔记第二篇
2017/07/26 Javascript
Angular js 实现添加用户、修改密码、敏感字、下拉菜单的综合操作方法
2017/10/24 Javascript
基于angular6.0实现的一个组件懒加载功能示例
2018/04/12 Javascript
Node.js模块全局安装路径配置方法
2018/05/17 Javascript
JavaScript使用indexOf()实现数组去重的方法分析
2018/09/04 Javascript
angularjs http与后台交互的实现示例
2018/12/21 Javascript
JavaScript自定义超时API代码实例
2020/04/30 Javascript
Python2.7+pytesser实现简单验证码的识别方法
2017/12/29 Python
python实现校园网自动登录的示例讲解
2018/04/22 Python
对Python中for复合语句的使用示例讲解
2018/11/01 Python
Django异步任务线程池实现原理
2019/12/17 Python
美国家喻户晓的保健品品牌:Vitamin World(维他命世界)
2016/08/19 全球购物
荷兰网上买鞋:MooieSchoenen.nl
2017/09/12 全球购物
什么是事务?为什么需要事务?
2012/01/09 面试题
个人实习生的自我评价
2014/02/16 职场文书
财务简历的自我评价
2014/03/05 职场文书
8和9的加减法教学反思
2014/05/01 职场文书
党员干部反四风民主生活会对照检查材料思想汇报
2014/10/12 职场文书
交通安全温馨提示语
2015/07/14 职场文书
Pytorch DataLoader shuffle验证方式
2021/06/02 Python
nginx服务器的下载安装与使用详解
2021/08/02 Servers
CSS实现单选折叠菜单功能
2021/11/01 HTML / CSS