爬虫工作量由小到大的思维转变---<第十六章 Scrapy给项目装上神器---免费代理ip>

前言:

项目完成后,你要通过scrapy进行抓取;现在问题是,如果你还是用之前调好的延时爬取,你没必要用scrapy呀!那你这是什么效率,2-3秒抓一个url.疯了?

所以,这时候,我们需要给他装个ip_pool ; 没有它,你玩啥爬虫~爬蜗牛了就是;

正文:

抓ip的文章,我写在前面了

抓免费代理ip

拿到这些ip,存哪是你自己的事;我个人建议是存redis,因为他最快;

然后,ip的代理业务写在哪里呢? scrapy的中间件

我个人是希望重新开一个类,专门给他定义成代理ip的类:

import redis
import random
import time

class ProxyMiddleware:
    def __init__(self):
        self.redis_client = redis.Redis()
        self.ip_cache = []

    def process_request(self, request, spider):
        # 从缓存中获取一个代理IP,并设置为请求的代理
        proxy_ip = self.get_proxy_ip()
        request.meta['proxy'] = proxy_ip

    def process_response(self, request, response, spider):
        # 处理响应,若状态码为403或429,则移除请求所使用的代理IP
        if response.status in [403, 429]:
            self.remove_proxy_ip(request.meta['proxy'])
        return response

    def process_exception(self, request, exception, spider):
        # 处理异常,将请求所使用的代理IP从缓存中移除
        self.remove_proxy_ip(request.meta.get('proxy'))
        return None

    def get_proxy_ip(self):
        # 若IP缓存数量少于10个,则刷新缓存,获取新的代理IP
        if len(self.ip_cache) < 10:
            self.refresh_proxy_ips()
        return self.ip_cache.pop()

    def refresh_proxy_ips(self):
        # 若IP缓存数量少于10个,则从Redis获取新的代理IP,并加入缓存
        if len(self.ip_cache) < 10:
            proxy_ips = self.redis_client.smembers('ippool')
            for ip in proxy_ips:
                self.ip_cache.append(ip.decode())

    def remove_proxy_ip(self, proxy_ip):
        # 从缓存中移除指定的代理IP
        if proxy_ip in self.ip_cache:
            self.ip_cache.remove(proxy_ip)

    def start_requests(self):
        # 启动爬虫时,若IP缓存数量少于10个,则循环刷新缓存,直到达到10个IP为止
        while len(self.ip_cache) < 10:
            self.refresh_proxy_ips()
            if len(self.ip_cache) < 10:
                time.sleep(30)

1.首先,你不能每爬一个url,就去redis里面拿一个;要是这样,你scrapy是异步抓取的,光拿ip对redis的请求就足够让你的程序爆了;

2.把ip全部放在scrapy内部缓存里面,这样提速,几十个 几百个ip,足够玩一阵子;

3.当scrapy发起请求,就拿一个ip,如果返回来的response.state有问题,就换一个ip再来一次;同时,在缓存里面,把这个失效(无用的ip)删掉;

4.当你缓存的ip少于X的时候,就再去redis里面拿ip;

5.如果redis里面的ip供应不过来,就让他等待一阵子再去拿;

--------------基本思路就是如此!

你可能感兴趣的:(15天玩转高级python,爬虫,scrapy,tcp/ip)