1. 程式人生 > >http程式設計系列(二)——java爬蟲實現刷個人部落格的訪問量

http程式設計系列(二)——java爬蟲實現刷個人部落格的訪問量

實現功能

這裡實現的功能是一個根據個人部落格主頁,搜尋出所有的個人博文連結,然後一個一個去訪問,從而增加訪問量。這裡我發現一個問題,csdn既沒有做介面ip訪問量的限制,訪問量統計時也沒有做同一ip相同時間段的重複訪問重複計數的處理。這也時這個程式能夠刷訪問量的原因。

思路

進入個人部落格主頁,如我的部落格:”http://blog.csdn.net/luo4105”,它會出來一個部落格的列表(blogListPage),但是,它沒有顯示所有的部落格,而是分頁顯示,這裡我們就找到下一頁

的連結並訪問它,然後如此遞迴,直到尾頁為止。這樣我們就獲得了所有的分頁部落格的地址。然後訪問所有的分頁部落格,拿到它們的頁面資料,找出所有的部落格連結,訪問。

這裡工作就分為以下幾步

1.根據個人主頁url,訪問個人主頁並拿到頁面資料

2.找出下一頁的URL並訪問,重複該動作直到沒有下一頁,將每個url都存到set集合中

3.遍歷set集合,訪問所有的部落格列表頁面,獲得頁面資料,找到頁面資料中所有的部落格連結,存入部落格連結的set集合

4.遍歷部落格連結的set集合,訪問所有部落格連結

具體實現步驟

1.根據個人主頁url,訪問個人主頁並拿到頁面資料

訪問url,並拿到響應的程式碼如下,為了重複使用,我將其放入工具類中。

訪問URL並拿到響應程式碼

public class HttpUtil {  
    public static InputStream doGet(String urlstr) throws IOException {  
       URL url= new URL(urlstr);  
       HttpURLConnection conn= (HttpURLConnection) url.openConnection();
       conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36");
       InputStream inputStream= conn.getInputStream();  
       return inputStream;  
    }
}
將響應的InputStream轉成String的程式碼
public class StreamUtil {
    public static String inputStreamToString(InputStream is, String charset) throws IOException {  
       byte[] bytes = new byte[1024];  
       int byteLength = 0;  
       StringBuffer sb = new StringBuffer();  
       while((byteLength = is.read(bytes)) != -1) {  
           sb.append(new String(bytes, 0, byteLength, charset));  
       }  
       return sb.toString();  
    }  
}

綜合使用就是

public void addBlogListPageUrl(String pageUrl, Set<String> pagelistUrls) throws IOException {
	InputStream is = HttpUtil.doGet(pageUrl);
	String pageStr = StreamUtil.inputStreamToString(is, "UTF-8");
	is.close();
	System.out.println(pageStr);
}
這裡後臺輸出頁面的程式碼。

2.找出下一頁的URL並訪問,重複該動作直到沒有下一頁,將每個url都存到set集合中

開啟f12,我們來看下一頁是怎麼樣的。


這裡我們可以通過下面的正則匹配<a href=”xxxxxx”>下一頁</a>標籤

private String nextPagePanner = "<a href=\"/luo4105/article/list/[0-9]{1,10}\">下一頁</a>";	//下一頁的正則表示式
然後我們用正則匹配URL連結
private String nextPageUrlPanner = "/luo4105/article/list/[0-9]{1,10}";	//下一頁Url的正則表示式
加上匹配正則,功能程式碼如下
private String csdnBlogUrl = "http://blog.csdn.net/";
private String nextPagePanner = "<a href=\"/luo4105/article/list/[0-9]{1,10}\">下一頁</a>";	//下一頁的正則表示式
	private String nextPageUrlPanner = "/luo4105/article/list/[0-9]{1,10}";						//下一頁Url的正則表示式
/**
 * 通過下一頁,遍歷所有部落格目錄頁面連結
 * @param pageUrl		
 * @param pagelistUrls
 * @throws IOException
 */
public void addBlogListPageUrl(String pageUrl, Set<String> pagelistUrls) throws IOException {
	InputStream is = HttpUtil.doGet(pageUrl);
	String pageStr = StreamUtil.inputStreamToString(is, "UTF-8");
	is.close();
	Pattern nextPagePattern = Pattern.compile(nextPagePanner);
	Matcher nextPagematcher = nextPagePattern.matcher(pageStr);
	if (nextPagematcher.find()) {
		nextPagePattern = Pattern.compile(nextPageUrlPanner);
		nextPagematcher = nextPagePattern.matcher(nextPagematcher.group(0));
		if (nextPagematcher.find()) {
			pagelistUrls.add(csdnBlogUrl + nextPagematcher.group(0));
			System.out.println("成功新增部落格列表頁面地址:" + csdnBlogUrl + nextPagematcher.group(0));
			//addBlogListPageUrl(csdnBlogUrl + nextPagematcher.group(0), pagelistUrls);這是呼叫新增blog連結的方法
		}
	}
}

3.遍歷set集合,訪問所有的部落格列表頁面,獲得頁面資料,找到頁面資料中所有的部落格連結,存入部落格連結的set集合

我們先看看再blog列表頁面中的blog連結


匹配/luo4105/art......的正則如下

private String artlUrl = "/luo4105/article/details/[0-9]{8,8}";	//部落格utl的正則表示式
功能程式碼
private String artlUrl = "/luo4105/article/details/[0-9]{8,8}";								//部落格utl的正則表示式
/**
 * 新增搜尋部落格目錄的部落格連結
 * @param blogListURL 部落格目錄地址
 * @param artlUrls    存放部落格訪問地址的集合
 * @throws IOException
 */
public void addBlogUrl(String blogListURL, Set<String> artlUrls) throws IOException {
	InputStream is = HttpUtil.doGet(blogListURL);
	String pageStr = StreamUtil.inputStreamToString(is, "UTF-8");
	is.close();
	Pattern pattern = Pattern.compile(artlUrl);
	Matcher matcher = pattern.matcher(pageStr);
	while (matcher.find()) {
		String e = matcher.group(0);
		System.out.println("成功新增部落格地址:" + e);
		artlUrls.add(e);
	}
}
4.遍歷部落格連結的set集合,訪問所有部落格連結

程式碼如下

@Test
public void visitBlog() throws IOException {
	addBlogUrl();
	/** 這裡可以寫迴圈 **/
		for(String blogUrl : blogUrls) {
			String artlUrl = csdnBlogUrl + blogUrl;
			InputStream is = HttpUtil.doGet(artlUrl);
			if (is != null) {
				System.out.println(artlUrl + "訪問成功");
			}
			is.close();
		}
  /** 這裡可以寫迴圈 **/ 
}
貼出所有程式碼

訪問URL並拿到響應工具類

public class HttpUtil {  
    public static InputStream doGet(String urlstr) throws IOException {  
       URL url= new URL(urlstr);  
       HttpURLConnection conn= (HttpURLConnection) url.openConnection();
       conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36");
       InputStream inputStream= conn.getInputStream();  
       return inputStream;  
    }
}
將響應的InputStream轉成String的工具類
public class StreamUtil {
    public static String inputStreamToString(InputStream is, String charset) throws IOException {  
       byte[] bytes = new byte[1024];  
       int byteLength = 0;  
       StringBuffer sb = new StringBuffer();  
       while((byteLength = is.read(bytes)) != -1) {  
           sb.append(new String(bytes, 0, byteLength, charset));  
       }  
       return sb.toString();  
    }  
}
blog刷訪問類
/**
 * @author 逝夕誠
 * 刷csdn部落格訪問量
 */
public class AddCsdnBlogPV {

	private String csdnBlogUrl = "http://blog.csdn.net/";
	private String firstBlogListPageUrl = "http://blog.csdn.net/luo4105";				//部落格主頁
	private String nextPagePanner = "<a href=\"/luo4105/article/list/[0-9]{1,10}\">下一頁</a>";	//下一頁的正則表示式
	private String nextPageUrlPanner = "/luo4105/article/list/[0-9]{1,10}";				//下一頁Url的正則表示式
	private String artlUrl = "/luo4105/article/details/[0-9]{8,8}";					//部落格utl的正則表示式

	private Set<String> blogListPageUrls = new TreeSet<>();
	private Set<String> blogUrls = new TreeSet<>();
	
	@Test
	public void visitBlog() throws IOException {
		addBlogUrl();
			for(String blogUrl : blogUrls) {
				String artlUrl = csdnBlogUrl + blogUrl;
				InputStream is = HttpUtil.doGet(artlUrl);
				if (is != null) {
					System.out.println(artlUrl + "訪問成功");
				}
				is.close();
			}
	}

	/**
	 * @throws IOException
	 * 載入所有的bolg地址
	 */
	@Test
	public void addBlogUrl() throws IOException {
		blogListPageUrls.add(firstBlogListPageUrl);
		addBlogListPageUrl(firstBlogListPageUrl, blogListPageUrls);
		for (String bolgListUrl : blogListPageUrls) {
			addBlogUrl(bolgListUrl, blogUrls);
		}
	}

	/**
	 * 通過下一頁,遍歷所有部落格目錄頁面連結
	 * @param pageUrl	
	 * @param pagelistUrls
	 * @throws IOException
	 */
	public void addBlogListPageUrl(String pageUrl, Set<String> pagelistUrls) throws IOException {
		InputStream is = HttpUtil.doGet(pageUrl);
		String pageStr = StreamUtil.inputStreamToString(is, "UTF-8");
		is.close();
		Pattern nextPagePattern = Pattern.compile(nextPagePanner);
		Matcher nextPagematcher = nextPagePattern.matcher(pageStr);
		if (nextPagematcher.find()) {
			nextPagePattern = Pattern.compile(nextPageUrlPanner);
			nextPagematcher = nextPagePattern.matcher(nextPagematcher.group(0));
			if (nextPagematcher.find()) {
				pagelistUrls.add(csdnBlogUrl + nextPagematcher.group(0));
				System.out.println("成功新增部落格列表頁面地址:" + csdnBlogUrl + nextPagematcher.group(0));
				addBlogListPageUrl(csdnBlogUrl + nextPagematcher.group(0), pagelistUrls);
			}
		}
	}

	/**
	 * 新增搜尋部落格目錄的部落格連結
	 * @param blogListURL 部落格目錄地址
	 * @param artlUrls    存放部落格訪問地址的集合
	 * @throws IOException
	 */
	public void addBlogUrl(String blogListURL, Set<String> artlUrls) throws IOException {
		InputStream is = HttpUtil.doGet(blogListURL);
		String pageStr = StreamUtil.inputStreamToString(is, "UTF-8");
		is.close();
		Pattern pattern = Pattern.compile(artlUrl);
		Matcher matcher = pattern.matcher(pageStr);
		while (matcher.find()) {
			String e = matcher.group(0);
			System.out.println("成功新增部落格地址:" + e);
			artlUrls.add(e);
		}
	}
}
結果



結語

功能實現主要技術點是

1.java http的請求、響應。

2.正則的匹配。

今天是星期六又是520,我又孤獨的坐在寶安圖書館三樓期刊後面的角落,又默默的寫著這無聊到蛋疼的程式、以及教別人如何寫這無聊到蛋疼的部落格,念及此不覺潸然淚下。

相關推薦

http程式設計系列——java爬蟲實現個人部落訪問量

實現功能 這裡實現的功能是一個根據個人部落格主頁,搜尋出所有的個人博文連結,然後一個一個去訪問,從而增加訪問量。這裡我發現一個問題,csdn既沒有做介面ip訪問量的限制,訪問量統計時也沒有做同一ip相同時間段的重複訪問重複計數的處理。這也時這個程式能夠刷訪問量的原因。 思路

前端必知必會HTTP請求系列簡單一點的HTTP協議

http協議使用者客戶端和伺服器之間的通訊 http協議和TCP/IP協議族內的其他眾多協議相同,用於客戶端和伺服器之間的通訊。 那麼問題來個如果兩臺伺服器之間一臺伺服器向另一臺伺服器進行介面請求那誰是客戶端呢?所以這裡的客戶端和服務端是相對的概念,如果一端擔任客戶端的角色,另一端就需要擔任伺服器端的角色不

C++11多執行緒程式設計系列實戰

C++11 新標準中引入了多個頭檔案來支援多執行緒程式設計,他們分別是<atomic> ,<thread>,<mutex>,<condition_variable>和<future>。 <

爬蟲入門系列:優雅的HTTP庫requests

爬蟲入門系列目錄: urllib、urllib2、urllib3、httplib、httplib2 都是和 HTTP 相關的 Python 模組,看名字就覺得很反人類,更糟糕的是這些模組在 Python2 與 Python3 中有很大的差異,如果業務程式碼要同時相容 2 和 3,寫起來

Java Thread系列線程狀態

做的 tor throws 前臺 bject 線程休眠 enume 死鎖 做出 Java Thread系列(二)線程狀態 一、線程的五種狀態 新建狀態(New):新創建了一個線程對象,尚未啟動。 就緒狀態(Runnable):也叫可運行狀態。線程對象創建後,其他線程調用

Java基礎系列

集合 一、Java集合構架支援三種類型的集合:規則集(set)、線性表(list)和圖(map),它們分別定義在介面 Set 、List與 Map 中。 Set 的例項儲存一組互不相同的元素,List 的例項儲存一組順序排列的元素,Map的例項儲存一組物件,每個物件都有一個關聯的鍵值。

Java EE入門教程系列第一章Java EE的概述——Java EE技術框架和開發工具

1.3Java EE的技術框架 從技術的角度劃分,完整的Java EE分成了4個部分:元件技術、服務技術、通訊技術和架構技術。 下面給出的是一個適合初學者的體系結構簡化圖,暫時接觸不到的部分統一用“支援技術”表示,我們暫時只專注於與應用級開發相關的技術即可。 1.元件技術 這是

Python3爬蟲入門實戰系列爬取貓眼電影排行榜

在進行本節實戰之前,希望您對requests庫以及正則表示式有所瞭解。 執行平臺:windows Python版本: Python3.x 一、依賴庫的安裝 在本節實戰之前,請確保已經正確安裝了requests庫 requests庫的安裝 pip3 instal

HTTP系列—— 常見的HTTP狀態碼

目錄  1. 狀態碼的類別 2. 狀態碼詳解  2.1 成功狀態碼 2.2 重定向狀態碼 2.3 客戶端錯誤狀態碼 2.4 服務端錯誤狀態碼  HTTP狀態碼負責表示客戶端HTTP請求的返回結果、標記服務端處理是否正常、通知出現的

Java WebSocket程式設計:WebSocket實現主動推送互動

WebSocket協議 WebSocket協議通訊機制 WebSocket協議是獨立的、基於TCP的協議。其本質是先通過HTTP/HTTPS協議進行握手後建立一個用於交換資料的TCP連線,此後伺服器端與客戶器端通過此TCP連線進行實時通訊。 WebSocket開啟握手

Java併發程式設計——Java併發底層實現原理

Java程式碼會被編譯後變成Java位元組碼,位元組碼會被類載入器載入到JVM中,JVM執行位元組碼,最終轉化成彙編指令在CPU上執行,Java中所使用的併發機制依賴於JVM的實現和CPU的指令。 volatile 在多執行緒併發程式設計中,synchronized和volatile

Python和Java程式設計

題目:古典問題:有一對兔子,從出生後第3個月起每個月都生一對兔子,小兔子長到第三個月後每個月又生一對兔子,假如兔子都不死,問每個月的兔子總數為多少? 兔子的規律為數列1,1,2,3,5,8,13,21.... 觀察規律,可以發現,自從第三個月開始,每個月的兔子總數為前兩個月兔子總數之和。 Java實現

Java原始碼解析系列ArrayList原始碼解析

備註:以下都是基於JDK8 原始碼分析 ArrayList簡介        ArrayList 是一個數組佇列,相當於 動態陣列。與Java中的陣列相比,它的容量能動態增長。它繼承於AbstractList,實現了List, RandomAccess, Clonea

Java程式設計思想第14章-型別資訊

目錄: 1. RTTI(Runtime Type Identification)執行階段型別識別 1.1 用途:   為了確定基類指標實際指向的子類的具體型別。——《C++ Primer Plus》 1.2 工作原理:   通過型別轉換運算子回答“是否可以

Java併發程式設計系列避免死鎖

避免死鎖 (1)避免一個執行緒同時獲取多個鎖 (2)避免一個執行緒在鎖內佔用多個資源,儘量保證每個鎖只佔用一個資源 (3)使用定時鎖,使用lock.trylock(timeout)替代內部鎖機制 (4)

java經典程式程式設計知識

static修飾的屬性和方法在類初始化時載入,非靜態屬性和方法在物件初始化時載入。 "\n"表示換行 一個數能表示成某個數的平方的形式,則稱這個數為完全平方數。完全平方數是非負數。 【程式12】 題目:企業發放的獎金根據利潤提成。利潤(I)低於或等於10萬元時,獎金可提10%;利潤高於10萬元,低於2

java-web系列---以dockerfile的方式釋出java-web專案

前言 extensible專案當前功能模組如下: 如對該專案有疑問,可在我的部落格/github下面留言,也可以以郵件的方式告知。 我的聯絡方式:[email protected] Docker相關環境搭建 1.空白虛擬機器的“傻瓜式”安裝 安裝

開發一款開源爬蟲框架系列:設計爬蟲架構

  既然是構建分散式爬蟲架構,分散式說明爬蟲能在多臺機器同時執行,所以一定是多客戶端的,客戶端主要用於下載網頁,內容會放入佇列,多客戶端就有可能執行在不同的作業系統不同的語言環境,所以我們讓它暫時支援java和scala兩種依賴jvm的語言,不用區分平臺。提到客戶端也一定意味著有服務端的存在,服務端主要用於解

微醫網爬蟲 java實現

博主在之前的部落格(傳送門)中寫過使用爬蟲來採集微醫網的一些資訊,但是在採集醫生的歷史問診資訊時,網站卻使用了一些簡單的反爬機制阻礙我們採集這些資訊,這篇部落格主要來介紹一下如何爬取到微醫網醫生患者問診的資訊。爬蟲在採集每一頁的資訊時,一般都會在url中設定pages以及每頁

看透SpringMVC系列用NIO自己手動實現HTTP協議

我們知道HTTP協議是在應用層解析內容的,只需要按照它的報文格式封裝和解析資料就可以了,具體的傳輸還是使用的Socket。 因為HTTP協議是在接受到資料之後才會用到的:程式碼 package nio; import java.io.IOException; import java.net