Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 557|回复: 0

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

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-4-26 11:43:49 | 显示全部楼层 |阅读模式

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

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

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

     

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

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

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

     

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

     

    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个小时重启一次浏览器,但是这样子有点麻烦吧,下面是禁用

    缓存的代码

    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右键,新建-->字符串,添加这个属性就可以

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-12-23 09:53 , Processed in 1.705546 second(s), 28 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表