Scrapy Request忽略请求返回Cookie,以及meta特殊参数浅析
  • 分类:Python
  • 发表:2018-11-29
  • 围观(4,411)
  • 评论(2)

问题由来

在Scrapy爬虫的开发过程中,由于爬取网页的限制,要求我们需要对Request进行深度构造,比如添加协议头,Cookie,Session等请求数据.Weiney在爬取一个小型网站时候发现,这个网站的数据是通过Get请求获取的,但是请求地址无需单独构造,因为数据返回是根据Get请求时附带的cookie判断的,不同的cookie返回不同的数据,由于cookie是不加密的,所以请求只需要构造不同的cookie即可,这个不难实现.但是网站的这种方式又给url去重带来了一定的难度,这又是,另外一个问题了,这里只讲解cookie这部分.

# 初始请求头
header = {
    'Host': 'www.weiney.com',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
    'Accept-Encoding': 'gzip, deflate',
    'Connection': 'keep-alive',
    'Cookie': 'SECURITY_USERID_COOKIE=2016101854;,
}

def parse(self, response):
    for year in range(2016, 2018):
        for id in range(1, 500000):
            uid = str(year * 1000000 + id)
            cookie = 'SECURITY_USERID_COOKIE={};'.format(uid) # 构造请求的cookie
            self.header["Cookie"] = cookie
            yield Request(self.start_urls[0],callback=self.parse_detail, headers=self.header) # 发送请求

但是问题出现了,每一个url我都有构造独立的cookie,但是为甚么抓取的内容都是相同的,也就是说我构造的cookie根本没有用,scrapy只使用的第一个构造的cookie,从而导致我的电脑下载了一堆一模一样的照片,这是什么愿意导致的呢?翻了一下文档,Request中有一个参数被我忽略了.先看看文档的说明.

其中有一个dont_filter参数,参数值为布尔类型,默认为False.文档解释为: 当您想要多次执行相同的请求时,可以使用此选项来忽略重复过滤器。由于构建的url都是相同的应该和这个参数有点联系,不管三七二十一先把参数加进去再试试,毕竟实践是检验真理的唯一标准.

但是当我加了这个参数之后,貌似情况并没有改变,问题依旧,那么问题就来了,到底是哪里的问题?

postman测试发现,请求发送成功时,服务器会重新给url分配cookie和session.因为在scrapy内spider的url都是不变的,所以在第一次成功的请求发送之后,scrapy会把服务器返回的cookie缓存至本地,当接下来有相同url的请求时,会把缓存的cookie带上,所以构造的cookie就被覆盖了,这貌似就是导致这次问题的罪魁祸首,通过简单的流程图看一下:

解决问题

为了解决问题,只能从文档入手,在文档我找到了Request的另外一个参数meta参数,meta参数我知道,一般是在用作上下文传参,当构建多级请求的时候,或许会需要将这次的某个数据保存到下次请求中使用,这个时候我们可以用dict的形式将数据保存到meta参数里面,meta标签会跟随response一起传递下去,这个用法很常见,但是文档告诉我,这个meta参数并没有那么简单.

meta作为一个dict,可以保存我们自定的字段,但是scrapy内同时赋值了几个特殊的字段,这几个字段的值将会影响Request的发送.

dont_redirect:禁止重定向
dont_retry:禁止重试
handle_httpstatus_list:处理的Http状态码
handle_httpstatus_all:处理所有Http状态码
dont_merge_cookies:不合并cookie
cookiejar dont_cache:不在cookiejar缓存
redirect_urls:重定向url
bindaddress:绑定地址
dont_obey_robotstxt:不遵守爬虫规则
download_timeout:下载超时时长
download_maxsize:下载文件最大尺寸
proxy:代理

这里的dont_merge_cookies参数貌似就是我们要找的参数,不合并cookie那么构造的cookie就不会被覆盖了,那么请求应该就没问题了吧,修正后的代码

# 初始请求头
header = {
    'Host': 'www.weiney.com',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
    'Accept-Encoding': 'gzip, deflate',
    'Connection': 'keep-alive',
    'Cookie': 'SECURITY_USERID_COOKIE=2016101854;,
}
def parse(self, response):
    for year in range(2016, 2018):
        for id in range(1, 500000):
            uid = str(year * 1000000 + id)
            cookie = 'SECURITY_USERID_COOKIE={};'.format(uid) # 构造请求的cookie
            self.header["Cookie"] = cookie
            yield Request(self.start_urls[0],callback=self.parse_detail, meta={"uid" : uid, "dont_merge_cookies" : True}, headers=self.header) # 发送请求

这样修改了,代码就没没问题了,这个小错误真是花了好长时间才解决,写篇文章记录一下,防止以后忘记


共有 2 条评论

  1. 不知名小粉丝

    真棒真棒!

    1. Avatar photo

      Continuity

      商业互吹一波

Top