后续技术类文档更新到微信公众号-------->>喜欢的扫码关注
scrapy流程的新理解
-
start_urls谁构造的请求?
def start_requests(self): for url in self.start_urls: yield Request(url, dont_filter=True)
-
当爬虫开始运行时,首先引擎会调用爬虫类的start_requests()方法将start_urls列表中的所有url构造成请求对象,放入请求队列
-
start_requests()方法yield的请求,不经过爬虫中间件,不过滤域名是否超出allowed_domains
是不是所有的请求,放入调度器之前,都会经过爬虫中间件?
- start_urls构造的请求不经过
- 下载器中间件返回的request请求不经过
scrapy之模拟登陆
-
携带Cookie
def start_requests(self): for url in self.start_urls: yield Request(url, dont_filter=True,cookies=cookie_dict)
-
发送post请求
yield scrapy.FormRequest( url="https://github.com/session", formdata=formdata, callback=self.parse_login )
-
form表单请求
formdata = { "login": "noobpythoner", "password": "zhoudawei123" } # 发送请求 yield scrapy.FormRequest.from_response( response, formdata=formdata, callback=self.parse_login )
scrapy_redis
pip install scrapy_redis
scrapy_reids 只是scrapy的一个组件
- 增量式爬虫 ,请求持久化,下次接着爬取
- 分布式爬虫 ,reids共享
实现增量式爬虫
在settings.py中添加如下代码
# 指定了去重的类
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
# 指定了调度器的类
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
# 调度器的内容是否持久化
SCHEDULER_PERSIST = True
# redis的url
REDIS_URL = "redis://127.0.0.1:6379"
# 如果数据需要保存到redis中,选配的
ITEM_PIPELINES = {
'scrapy_redis.pipelines.RedisPipeline': 400,
}
生成指纹
def request_seen(self, request):
"""
生成请求指纹,并判断请求在不在指纹集合中
如果返回True,表示已经放入请求队列中了
返回False,表示该请求还未做过
"""
fp = self.request_fingerprint(request) #生成指纹
# This returns the number of values added, zero if already exists.
# 尝试将指纹放入指纹集合中,如果返回值为0,代表已经存在
added = self.server.sadd(self.key, fp)
return added == 0
def request_fingerprint(request):
"""
对请求生成指纹,利用hashlib的sha1对象,对request的url、method、body进行哈希,会产生一个40位16进制的字符串,作为request的指纹
"""
fp = hashlib.sha1()
fp.update(to_bytes(request.method))
fp.update(to_bytes(canonicalize_url(request.url)))
fp.update(request.body or b'')
return fp.hexdigest()
进入队列
def enqueue_request(self, request):
if not request.dont_filter and self.df.request_seen(request):
return False
self.queue.push(request)
return True
-
如果请求设置的过滤并且请求的指纹在指纹集合中存在的,不进入队列
-
其他情况会进入队列
-
start_url中由于yield请求时,默认设置了dont_filter为True,不过滤,所以肯定会进入队列
为啥设置start_urls为不过滤?
start_url是起始页,其他请求需要靠start_url对应的响应才能保证抓取
如何对数据进行去重?
- 数据存入mongodb的时候,可以对关键字段建立复合索引,实现去重
- 可以对数据的关键字段进行哈希映射,生成的指纹判断是否存在与指纹集合中,如果存在,说明数据重复
- 布隆过滤器,实现大数据量的去重