java爬蟲系列第五講-如何使用代理防止爬蟲被屏蔽?


本文內容

1、分析一下爬蟲存在的問題及解決方案

2、webmagic中代理的使用

3、目前市面上一些比較好用的代理服務器

存在的問題

我們在使用爬蟲過程中,大多都會遇到這樣的問題:突然某一天爬蟲爬不到內容了,目標網站直接返回404或者其他錯誤信息,這說明我們的爬蟲被目標網站給屏蔽了。

爬蟲被屏蔽的原因

1、爬蟲大量請求對對目標服務器造成了壓力

2、爬蟲采集目標網站有價值的內容到處傳播,對目標網站造成了不良影響

出於以上原因,正常情況下目標網站會把爬蟲屏蔽掉,這樣直接導致我們開發的爬蟲無法采集正確的內容。

未使用代理的情況

我們的爬蟲程序以一個固定的ip去訪問目標網站,目標網站會發現這個固定的ip有大量的請求,會判定為爬蟲,直接進行屏蔽。

如果我們每次請求發送的ip都不一樣,這樣目標網站一般情況下就不會把我們當成爬蟲屏蔽了。

解決辦法

使用代理來解決問題

請求過程如下:

1、爬蟲采集請求給代理服務器

2、代理服務器一般是一個集群,內部有很多機器,代理隨機選擇一台機器,將請求發送給目標服務器

3、目標服務器將結果返回給代理服務器

4、代理服務器將結果返回給爬蟲

可以看出,整個系統的穩定性在代理服務器上,代理服務器的質量直接影響到整個程序的穩定性。

webmagic中使用代理

從0.7.1版本開始,WebMagic開始使用了新的代理APIProxyProvider。因為相對於Site的“配置”,ProxyProvider定位更多是一個“組件”,所以代理不再從Site設置,而是由HttpClientDownloader設置。

API 說明
HttpClientDownloader.setProxyProvider(ProxyProvider proxyProvider) 設置代理

ProxyProvider有一個默認實現:SimpleProxyProvider。它是一個基於簡單Round-Robin的、沒有失敗檢查的ProxyProvider。可以配置任意個候選代理,每次會按順序挑選一個代理使用。它適合用在自己搭建的比較穩定的代理的場景。

代理示例:

1、設置單一的普通HTTP代理為101.101.101.101的8888端口,並設置密碼為"username","password"

HttpClientDownloader httpClientDownloader = new HttpClientDownloader();
httpClientDownloader.setProxyProvider(SimpleProxyProvider.from(new Proxy("101.101.101.101",8888,"username","password")));
spider.setDownloader(httpClientDownloader);

2、設置代理池,其中包括101.101.101.101和102.102.102.102兩個IP,沒有密碼

HttpClientDownloader httpClientDownloader = new HttpClientDownloader();
        httpClientDownloader.setProxyProvider(SimpleProxyProvider.from(new Proxy("101.101.101.101", 8888), new Proxy("102.102.102.102", 8888)));

免費代理服務器

1、目前用的還不錯的有快代理,有免費 和 收費版,如果是咱們自己搞着玩,可以使用免費版的,如果對代理服務器要求比較高,可以用他們的付費版的。我之前做過一個爬取財經數據的程序,對代理要求比較高,使用的是他們的收費版的,用下來還可以的。如果你們有發現更好的,可以留言,分享分享,謝謝

對於快代理我這邊提供一個代理代碼,可以拿去直接用:

public class KuaidailiProxyProvider implements ProxyProvider {
    private Logger logger = Logger.getLogger(KuaidailiProxyProvider.class);

    private List<Proxy> proxyList = new ArrayList<>();
    private volatile Map<String, ArrayBlockingQueue<Proxy>> siteProxysMap = new HashMap<String, ArrayBlockingQueue<Proxy>>();
    private Object siteProxysMapLock = new Object();
    //獲取代理信息的地址
    private String apiurl;
    //用戶名
    private String username;
    //密碼
    private String password;
    private volatile static KuaidailiProxyProvider instance = null;

    public KuaidailiProxyProvider(String apiurl, String username, String password) {
        this.apiurl = apiurl;
        this.username = username;
        this.password = password;
        this.init();
    }

    public static KuaidailiProxyProvider getInstance(String apiurl, String username, String password) {
        if (instance == null) {
            synchronized (KuaidailiProxyProvider.class) {
                if (instance == null) {
                    instance = new KuaidailiProxyProvider(apiurl, username, password);
                }
            }
        }
        return instance;
    }

    private void init() {
        try {
            logger.info("get proxy");
            String s = HttpsUtil.requestGet(this.apiurl);
            logger.info(s);
            if (StringUtil.isNotEmpty(s)) {
                final JSONObject jsonObject = JSON.parseObject(s);
                if (jsonObject == null) {
                    return;
                }
                final JSONObject data = jsonObject.getJSONObject("data");
                if (data == null) {
                    return;
                }
                final JSONArray proxy_list = data.getJSONArray("proxy_list");
                if (proxy_list == null && proxy_list.size() == 0) {
                    return;
                }
                List<String> tempList = new ArrayList<>();
                for (int i = 0; i < proxy_list.size(); i++) {
                    final String string = proxy_list.getString(i);
                    final String[] split = string.split(":");
                    proxyList.add(new Proxy(split[0], Integer.parseInt(split[1]), this.username, this.password));
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
    }

    private ArrayBlockingQueue<Proxy> get(String key) {
        try {
            ArrayBlockingQueue<Proxy> queue = siteProxysMap.get(key);
            if (queue == null) {
                synchronized (siteProxysMapLock) {
                    queue = siteProxysMap.get(key);
                    if (queue == null) {
                        ArrayBlockingQueue<Proxy> proxies = new ArrayBlockingQueue<Proxy>(proxyList.size());
                        for (Proxy proxy : proxyList) {
                            proxies.put(proxy);
                        }
                        siteProxysMap.put(key, proxies);
                    }
                }
            }
        } catch (InterruptedException e) {
            this.logger.error(e.getMessage(), e);
        }
        return siteProxysMap.get(key);
    }

    @Override
    public void returnProxy(Proxy proxy, Page page, Task task) {
        this.logger.info(proxy);
        try {
            String key = getKey(task);
            this.get(key).put(proxy);
        } catch (InterruptedException e) {
            this.logger.error(e.getMessage(), e);
        }
    }

    private String getKey(Task task) {
        final String domain = task != null && task.getSite() != null ? task.getSite().getDomain() : null;
        return StringUtil.isNotEmpty(domain) ? domain : KuaidailiProxyProvider.class.getName();
    }

    @Override
    public Proxy getProxy(Task task) {
        Proxy proxy = null;
        try {
            proxy = this.get(this.getKey(task)).take();
            this.logger.info(proxy);
        } catch (InterruptedException e) {
            logger.error(e.getMessage(), e);
        }
        return proxy;
    }
}

調用KuaidailiProxyProvider.getInstance獲取代理實例。

可以關注公眾號:路人甲Java,獲取年薪50萬課程,獲取最新文章。


免責聲明!

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



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