爬虫(1) - 网页下载 | 青训营笔记

86 阅读2分钟

这是我参与「第四届青训营 」笔记创作活动的第5天。

我们确定了目标为开发一个基于流式计算框架、遵循robots协议的分布式爬虫,并能够对爬取到的数据进行解析并存储。本文章就爬虫系统部分进行讲解。爬虫系统主要用来爬取数据、解析并存储,该模块较为独立,可以扩展到不同的计算框架下进行调度使用。

1. 随机ip代理

为了增强爬虫系统运行的稳定性,我们设置了随机ip代理来实现反反爬虫。具体来说,首先在resourses目录下新建一个txt文档来存储可用的代理地址,格式如下:

47.106.105.236:80
222.66.202.6:80
122.226.57.70:8888
...

然后,读入文件中的ip地址,并将ip名和端口号加载到内存中。

private static Map<String, Integer> IPProxyRepository = new HashMap<>();
private static String[] keysArray = null;

static {
    InputStream in = HttpUtil.class.getClassLoader().getResourceAsStream("IPProxyRepository.txt");  // 加载包含代理IP的文本
    // 构建缓冲流对象
    InputStreamReader isr = new InputStreamReader(in);
    BufferedReader bfr = new BufferedReader(isr);
    String line = null;
    try {
        // 循环读每一行,添加进map中
        while ((line = bfr.readLine()) != null) {
            String[] split = line.split(":");
            String host = split[0];
            int port = Integer.valueOf(split[1]);
            IPProxyRepository.put(host, port);
        }
        Set<String> keys = IPProxyRepository.keySet();
        keysArray = keys.toArray(new String[keys.size()]);
    } catch (IOException e) {
        e.printStackTrace();
    }

}

需要用到代理ip时,从map中随机取出一个ip地址。

public static HttpHost getRandomProxy() {
    Random random = new Random();
    String host = keysArray[random.nextInt(keysArray.length)];
    int port = IPProxyRepository.get(host);
    HttpHost proxy = new HttpHost(host, port);
    return proxy;
}

2. 下载网页

下载器部分,首先,为了方便之后的扩展,定义一个下载器接口。

public interface IDownload {
    /**
     * 下载给定url的网页数据
     * @param url
     * @return
     */
    public Page download(String url);
}

然后,我们定义一个http get的实现方法。

public class HttpGetDownloadImpl implements IDownload, Serializable {

    @Override
    public Page download(String url) {
        Page page = new Page();
        String content = HttpUtil.getHttpContent(url);
        page.setUrl(url);
        page.setContent(content);
        return page;
    }
}

具体实现时,我们基于java的httpclient库,向网页发送http请求,并获取网页的html内容。

public static String getHttpContent(String url) {

    CloseableHttpClient httpClient = null;
    HttpHost proxy = null;
    if (IPProxyRepository.size() > 0) {  // 如果ip代理地址库不为空,则设置代理
        proxy = getRandomProxy();
        httpClient = HttpClients.custom().setProxy(proxy).build();  // 创建httpclient对象
    } else {
        httpClient = HttpClients.custom().build();  // 创建httpclient对象
    }
    HttpGet request = new HttpGet(url); // 构建htttp get请求
    request.setHeader("user-agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.221 Safari/537.36 SE 2.X MetaSr 1.0");

    RequestConfig requestConfig = RequestConfig.custom()
            .setConnectTimeout(5000).setConnectionRequestTimeout(1000)
            .setSocketTimeout(5000).build();
    request.setConfig(requestConfig);
    String host = null;
    Integer port = null;
    if(proxy != null) {
        host = proxy.getHostName();
        port = proxy.getPort();
    }
    try {
        return EntityUtils.toString(response.getEntity());
    } catch (Exception e) {
        logger.error("下载网页出错,代理信息:{},", url, host + ":" + port);
        }
        e.printStackTrace();
    }

    return null;
}

参考 blog.51cto.com/xpleaf/2093…