关于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 ljust rjust center输出
Sep 06 Python
详解Python中类的定义与使用
Apr 11 Python
利用信号如何监控Django模型对象字段值的变化详解
Nov 27 Python
python决策树之C4.5算法详解
Dec 20 Python
Python3.6笔记之将程序运行结果输出到文件的方法
Apr 22 Python
python2使用bs4爬取腾讯社招过程解析
Aug 14 Python
pyenv与virtualenv安装实现python多版本多项目管理
Aug 17 Python
Python lambda表达式filter、map、reduce函数用法解析
Sep 11 Python
pandas将多个dataframe以多个sheet的形式保存到一个excel文件中
Oct 10 Python
Python异常模块traceback用法实例分析
Oct 22 Python
python GUI库图形界面开发之PyQt5表单布局控件QFormLayout详细使用方法与实例
Mar 06 Python
python+opencv实现车道线检测
Feb 19 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之第八天
2006/10/09 PHP
解决phpmyadmin 乱码,支持gb2312和utf-8
2006/11/20 PHP
php旋转图片90度的方法
2013/11/07 PHP
PHP消息队列实现及应用详解【队列处理订单系统和配送系统】
2019/05/20 PHP
php 的多进程操作实践案例分析
2020/02/28 PHP
基于jquery的跟随屏幕滚动代码
2012/07/24 Javascript
javaScript 删除字符串空格多种方法小结
2012/10/24 Javascript
node.js中的fs.utimes方法使用说明
2014/12/15 Javascript
JS解析XML实例分析
2015/01/30 Javascript
兼容各大浏览器的JavaScript阻止事件冒泡代码
2015/07/09 Javascript
原生JavaScript实现动态省市县三级联动下拉框菜单实例代码
2016/02/03 Javascript
高效利用Angular中内置服务$http、$location等
2016/03/22 Javascript
webpack+vue2构建vue项目骨架的方法
2018/01/09 Javascript
ng-repeat指令在迭代对象时的去重方法
2018/10/02 Javascript
微信小程序实现录音功能
2019/11/22 Javascript
JS写滑稽笑脸运动效果
2020/05/28 Javascript
浅谈vue-props的default写不写有什么区别
2020/08/09 Javascript
小程序实现列表倒计时功能
2021/01/29 Javascript
python不换行之end=与逗号的意思及用途
2017/11/21 Python
pandas值替换方法
2018/07/10 Python
python之消除前缀重命名的方法
2018/10/21 Python
Django视图扩展类知识点详解
2019/10/25 Python
Python多进程编程常用方法解析
2020/03/26 Python
Expedia印度:您的一站式在线旅游网站
2017/08/24 全球购物
德国自行车商店:Tretwerk
2019/06/21 全球购物
欧姆龙医疗保健与医疗产品:Omron Healthcare
2020/02/10 全球购物
西式婚礼证婚词
2014/01/12 职场文书
十八届三中全会个人学习材料
2014/02/13 职场文书
家长会主持词开场白
2014/03/18 职场文书
中秋手机店促销方案
2014/06/16 职场文书
年度考核个人总结
2015/03/06 职场文书
劳动争议仲裁代理词
2015/05/25 职场文书
标枪加油稿
2015/07/22 职场文书
Python数据分析入门之教你怎么搭建环境
2021/05/13 Python
Python一行代码实现自动发邮件功能
2021/05/30 Python
SpringBoot项目中控制台日志的保存配置操作
2021/06/18 Java/Android