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右鍵,新建-->字符串,添加這個屬性就能夠

相關文章
相關標籤/搜索