Scrapy-发起相同请求得到不同的返回结果原因及解决方法

今天遇到一个玄学问题,使用相同的url,请求头headers,请求体data,在通过

>> requests.post(url,headers=headers,data=data)

请求的时候,响应没有问题,而在使用

>> r=scrapy.Request(url,method='POST',headers=headers,body=data)
>> fetch(r)

的时候却响应403错误!?以上代码均在scrapy shell内运行,经过多次尝试,发现每当开启一个新的scrapy shell,第一次的响应是正确的,但是第二次开始就响应403。我们知道,HTTP协议是基于文本的,如果返回的内容不一致,只有两种可能:

1.HTTP请求不同

2.HTTP请求相同,但是服务器基于时间,请求频率等其他信息响应不同内容(反爬)

由于我们是在scrapy shell里调试,不存在频次过高的问题,且特征是新的scrapy shell第一次请求没问题,由此推测scrapy shell第一次和第二次的请求不一致!如何验证?有两种方法:

1)scrapy shell调试查看请求头

我们通过response.request.headers可以查看响应对应的请求的请求头,或者直接通过request.headers查看请求头。需要注意的是,fetch()完成之后,request.headers就是刚刚请求的请求头,

>>> request=scrapy.Request(url,method='POST',headers=headers,body=data)
>>> request.headers
{b'Content-Type': [b'application/json']}
>>> fetch(request)
2020-03-04 20:15:44 [scrapy.core.engine] INFO: Spider opened
2020-03-04 20:15:45 [scrapy.core.engine] DEBUG: Crawled (200) <POST https://study.163.com/p/search/studycourse.json> (referer: None)
>>> request.headers
{b'Content-Type': [b'application/json'], b'Accept': [b'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'], b'Accept-Language': [b'en'], b'User-Agent': [b'Scrapy/1.8.0 (+https://scrapy.org)'], b'Accept-Encoding': [b'gzip,deflate']}
>>> fetch(request)
2020-03-04 20:20:34 [scrapy.core.engine] DEBUG: Crawled (403) <POST https://study.163.com/p/search/studycourse.json> (referer: None)
>>> request.headers
{b'Content-Type': [b'application/json'], b'Accept': [b'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'], b'Accept-Language': [b'en'], b'User-Agent': [b'Scrapy/1.8.0 (+https://scrapy.org)'], b'Accept-Encoding': [b'gzip,deflate'], b'Cookie': [b'NTESSTUDYSI=2998817e52464f8ba0b578d09bc449e3; EDUWEBDEVICE=bffdf353c8ec4f8eb7fc83aef5caf2d1']

可以看到,我们一开始只设置了Content-Type请求头,而第一次的实际请求头还包括了scrapy自动生成的User-Agent、Accept等。而第二次请求头比第一次多了Cookie头的信息,因此我们推断正是多了这个cookie我们的后续请求才会出现错误。

注意,第一次请求后可通过response.request.headers查看头,第二次请求由于403错误我们的response为None,只能通过request.headers查看请求头。

2)Fiddler抓包查看请求头

Fiddler开启抓包,分别执行两次fetch(request),查看对应的条目

 发现多出Cookie字段,与第一种方法得到的结果一致。

那么为什么会出现先后请求不一致的结果呢?因为scrapy默认会保留之前响应中Set-Cookie的cookie,并在下一次请求时带上这些cookie。scrapy中如何设置不太清楚,如果是在scrapy的爬虫类中,我们可以通过

custom_settings={
    'COOKIES_ENABLED' : False,
}

设置当前爬虫不使用cookie,这样就不会因为带上cookie而出错啦。

最后,我还是没太搞懂,这属于反爬虫的措施之一吗,还是服务端的某种逻辑需要?因为如果是反爬虫,为何不第一次就禁止爬虫访问?还是说这个cookie就是某种表示我是爬虫的标志,如果这样,为何不设计成“仅当获得一个有效的cookie才能获取相关数据”的模式?总之,这个搞了我很久的问题既有自己对scrapy了解不足的原因,也有这个奇怪服务端逻辑的原因。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章