scrapy-redis+selenium+webdriver解決動態代理ip和user-agent的問題(全網唯一完整代碼解決方案)


問題描述:在爬取一些反爬機制做的比較好的網站時,經常會遇見一個問題就網站代碼是通過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右鍵,新建-->字符串,添加這個屬性就可以


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM