crawler學習篇(jar爬取)
阿新 • • 發佈:2018-12-12
新建maven專案
匯入依賴的jar包
<dependencies> <!-- 新增Httpclient支援 --> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.2</version> </dependency> <!-- 新增jsoup支援 --> <dependency> <groupId>org.jsoup</groupId> <artifactId>jsoup</artifactId> <version>1.10.1</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.16</version> </dependency> </dependencies>
需要爬取的網址 :http://central.maven.org/
/** * 爬取網路資源的類 * @author Admin * *1、通過httpclient和jsoup爬取網頁,分析所有url *2、過濾無效url,迭代解析 *3、利用非同步執行緒池對爬取的效能進行優化 * */ public class StartCrawler { // 要過濾掉的url字尾 public static String[] excludeUrls = new String[] { ".pom", ".xml", ".md5", ".sha1", ".asc", ".gz", ".zip", "../" }; //佇列 先進先出 public static Queue<String> waitForCrawlerUrls = new LinkedList<String>();// 等待再次爬取的Url public static long total = 0;//計數 public static boolean exeFlag = true;//預設解析爬取佇列裡面的網址 /** * 通過網址url,利用httpclient技術,獲得當前url對應的網路內容 * @param url */ // public static void parseUrl(String url,String realDir) { public static void parseUrl() { // 利用非同步執行緒池 對爬取的效能進行優化 //存放10個非同步執行緒的執行緒池 ExecutorService executorService = Executors.newFixedThreadPool(10);//例項化一個執行緒池 池中放10個執行緒 while(exeFlag) {//需要滿足的條件 if(waitForCrawlerUrls.size() > 0) {//佇列裡有連結 executorService.execute(new Runnable() { //使用執行緒池中的非同步執行解析邏輯 public void run() { while(waitForCrawlerUrls.size() > 0) { String url = waitForCrawlerUrls.poll();//(隊列當中的取值)摘取佇列的第一個元素,並且移除 //CloseableHttpClient可以被用於從客戶端傳送HTTP請求到服務端 CloseableHttpClient httpClient = HttpClients.createDefault();//獲取httpclient的一個例項 HttpGet httpGet = new HttpGet(url);//獲得是什麼請求 //設定連線時長5秒和等待伺服器響應資料時長8秒 RequestConfig config = RequestConfig.custom().setConnectTimeout(5000).setSocketTimeout(8000).build(); httpGet.setConfig(config); CloseableHttpResponse response = null; //執行 try { //要抓異常是因為避免訪問超時 response = httpClient.execute(httpGet); if(response != null) { HttpEntity entity = response.getEntity();//獲取內容 //凡是text/html(網頁)這一型別的需要進行再次解析 if("text/html".equals(entity.getContentType().getValue())) { String pageContent = EntityUtils.toString(entity,"utf-8");//獲取網頁內容 parsePageContent(pageContent,url);//再次解析頁面的內容 } }else {//未得到響應 System.out.println("連線時間過長"); addUrl(url);//再次把連結加到隊列當中去 } } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { try { if(response != null) { response.close(); } if(httpClient != null) { httpClient.close(); } } catch (IOException e) { e.printStackTrace(); } } } } }); }else {//佇列裡沒有連結 if(((ThreadPoolExecutor)executorService).getActiveCount() == 0) {//要求執行緒池中沒有還在執行的執行緒 exeFlag = false; break; } } } //避免解析不過來讓執行緒休眠 try { Thread.sleep(1000);//(給執行緒解析的時間,避免出現問題) } catch (InterruptedException e) { e.printStackTrace(); } } /** * 通過網頁爬蟲爬蟲框架jsoup對網頁內容進行解析(再次解析頁面的內容) * @param pageContent */ public static void parsePageContent(String pageContent,String realDir) { Document doc = Jsoup.parse(pageContent);//jsp頁面中的doc樹 Elements aEles = doc.select("a");//通過doc獲取a標籤 for (Element aEle : aEles) { String aHref = aEle.attr("href"); // System.out.println(realDir + aHref);//所有的連結地址 String url = realDir + aHref; /** * 連結分為三種(以這個為例) * 目標連結(jar) * 過濾的連結(不需要的連結) * 迭代解析的連結(需要再次解析的連結) */ if(null == url || "".equals(url) ) return; boolean f = true;//預設就是我想要的連結 for (String excludeUrl : excludeUrls) { if(url.endsWith(excludeUrl)) {//url.endsWith(excludeUrl) 連結url以excludeUrl結尾 f = false;//不是需要的連結 break; } } if(f && url.endsWith(".jar")) { System.out.println("爬了第"+(++total)+"個目標,連結地址url為:"+ url); }else {//迭代解析的連結 addUrl(url);//加入到佇列裡面去,需要再一次爬取的 } } } /** * 新增到爬蟲佇列裡面,等待再一次爬取 * @param url */ private static void addUrl(String url) { System.out.println(url + "新增成功"); waitForCrawlerUrls.add(url); } /** * 給佇列提供初始值 */ public static void init() { String url = "http://central.maven.org/maven2/HTTPClient/HTTPClient/"; addUrl(url); addUrl("http://central.maven.org/maven2/commons-cli/commons-cli/"); parseUrl(); } public static void main(String[] args) { init(); } //未進行優化的程式碼 public static void version1() { //連結地址來自於隊列當中 while(waitForCrawlerUrls.size() > 0) { String url = waitForCrawlerUrls.poll();//(隊列當中的取值)摘取佇列的第一個元素,並且移除 //CloseableHttpClient可以被用於從客戶端傳送HTTP請求到服務端 CloseableHttpClient httpClient = HttpClients.createDefault();//獲取httpclient的一個例項 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()); //凡是text/html(網頁)這一型別的需要進行再次解析 if("text/html".equals(entity.getContentType().getValue())) { String pageContent = EntityUtils.toString(entity,"utf-8");//獲取網頁內容 parsePageContent(pageContent,url);//再次解析頁面的內容 // System.out.println(pageContent); } } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { try { if(response != null) { response.close(); } if(httpClient != null) { httpClient.close(); } } catch (IOException e) { e.printStackTrace(); } } } } }