问题由来
在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) # 发送请求
这样修改了,代码就没没问题了,这个小错误真是花了好长时间才解决,写篇文章记录一下,防止以后忘记
不知名小粉丝
真棒真棒!
Continuity
商业互吹一波