scrapy-redis+selenium+webdriver解决动态代理ip和user-agent的问题(全网惟一完整代码解决方案)

问题描述:在爬取一些反爬机制作的比较好的网站时,常常会碰见一个问题就网站代码是经过js写的,这种就没法直接使用通常的爬虫工具爬取,这种状况通常有两种解决方案html

第一种:把js代码转为html代码,而后再使用html代码解析工具爬取,目前经常使用的工具是selenium和scrapy-splash,我使用的是第一个工具,第二个还有搞个docker服务,太麻烦程序员

第二种:本身观察js代码,找到存放数据的地方,直接获取,这种方式须要有js基础,反正我看到一堆乱七八糟的js就头大,这种方式passweb

 

下面就是第一种实现方式:redis

技术架构:scrapy-redis + selenium + webdriverdocker

解释:使用scrapy-redis进行分布式爬虫效率高,并且直接把url放到redis中,这种方式对于请求连接的管理很是简单, selenium这工具能够直接融入到scrapy中,做为一个中间件,至于这个中间件的原理,网上有不少资料,其实原理很简单,就是每次请求进来,先让selenium这中间件处理一下,把js代码转为html,而后直接return一个对象给spider进行爬虫,这个对象里面放的就是html,api

 

下面就是这个中间件的代码:浏览器

 

class SeleniumMiddleware(object):

    def __init__(self,timeout=25):
        profile = FirefoxProfile()
        profile.set_preference('permissions.default.image', 2)
        self.browser = webdriver.Firefox(profile)
        self.timeout = timeout
        self.browser.maximize_window()
        # # self.browser.implicitly_wait(20)
        self.browser.set_page_load_timeout(self.timeout)
        self.wait = WebDriverWait(self.browser, self.timeout)
    def __del__(self):
        self.browser.close()

    def process_request(self, request, spider):
        """
           用WebDriver抓取页面
           :param request: Request对象
           :param spider: Spider对象
           :return: HtmlResponse
           """
        logging.info('******WebDriver is Starting******')
        try:
     #这里的ip和port能够根据本身的状况填充,好比经过api获取的代理ip,或者从代理池中获取也能够
            ip = '60.182.17.174'
            port = '4224'
    #user_agent仍然能够动态修改,这里测试写死,网上有不少每次请求随机修改代理的user-agent的方法
    user_agent ='Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)'
            self.browser.get("about:config")
            script = '''
            var prefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
            prefs.setIntPref("network.proxy.type", 1);
            prefs.setCharPref("network.proxy.http", "{ip}");
            prefs.setIntPref("network.proxy.http_port", "{port}");
            prefs.setCharPref("network.proxy.ssl", "{ip}");
            prefs.setIntPref("network.proxy.ssl_port", "{port}");
            prefs.setCharPref("network.proxy.ftp", "{ip}");
            prefs.setIntPref("network.proxy.ftp_port", "{port}");
       prefs.setBoolPref("general.useragent.site_specific_overrides",true);
       prefs.setBoolPref("general.useragent.updates.enabled",true);
      prefs.setCharPref("general.useragent.override","{user_agent}");
            '''.format(ip = ip,port=port,user_agent=user_agent)
            self.browser.execute_script(script);
            time.sleep(1);
            self.browser.get(request.url)
            self.wait.until(EC.presence_of_element_located((By.XPATH, '//div[@class="s-result-list sg-row"]')))
            return HtmlResponse(url=request.url, body=self.browser.page_source, request=request, encoding='utf-8',
                            status=200)
        except TimeoutException:
            return HtmlResponse(url=request.url, status=500, request=request)

 

    
-------------------------------------------------姑娘滑溜溜的马甲线------------------------------------------------------



注意:这是网上目前能够找到的惟一个完整代码的解决方案,能够直接复制粘贴,上面都没有说重点,其实这里最重要的就是动态修改代理ip,网上不少资料都是当浏览器启动的时候指定代理ip,那若是想要更换代理ip,很差意思,重启浏览器,这种方式效率很是低,对于一个有追求的程序员来讲就是种耻辱

而后把这个中间件配置到settings中:
 
DOWNLOADER_MIDDLEWARES = {
    'scrapy.contrib.downloadermiddleware.useragent.UserAgentMiddleware' : None,  # 必需 ,禁用默认的middleware
    'amazon.custom_rewrite.SeleniumMiddlewares.SeleniumMiddleware': 541, #自定义selenium中间件
}
-------------------------------------------------姑娘滑溜溜的马甲线------------------------------------------------------
更新:上面只是解决了动态代理ip的问题,那如何解决动态修改浏览器头呢,很简单,只须要在上面的js中添加
prefs.setBoolPref("general.useragent.site_specific_overrides",true);
prefs.setBoolPref("general.useragent.updates.enabled",true);
prefs.setCharPref("general.useragent.override","{user_agent}");
-------------------------------------------------姑娘滑溜溜的马甲线------------------------------------------------------

2019-04-17更新:缓存

  上面的配置在运行的过程当中,浏览器通常运行几天以后就会崩溃, 我定位了好久才发现是浏览器内存泄露致使的,由于firefox浏览器默认是可使用缓存的,随着爬虫的运行,这就会使浏览器的缓存愈来愈大,从而致使内存架构

泄露,那怎么解决呢?很简单,直接把缓存给禁用了就能够,不过有的爬虫须要用缓存加快爬虫的速度,这种状况下我尚未想到好的处理办法,一个思路是定时启动浏览器,好比定时5个小时重启一次浏览器,可是这样子有点麻烦吧,下面是禁用scrapy

缓存的代码

prefs.setBoolPref("browser.cache.disk.enable", false);
prefs.setBoolPref("browser.cache.memory.enable", false);
prefs.setBoolPref("browser.cache.offline.enable", false);

 

 

说明:火狐浏览器从25版本以后就已经在about:config中没法找到general.useragent.override属性了,解决办法就是在about:config右键,新建-->字符串,添加这个属性就能够

相关文章
相关标签/搜索