1、前言 html
相信你們平時確定會收到朋友發來的連接,打開一看,哦,須要投票。投完票後彈出一個頁面(恭喜您,您已經投票成功),再次點擊的時候發現,啊哈,您的IP(***.***.***.***)已經投過票了,不能重複投票。這時候,咱們可能會想,能不能突破ip地址的限制進行刷票呢?有了這樣的想法,那就去作吧,下面我將介紹我這個簡單的刷票系統,僅供有需求的園友們參考。java
2、系統設計node
系統主要實現的是突破IP限制進行刷票,其中,由IP採集模塊負責從互聯網上爬取代理IP,放入阻塞隊列,該任務會按期執行。以後由投票模塊從阻塞隊列中獲取IP,並進行設置,而後進行投票。系統流程圖以下:git
3、系統技術github
系統使用HttpClient + JSoup + 多線程來完成刷票,HttpClient用於進行投票,JSoup用於解析頁面,多線程技術用於分離任務,使得分工更加明確。使用到了生產者消費者模式,該模式直接使用BlockingQueue來實現。apache
4、系統介紹多線程
系統主要分爲三個模塊:框架
① IP採集模塊ide
② 投票模塊網站
③ IP信息模塊
其中,IP採集模塊主要是從互聯網爬取IP代理信息,並將該信息放入阻塞隊列,這樣就能夠僞造IP,進行屢次投票。
其中,投票模塊從IP採集模塊放入阻塞隊列取出IP信息,並設置代理,找到投票入口地址,而後進行投票操做。
其中,IP信息模塊主要是對爬取的IP信息進行了封裝,方便其餘模塊進行操做。
4.1 IP採集模塊
IP採集模塊流程圖以下
幾點說明:
1.系統使用的代理IP站點URL爲http://www.kuaidaili.com/,www.xicidaili.com。
2.提取IP信息爲提取單條IP信息,並判斷歷史IP表是否已經存在,若存在,表示以前已經加入過此IP信息,則直接丟棄,反之,則加入隊列並加入歷史IP表。
3.此任務會按期開啓,如一個小時爬取一次代理IP。
4.2 投票模塊
投票模塊流程圖以下
幾點說明:
1.投票網站http://www.hnxdf.com/vote/,咱們選取的第一位進行投票,分析出投票的入口爲http://www.hnxdf.com/vote/iRadio_vote.asp?VoTeid=215。
2.根據IP採集模塊放入隊列的IP信息進行設置,而後進行投票。
4.3 IP信息模塊
此模塊主要對從網站爬取的IP信息進行了封裝,方便其餘模塊進行操做。
5、系統代碼框架
系統的整個代碼框架以下
其中,bean包的IpInfo封裝了爬取的IP信息。
其中,entrance包的Vote爲系統的入口。
其中,thread包的IPCollectTask爲爬取代理IP任務,VoteThread爲進行投票線程。
6、系統代碼
1.IpInfo.java
package com.hust.grid.leesf.bean; public class IpInfo { public IpInfo(String ipAddress, int port, String location, String anonymousType, String type, String confirmTime) { this(ipAddress, port, location, anonymousType, type, confirmTime, null, null); } public IpInfo(String ipAddress, int port, String location, String anonymousType, String type, String confirmTime, String getPostSupport, String responseSpeed) { this.ipAddress = ipAddress; this.port = port; this.location = location; this.anonymousType = anonymousType; this.type = type; this.confirmTime = confirmTime; this.getPostSupport = getPostSupport; this.responseSpeed = responseSpeed; } public String getIpAddress() { return ipAddress; } public void setIpAddress(String ipAddress) { this.ipAddress = ipAddress; } public int getPort() { return port; } public void setPort(int port) { this.port = port; } public String getLocation() { return location; } public void setLocation(String location) { this.location = location; } public String getAnonymousType() { return anonymousType; } public void setAnonymousType(String anonymousType) { this.anonymousType = anonymousType; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getConfirmTime() { return confirmTime; } public void setConfirmTime(String confirmTime) { this.confirmTime = confirmTime; } public String getGetPostSupport() { return getPostSupport; } public void setGetPostSupport(String getPostSupport) { this.getPostSupport = getPostSupport; } public String getResponseSpeed() { return responseSpeed; } public void setResponseSpeed(String responseSpeed) { this.responseSpeed = responseSpeed; } @Override public boolean equals(Object anthor) { if (this == anthor) { return true; } if (anthor == null || getClass() != anthor.getClass()) { return false; } IpInfo ipInfo = (IpInfo) anthor; return (this.ipAddress.equals(ipInfo.ipAddress) && this.port == ipInfo.port && this.location.equals(ipInfo.location) && this.anonymousType.equals(ipInfo.anonymousType) && this.type.equals(ipInfo.type) && this.confirmTime .equals(ipInfo.confirmTime)) && this.getPostSupport.equals(ipInfo.getPostSupport) && this.responseSpeed.equals(ipInfo.responseSpeed); } @Override public int hashCode() { int hash = 5; hash = 89 * hash + (this.ipAddress != null ? this.ipAddress.hashCode() : 0); hash = 89 * hash + this.port; hash = 89 * hash + (this.location != null ? this.location.hashCode() : 0); hash = 89 * hash + (this.anonymousType != null ? this.anonymousType.hashCode() : 0); hash = 89 * hash + (this.type != null ? this.type.hashCode() : 0); hash = 89 * hash + (this.confirmTime != null ? this.confirmTime.hashCode() : 0); hash = 89 * hash + (this.getPostSupport != null ? this.getPostSupport.hashCode() : 0); hash = 89 * hash + (this.responseSpeed != null ? this.responseSpeed.hashCode() : 0); return hash; } @Override public String toString() { return "ipAddress = " + ipAddress + ", port = " + port + ", localtion = " + location + ", anonymousType = " + anonymousType + ", type = " + type + ", confirmTime = " + confirmTime + ", getPostSupport = " + getPostSupport + ", responseSpeed = " + responseSpeed; } private String ipAddress; private int port; private String location; private String anonymousType; private String type; private String confirmTime; private String getPostSupport; private String responseSpeed; }
2.Vote.java
package com.hust.grid.leesf.entrance; import java.util.Timer; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import com.hust.grid.leesf.bean.IpInfo; import com.hust.grid.leesf.thread.IPCollectTask; import com.hust.grid.leesf.thread.VoteThread; public class Vote { private BlockingQueue<IpInfo> ipInfoQueue; private IPCollectTask ipCollectTask; private VoteThread voteThread; public Vote() { ipInfoQueue = new LinkedBlockingQueue<IpInfo>(); ipCollectTask = new IPCollectTask(ipInfoQueue); voteThread = new VoteThread(ipInfoQueue); } public void vote() { Timer timer = new Timer(); long delay = 0; long period = 1000 * 60 * 60; // 每個小時採集一次ip timer.scheduleAtFixedRate(ipCollectTask, delay, period); // 開啓投票任務 voteThread.start(); } public static void main(String[] args) { Vote vote = new Vote(); vote.vote(); } }
3.IPCollectTask.java
package com.hust.grid.leesf.thread; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.TimerTask; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import com.hust.grid.leesf.bean.IpInfo; public class IPCollectTask extends TimerTask { private BlockingQueue<IpInfo> ipInfoQueue; // 鏈接生產者與消費者的阻塞隊列 private List<IpInfo> historyIpLists; // 記錄已經獲取的ip信息 public IPCollectTask(BlockingQueue<IpInfo> ipInfoQueue) { this.ipInfoQueue = ipInfoQueue; this.historyIpLists = new ArrayList<IpInfo>(); } /** * 獲取www.xicidaili.com的ip地址信息 */ public void getXiCiDaiLiIpLists() { String url = "http://www.xicidaili.com/"; String host = "www.xicidaili.com"; Document doc = getDocumentByUrl(url, host); // 解析頁面的ip信息 parseXiCiDaiLiIpLists(doc); } /** * 解析頁面的ip信息 * * @param doc */ public void parseXiCiDaiLiIpLists(Document doc) { Elements eleLists = doc.getElementsByTag("tbody"); Element tbody = eleLists.get(0); // 獲取tbody Elements trLists = tbody.children(); Element ele = null; for (int i = 0; i < trLists.size(); i++) { if ((i % 22 == 0) || (i % 22 == 1)) { // 去掉不符合條件的項 continue; } ele = trLists.get(i); Elements childrenList = ele.children(); String ipAddress = childrenList.get(1).text(); int port = Integer.parseInt(childrenList.get(2).text()); String location = childrenList.get(3).text(); String anonymousType = childrenList.get(4).text(); String type = childrenList.get(5).text(); String confirmTime = childrenList.get(6).text(); IpInfo ipInfo = new IpInfo(ipAddress, port, location, anonymousType, type, confirmTime); putIpInfo(ipInfo); } } /** * 將ip信息放入隊列和歷史記錄中 * * @param ipInfo */ private void putIpInfo(IpInfo ipInfo) { if (!historyIpLists.contains(ipInfo)) { // 若歷史記錄中不包含ip信息,則加入隊列中 // 加入到阻塞隊列中,用做生產者 try { ipInfoQueue.put(ipInfo); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } // 加入歷史記錄中 historyIpLists.add(ipInfo); } } /** * 根據網頁Document解析出ip地址信息 * * @param doc */ private void parseKuaiDaiLiIpLists(Document doc) { Elements eleLists = doc.getElementsByTag("tbody"); Element tbody = eleLists.get(0); // 獲取tbody Elements trLists = tbody.children(); // 獲取十條ip記錄 for (Element tr : trLists) { // 遍歷tr Elements tdElements = tr.children(); // tr中的td包含了具體的信息 String ipAddress = tdElements.get(0).text(); int port = Integer.parseInt(tdElements.get(1).text()); String anonymousType = tdElements.get(2).text(); String type = tdElements.get(3).text(); String getPostSupport = tdElements.get(4).text(); String location = tdElements.get(5).text(); String responseSpeed = tdElements.get(6).text(); String confirmTime = tdElements.get(7).text(); IpInfo ipInfo = new IpInfo(ipAddress, port, location, anonymousType, type, confirmTime, getPostSupport, responseSpeed); putIpInfo(ipInfo); } } /** * 根據提供的url和host來獲取頁面信息 * * @param url * @param host * @return */ private Document getDocumentByUrl(String url, String host) { Document doc = null; try { doc = Jsoup .connect(url) .header("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0") .header("Host", host).timeout(5000).get(); } catch (IOException e) { e.printStackTrace(); } return doc; } /** * 獲取http://www.kuaidaili.com/free/的ip */ private void getKuaiDaiLiFreeIpLists() { // 第一次訪問,需解析總共多少頁 String baseUrl = "http://www.kuaidaili.com/free/inha/"; String host = "www.kuaidaili.com"; Document doc = getDocumentByUrl(baseUrl, host); // 解析ip信息 parseKuaiDaiLiIpLists(doc); Element listNav = doc.getElementById("listnav"); // 獲取listnav下的li列表 Elements liLists = listNav.children().get(0).children(); // 獲取含有多少頁的子元素 Element pageNumberEle = liLists.get(liLists.size() - 2); // 解析有多少頁 int pageNumber = Integer.parseInt(pageNumberEle.text()); // 拼接成其餘頁的訪問地址 for (int index = 1; index <= pageNumber; index++) { baseUrl = baseUrl + index; doc = getDocumentByUrl(baseUrl, host); parseKuaiDaiLiIpLists(doc); // 休眠一秒 fallSleep(1); } } /** * 獲取www.kuaidaili.com/proxylist/的ip */ private void getKuaiDaiLiIpLists() { int start = 1; String baseUrl = "http://www.kuaidaili.com/proxylist/"; String host = "www.kuaidaili.com"; while (start <= 10) { // 爬取10頁 String url = baseUrl + start + "/"; Document doc = getDocumentByUrl(url, host); // 解析ip信息 parseKuaiDaiLiIpLists(doc); start++; // 休眠一秒 fallSleep(1); } } /** * 進行休眠 */ private void fallSleep(long seconds) { try { Thread.sleep(seconds * 1000); } catch (InterruptedException e) { e.printStackTrace(); } } @Override public void run() { // getKuaiDaiLiFreeIpLists(); System.out.println("IPCollect task is running"); getKuaiDaiLiIpLists(); getXiCiDaiLiIpLists(); } public BlockingQueue<IpInfo> getIpInfoQueue() { return ipInfoQueue; } public static void main(String[] args) { BlockingQueue<IpInfo> queue = new LinkedBlockingQueue<IpInfo>(); IPCollectTask task = new IPCollectTask(queue); Thread thread = new Thread(task); thread.start(); try { Thread.sleep(30 * 1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("queue size is " + queue.size()); try { while (!queue.isEmpty()) { System.out.println(queue.take()); } } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("historyList size is " + task.historyIpLists.size()); } }
4.VoteThread.java
package com.hust.grid.leesf.thread; import java.io.IOException; import java.util.concurrent.BlockingQueue; import org.apache.http.HttpEntity; import org.apache.http.HttpHost; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.conn.params.ConnRoutePNames; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpParams; import org.apache.http.util.EntityUtils; import com.hust.grid.leesf.bean.IpInfo; public class VoteThread extends Thread { private BlockingQueue<IpInfo> ipInfoQueue; public VoteThread(BlockingQueue<IpInfo> ipInfoQueue) { this.ipInfoQueue = ipInfoQueue; } @Override public void run() { HttpClient client = new DefaultHttpClient(); HttpParams params = client.getParams(); HttpConnectionParams.setConnectionTimeout(params, 10000); HttpConnectionParams.setSoTimeout(params, 15000); HttpResponse response = null; HttpGet get = null; HttpEntity entity = null; HttpHost proxy = null; while (true) { IpInfo ipInfo = null; try { ipInfo = ipInfoQueue.take(); } catch (InterruptedException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } proxy = new HttpHost(ipInfo.getIpAddress(), ipInfo.getPort()); client.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy); get = new HttpGet( "http://www.hnxdf.com/vote/iRadio_vote.asp?VoTeid=215"); get.addHeader("Host", "www.hnxdf.com"); get.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0"); try { response = client.execute(get); entity = response.getEntity(); byte[] bytes = EntityUtils.toByteArray(entity); // 對響應內容編碼格式進行轉化,統一成utf-8格式 String temp = new String(bytes, "gbk"); byte[] contentData = temp.getBytes("utf-8"); System.out.println(new String(contentData)); System.out.println("-----------------------------------"); } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } }
7、系統總結
此係統很簡單,想清楚思路以後很快就可以寫出代碼,系統運行時,因爲代理IP站點提供的免費IP質量不是過高,有效的IP地址仍是不多,全部效果不是特別理想,此係統功能也很簡單,可是各位園友能夠在此基礎上去發揮本身的想象力,定製屬於本身的投票系統。
8、總結
至此,整個系統分析就已經完成了,其中,圖也畫得不是太規範,還請各位園友海涵。也謝謝各位園友觀看。
ps:整個工程(包含必要的jar文件)已經上傳到GitHub上,歡迎各位園友訪問:https://github.com/leesf/TicketBrushSystem
https://www.cnblogs.com/leesf456/p/5170212.html