关于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 相关文章推荐
Python3.6安装及引入Requests库的实现方法
Jan 24 Python
Python实现的求解最小公倍数算法示例
May 03 Python
Python subprocess模块常见用法分析
Jun 12 Python
Python OpenCV读取png图像转成jpg图像存储的方法
Oct 28 Python
python使用matplotlib画柱状图、散点图
Mar 18 Python
python登录WeChat 实现自动回复实例详解
May 28 Python
python不使用for计算两组、多个矩形两两间的iou方式
Jan 18 Python
Python3 字典dictionary入门基础附实例
Feb 10 Python
Python requests.post方法中data与json参数区别详解
Apr 30 Python
python能开发游戏吗
Jun 11 Python
python 实现压缩和解压缩的示例
Sep 22 Python
如何正确理解python装饰器
Jun 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动态生成JavaScript代码
2009/03/09 PHP
PHP生成网页快照 不用COM不用扩展.
2010/02/11 PHP
浅析php学习的路线图
2013/07/10 PHP
拖动Html元素集合 Drag and Drop any item
2006/12/22 Javascript
Code:loadScript( )加载js的功能函数
2007/02/02 Javascript
jquery中输入验证中一个不错的效果
2010/08/21 Javascript
js定时器怎么写?就是在特定时间执行某段程序
2013/10/11 Javascript
javascript刷新父页面的各种方法汇总
2014/09/03 Javascript
jquery+html5烂漫爱心表白动画代码分享
2015/08/24 Javascript
javascript实现tab切换的两个实例
2015/11/05 Javascript
Javascript 字符串模板的简单实现
2016/02/13 Javascript
jquery点击改变class并toggle的实现代码
2016/05/15 Javascript
jQuery插件开发汇总
2016/05/15 Javascript
vue.js表格组件开发的实例详解
2016/10/12 Javascript
快速实现JS图片懒加载(可视区域加载)示例代码
2017/01/04 Javascript
Bootstrap Table快速完美搭建后台管理系统
2017/09/20 Javascript
Vue使用Clipboard.JS在h5页面中复制内容实例详解
2019/09/03 Javascript
微信小程序实现星级评价
2019/11/20 Javascript
JS深入学习之数组对象排序操作示例
2020/05/01 Javascript
python实现装饰器、描述符
2018/02/28 Python
TensorFLow用Saver保存和恢复变量
2018/03/10 Python
Python图像处理之图像的读取、显示与保存操作【测试可用】
2019/01/04 Python
python实现while循环打印星星的四种形状
2019/11/23 Python
tensorflow实现在函数中用tf.Print输出中间值
2020/01/21 Python
高考考python编程是真的吗
2020/07/20 Python
Pycharm配置lua编译环境过程图解
2020/11/28 Python
Tory Burch美国官方网站:美国时尚生活品牌
2016/08/01 全球购物
信用社实习人员自我鉴定
2013/09/20 职场文书
党的群众路线教育实践方案
2014/05/11 职场文书
留学生求职信
2014/06/03 职场文书
幼儿园春季开学通知
2015/07/16 职场文书
Python爬虫之自动爬取某车之家各车销售数据
2021/06/02 Python
你需要掌握的20个Python常用技巧
2022/02/28 Python
 Python 中 logging 模块使用详情
2022/03/03 Python
详细聊一聊mysql的树形结构存储以及查询
2022/04/05 MySQL
Spring boot实现上传文件到本地服务器
2022/08/14 Java/Android