简介
1. 什么是网络爬虫:
网络爬虫(又被称为网也蜘蛛,网络机器人,在FOAF社区中间,更经常称为网页追逐者。)
作用
网络蜘蛛是用过网页的链接地址来寻找网页。
从网站某一个页面(通常是首页)开始,读取网页的内容,找到在网页中的其它链接地址,然后通过这些链接地址寻找下一个网页,这样一直循环下去,直到把这个网站所有的网页都抓取完为止。如果把整个互联网当成一个网站,那么网络蜘蛛就可以用这个原理把互联网上所有的网页都抓取下来。
网络爬虫的思路以及实现
解析网络类资源的方法,通过网络URL,是利用HTTPclient技术,获取网络资源类容。
// 解析网络资源类的方法
// 用过网络URL,是利用HTTPclient技术,获取网络资源类容
//定义需要过滤的文件后缀
private static String[] fiterUrls = new String[] { ".com/tv/", ".htm" };
//定义队列(所放的是需要再次解析的URL)
private static Queue<String> waitForCrawler = new LinkedList<String>();
//爬取目标的总数
private static long total = 0;
public static void parseUrl() {
while (waitForCrawler.size() > 0) {
// 摘取队列的url,并摘除掉
String url = waitForCrawler.poll();
CloseableHttpClient httpClient = HttpClients.createDefault();
// 获取一个请求
HttpGet httpGet = new HttpGet(url);
// 关闭响应
CloseableHttpResponse response = null;
try {
response = httpClient.execute(httpGet);
HttpEntity entity = response.getEntity();
// System.out.println(entity.getContentType().toString());
// System.out.println(entity.getContentType().getValue());
/**
* 获取此类型的url,需要再次解析
*/
if ("text/html; charset=GB2312".equals(entity.getContentType().getValue())) {
/**
* 获取网页内容
*/
String pageContent = EntityUtils.toString(entity, "utf-8");
// System.out.println("网页内容"+pageContent);
parsepageContent(pageContent, url);
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭资源
if (response != null) {
try {
response.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (httpClient != null) {
try {
httpClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
通过网络爬虫框架对网进行再次解析
1.
private static void parsepageContent(String pageContent, String realDir) {
// 节点
Document doc = Jsoup.parse(pageContent);
//获取节点元素
Elements aEles = doc.select("a");
for (Element aEle : aEles) {
// 获取网页url
String aHref = aEle.attr("href");
// System.out.println(aHref);
// 获取真实url地址
String url = realDir + aHref;
System.out.println(url);
if (url == null || "".equals(url)) {
return;
}
/**
* 1目标链接 2 需要过滤的链接 3需要迭代解析的链接
*/
boolean f = true;// 假设就是我们需要的目标资源
/**
* 循环遍历所有url
*/
for (String filterUrl : fiterUrls) {
// 如果所遍历的url与你定义不需要的文件后缀,就过滤掉
if (url.endsWith(filterUrl)) {
f = false;
break;
}
}
if (f && url.endsWith(".html")) {
System.out.println("爬取了第" + (++total) + "个目标文件,url为:" + url);
} else {
//需要再次爬取的URL
addUrl(url);
}
}
}
添加到爬虫队列,等待再次爬取
private static void addUrl(String url) {
System.out.println(url + "被添加到爬虫队列");
waitForCrawler.add(url);
}
初始化方法
public static void init() {
// String url = "https://www.qq.com/";
//网络URL被放进队列中,默认一个被解析的网络url
addUrl("https://www.qq.com/");
parseUrl();
}
main方法测试
public static void main(String[] args) {
// // 默认一个网页的链接地址
// String url = "https://www.qq.com/";
// // 解析url
// parseUrl(url, url);
init();
}
网络爬虫框架所需要的jar包
HTTPclient点击下载
jsoup点击下载
log4j点击下载
引用到你的项目里面就ok了
注意此时的网络爬虫的性能是非常差的。所以进行了进一步优化
利用异步线程池进行优化
1.默人解析爬虫队列的URL(全局变量),创建能存放10个异步线程的线程池
public static boolean exeFlag = true;// 默认解析爬虫队列中的url
// 创建能存放10个异步线程的线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
2,使用异步线程池进行逻辑解析
// 使用线程中的线程池中的异步线程解析逻辑
executorService.execute(new Runnable() {
@Override
public void run() {
while (waitForCrawler.size() > 0) {
// 摘取队列的url,并以除掉
String url = waitForCrawler.poll();
CloseableHttpClient httpClient = HttpClients.createDefault();
// 获取一个请求
HttpGet httpGet = new HttpGet(url);
// 设置连接时间5秒,等待服务器响应数据时间10秒
RequestConfig config = RequestConfig.custom().setConnectTimeout(5000)
.setSocketTimeout(10000).build();
httpGet.setConfig(config);
3,这是逻辑判断的else
// 获取正在执行爬虫任务的线程数
if (((ThreadPoolExecutor) executorService).getActiveCount() == 0) {
exeFlag = false;
break;
}
4,为了尽可能避免意外的发生,给点一个休眠时间
Thread.sleep(1000);