这是我参与「第四届青训营 」笔记创作活动的第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;
}