关于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快速查找算法应用实例
Sep 26 Python
Python进行数据科学工作的简单入门教程
Apr 01 Python
举例讲解Python面相对象编程中对象的属性与类的方法
Jan 19 Python
Python解析json文件相关知识学习
Mar 01 Python
利用python获取Ping结果示例代码
Jul 06 Python
Python中顺序表的实现简单代码分享
Jan 09 Python
树莓派3 搭建 django 服务器的实例
Aug 29 Python
Django后端发送小程序微信模板消息示例(服务通知)
Dec 17 Python
ipython jupyter notebook中显示图像和数学公式实例
Apr 15 Python
python 使用cycle构造无限循环迭代器
Dec 02 Python
PyTorch dropout设置训练和测试模式的实现
May 27 Python
Python pandas读取CSV文件的注意事项(适合新手)
Jun 20 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动态生成VRML网页
2006/10/09 PHP
php和javascript之间变量的传递实现代码
2012/12/19 PHP
PHP实现JS中escape与unescape的方法
2016/07/11 PHP
javascript 一个函数对同一元素的多个事件响应
2009/07/25 Javascript
JavaScript 图片预览效果 推荐
2009/12/22 Javascript
jquery遍历checkbox的注意事项说明
2014/02/21 Javascript
ajax提交表单实现网页无刷新注册示例
2014/05/08 Javascript
js实现屏幕自适应局部代码分享
2015/01/30 Javascript
javascript实现俄罗斯方块游戏的思路和方法
2015/04/27 Javascript
JS选中checkbox后获取table内一行TD所有数据的方法
2015/07/01 Javascript
jQuery实现的选择商品飞入文本框动画效果完整实例
2016/08/10 Javascript
BootStrap 图片样式、辅助类样式和CSS组件的实例详解
2017/01/20 Javascript
基于bootstrap实现bootstrap中文网巨幕效果
2017/05/02 Javascript
全新打包工具parcel零配置vue开发脚手架
2018/01/11 Javascript
JavaScript数组,JSON对象实现动态添加、修改、删除功能示例
2018/05/26 Javascript
Vue 实现输入框新增搜索历史记录功能
2019/10/15 Javascript
javascript+css实现进度条效果
2020/03/25 Javascript
Vue优化:常见会导致内存泄漏问题及优化详解
2020/08/04 Javascript
TensorFlow实现卷积神经网络CNN
2018/03/09 Python
用Python逐行分析文件方法
2019/01/28 Python
Python实现变声器功能(萝莉音御姐音)
2019/12/05 Python
pycharm 2019 最新激活方式(pycharm破解、激活)
2020/09/22 Python
Python warning警告出现的原因及忽略方法
2020/01/31 Python
Python3中对json格式数据的分析处理
2021/01/28 Python
基于html5 DeviceOrientation 实现微信摇一摇功能
2015/09/25 HTML / CSS
英国天然有机美容护肤品:Neal’s Yard Remedies
2018/05/05 全球购物
运动鞋、足球鞋和慕尼黑球衣:Sport Münzinger
2019/08/26 全球购物
实习自荐信
2013/10/13 职场文书
党校培训思想汇报
2014/01/03 职场文书
《狐假虎威》教学反思
2014/02/07 职场文书
恶搞卫生巾广告词
2014/03/18 职场文书
中介业务员岗位职责
2014/04/09 职场文书
初中教师业务学习材料
2014/05/12 职场文书
项目经理任命书内容
2014/06/06 职场文书
浅谈哪个Python库才最适合做数据可视化
2021/06/28 Python
Python中rapidjson参数校验实现
2021/07/25 Python