通常我们在使用
Scrapy-redis
的时候初始请求是 Get 的情况下,我们可以通过重写 start_requests
方法来实现请求需求。但是如果我们要发送的是 post
请求,就不能简单的用上面的方法了。
scrapy-redis 源码阅读
用scrapy
发送POST
肯定没问题(重写start_requests
方法即可),但scrapy-redis
不同,scrapy-redis
框架只会从配置好的redis
数据库中读取起始url
,所以,在scrapy-redis
中,就算重写start_requests
方法也没用。怎么办呢?我们看看源码。
我们发现 RedisSpider
继承了 RedisMixin
所以我们跟进 RedisMixin
从start_requests
开始分析, 直接把所有任务丢给next_requests
方法
上面next_requests
方法中,关键的就是那个while
循环,每一次循环都调用了一个make_request_from_data
方法,从函数名可以函数,这个方法就是根据从redis
中读取从来的数据,实例化一个request
,那不就是我们要找的方法吗?
重写 make_request_from_data
from scrapy import FormRequest
from scrapy_redis.spiders import RedisSpider
class MeituanSpider(RedisSpider):
"""类似 start_requests"""
def make_request_from_data(self, data):
"""
重写make_request_from_data方法,data是scrapy-redis读取redis中的[url,form_data,meta],然后发送post请求
:param data: redis中都去的请求数据,是一个list
:return: 一个FormRequest对象
"""
data = json.loads(data)
url = data.get('url')
form_data = data.get('form_data')
meta = data.get('meta')
return FormRequest(url=url, formdata=form_data, meta=meta, callback=self.parse)
def parse(self, response):
pass
编写推入redis 程序
import redis
import json
"""decode_responses 写存的数据是字符串形式"""
r = redis.Redis() # 默认db=0
def push_start_url_data(request_data):
"""
将一个完整的request_data推送到redis的start_url列表中
:param request_data: {'url':url, 'form_data':form_data, 'meta':meta}
:return:
"""
r.lpush('XX:start_urls', request_data)
if __name__ == '__main__':
url = 'http://www.xxx.com'
form_data = {
"sourceType": "A"
}
meta = {
'search_key': '91650100MA786PE4XT',
'_id': '5f45b7eaeb898de3b4cafe34'
}
request_data = {
'url': url,
'form_data': form_data,
'meta': meta
}
push_start_url_data(json.dumps(request_data))
总结
redis-scrapy 开启后会阻塞等待 redis 请求需求推入,然后读取任务爬取, 如果用post的方法, 只需要重写 make_request_from_data
即可