网页爬虫
Posted yxysuanfa
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网页爬虫相关的知识,希望对你有一定的参考价值。
一. 前言
近期要測试改动一个反爬虫代码, 之前一直没接触过反爬虫, 仅仅闻其声不见其人。
既然要反爬虫。 肯定要理解爬虫的思维方式, 见招拆招, 只是遗憾的是仅仅要你想爬没啥爬不到的, 比方控制下爬取频率, 用无数个代理小量多次爬取, 反爬虫仅仅能说是尽量添加一些爬取的门槛吧, 至少把一些练手的小爬虫(比方如今这个小菜鸡爬虫)挡在外面。 降低些负载。
二. 设计思路
(1)一个收集所需网页全站或者指定子域名的链接队列
(2)一个存放将要訪问的URL队列(跟上述有点反复, 用空间换时间。 提升爬取速度)
(3)一个保存已訪问过URL的数据结构
数据结构有了, 接下来就是算法了, 一般推荐採取广度优先的爬取算法, 免得中了反爬虫的某些循环无限深度的陷阱。
使用了 jsoup (一个解析html元素的Lib)和 httpclient (网络请求包)来简化代码实现。
三. 代码实现
上述三种数据结构:
// 已爬取URL <URL, isAccess> final static ConcurrentHashMap<String, Boolean> urlQueue = new ConcurrentHashMap<String, Boolean>(); // 待爬取URL final static ConcurrentLinkedDeque<String> urlWaitingQueue = new ConcurrentLinkedDeque<String>(); // 待扫描网页URL队列 final static ConcurrentLinkedDeque<String> urlWaitingScanQueue = new ConcurrentLinkedDeque<String>();
/** * url store in the waiting queue * @param originalUrl * @throws Exception */ private static void enterWaitingQueue(final String originalUrl) throws Exception{ String url = urlWaitingScanQueue.poll(); // if accessed, ignore the url /*while (urlQueue.containsKey(url)) { url = urlWaitingQueue.poll(); }*/ final String finalUrl = url; Thread.sleep(600); new Thread(new Runnable() { public void run() { try{ if (finalUrl != null) { Connection conn = Jsoup.connect(finalUrl); Document doc = conn.get(); //urlQueue.putIfAbsent(finalUrl, Boolean.TRUE); // accessed logger.info("扫描网页URL: " + finalUrl); Elements links = doc.select("a[href]"); for (int linkNum = 0; linkNum < links.size(); linkNum++) { Element element = links.get(linkNum); String suburl = element.attr("href"); // 某条件下, 而且原来没訪问过 if (!urlQueue.containsKey(suburl)) { urlWaitingScanQueue.offer(suburl); urlWaitingQueue.offer(suburl); logger.info("URL入队等待" + linkNum + ": " + suburl); } } } } } catch (Exception ee) { logger.error("muti thread executing error, url: " + finalUrl, ee); } } }).start(); }
訪问页面:
private static void viewPages() throws Exception{ Thread.sleep(500); new Thread(new Runnable() { @Override public void run() { try { while(!urlWaitingQueue.isEmpty()) { String url = urlWaitingQueue.peek(); final String finalUrl = url; // build a client, like open a browser CloseableHttpClient httpClient = HttpClients.createDefault(); // create get method, like input url in the browser //HttpGet httpGet = new HttpGet("http://www.dxy.cn"); HttpPost httpPost = new HttpPost(finalUrl); StringBuffer stringBuffer = new StringBuffer(); HttpResponse response; //List<NameValuePair> keyValue = new ArrayList<NameValuePair>(); // Post parameter // keyValue.add(new BasicNameValuePair("username", "zhu")); // // httpPost.setEntity(new UrlEncodedFormEntity(keyValue, "UTF-8")); // access and get response response = httpClient.execute(httpPost); // record access URL urlQueue.putIfAbsent(finalUrl, Boolean.TRUE); if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { HttpEntity httpEntity = response.getEntity(); if (httpEntity != null) { logger.info("viewPages訪问URL:" + finalUrl); BufferedReader reader = new BufferedReader( new InputStreamReader(httpEntity.getContent(), "UTF-8")); String line = null; if (httpEntity.getContentLength() > 0) { stringBuffer = new StringBuffer((int) httpEntity.getContentLength()); while ((line = reader.readLine()) != null) { stringBuffer.append(line); } System.out.println(finalUrl + "内容: " + stringBuffer); } } } } } catch (Exception e) { logger.error("view pages error", e); } } }).start(); }
三. 总结及将来要实现功能
以上贴出了简易版Java爬虫的核心实现模块, 基本上拿起来就能測试。
比方前言所提到的控制爬取速度(调度模块), 使用代理IP訪问(收集网络代理模块)的实如今兴许版本号中会慢慢加上...
以上是关于网页爬虫的主要内容,如果未能解决你的问题,请参考以下文章