关于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使用Supervisor来管理进程的方法
May 28 Python
Python极简代码实现杨辉三角示例代码
Nov 15 Python
python隐藏终端执行cmd命令的方法
Jun 24 Python
Python绘制频率分布直方图的示例
Jul 08 Python
python3 写一个WAV音频文件播放器的代码
Sep 27 Python
Django1.11自带分页器paginator的使用方法
Oct 31 Python
Python selenium抓取虎牙短视频代码实例
Mar 02 Python
python数据库编程 Mysql实现通讯录
Mar 27 Python
python的flask框架难学吗
Jul 31 Python
Python爬虫之Selenium下拉框处理的实现
Dec 04 Python
python flask框架快速入门
May 14 Python
Pytorch可视化的几种实现方法
Jun 10 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
thinkPHP框架实现的短信接口验证码功能示例
2018/06/20 PHP
phpStudy vscode 搭建debug调试的教程详解
2020/07/28 PHP
THINKPHP5分页数据对象处理过程解析
2020/10/28 PHP
JQuery动画和停止动画实例代码
2013/03/01 Javascript
图片延迟加载的实现代码(模仿懒惰)
2013/03/29 Javascript
基于jquery的网站幻灯片切换效果焦点图代码
2013/09/15 Javascript
Javascript学习笔记之相等符号与严格相等符号
2014/11/23 Javascript
javascript实现表格增删改操作实例详解
2015/05/15 Javascript
原生js实现的贪吃蛇网页版游戏完整实例
2015/05/18 Javascript
巧用jQuery选择器提高写表单效率的方法
2016/08/19 Javascript
微信小程序 progress组件详解及实例代码
2016/10/25 Javascript
Bootstrap DateTime Picker日历控件简单应用
2017/03/25 Javascript
mongoose设置unique不生效问题的解决及如何移除unique的限制
2017/11/07 Javascript
cnpm加速Angular项目创建的方法
2018/09/07 Javascript
JavaScript实现无限级递归树的示例代码
2019/03/29 Javascript
微信小程序 弹窗输入组件的实现解析
2019/08/12 Javascript
nodejs语言实现验证码生成功能的示例代码
2019/10/13 NodeJs
Node如何后台数据库使用增删改查功能
2019/11/21 Javascript
JS实现横向轮播图(中级版)
2020/01/18 Javascript
vue单文件组件无法获取$refs的问题
2020/06/24 Javascript
python中使用urllib2伪造HTTP报头的2个方法
2014/07/07 Python
Python存取XML的常见方法实例分析
2017/03/21 Python
pandas表连接 索引上的合并方法
2018/06/08 Python
Python3.0中普通方法、类方法和静态方法的比较
2019/05/03 Python
Python matplotlib以日期为x轴作图代码实例
2019/11/22 Python
Python基于numpy模块实现回归预测
2020/05/14 Python
利用CSS3的定位页面元素
2009/08/29 HTML / CSS
一个不错的HTML5 Canvas多层点击事件监听实例
2014/04/29 HTML / CSS
美国专注于健康商品的网站:eVitamins
2017/01/23 全球购物
Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是equals()? 它们有何区别?用contains来区分是否有重复的对象。还是都不用
2013/07/30 面试题
2019年Java 最常见的 面试题
2016/10/19 面试题
五四青年节的活动方案
2014/08/20 职场文书
工作失误检讨书(3篇)
2014/10/11 职场文书
寻找最美乡村教师观后感
2015/06/18 职场文书
婚礼双方父亲致辞
2015/07/27 职场文书
2016形势与政策学习心得体会
2016/01/12 职场文书