這裡我就在想一個請求嘛,我驗證請求一次,瀏覽量增加1。於是我就按F5重新整理,但是實際上並不是每次都增加,繼續驗證發現多過會再按F5就增加1了。到這裡基本特徵分析完畢,親,你有思路了嗎?我這裡想到以前的爬蟲,不就是請求頁面,得到返回的html再解析字串嘛。所以我也借鑒這個思想,使用服務端請求連結,然後剩下的就是這個等待時間,如果不管一直刷,可能會有惡意請求的嫌疑,這是要被封號的。那麼這個情境適合什麼技術了,大家think到沒?沒錯,可以用線程,設定每次請求後的sleep時間。
那麼大致思路就明確了:httpClient發請求,線程式控制制停頓時間。廢話不說了,我就上代碼了:
上面這個main大家應該熟的很,我這裡的想法就是線程類裡有三個變數,我使用前,new出來後先設定好變數,便於後期線程run方法裡使用。這裡跟大家補充下多線程實現的4中方式,這個之前好像也寫了博文提到過。
多線程的實現有4種方式,很多都至說前面兩種,不帶傳回值的。
1、繼承Thread類建立線程
Thread類本質上是實現了Runnable介面的一個執行個體,代表一個線程的執行個體。啟動線程的唯一方法就是通過Thread類的start()執行個體方法。start()方法是一個native方法,它將啟動一個新線程,並執行run()方法。這種方式實現多線程很簡單,通過自己的類直接extend Thread,並複寫run()方法,就可以啟動新線程並執行自己定義的run()方法。例如:
public class MyThread extends Thread { public void run() { System.out.println("MyThread.run()"); } } MyThread myThread1 = new MyThread(); MyThread myThread2 = new MyThread(); myThread1.start(); myThread2.start();
2、實現Runnable介面建立線程
如果自己的類已經extends另一個類,就無法直接extends Thread,此時,可以實現一個Runnable介面,如下:
public class MyThread extends OtherClass implements Runnable { public void run() { System.out.println("MyThread.run()"); } }
為了啟動MyThread,需要首先執行個體化一個Thread,並傳入自己的MyThread執行個體:
MyThread myThread = new MyThread(); Thread thread = new Thread(myThread); thread.start();
事實上,當傳入一個Runnable target參數給Thread後,Thread的run()方法就會調用target.run(),參考JDK原始碼:
public void run() { if (target != null) { target.run(); } }
3、實現Callable介面通過FutureTask封裝器來建立Thread線程
Callable介面(也只有一個方法)定義如下:
public interface Callable<V> { V call() throws Exception; }
public class SomeCallable<V> extends OtherClass implements Callable<V> { @Override public V call() throws Exception { // TODO Auto-generated method stub return null; }}
Callable<V> oneCallable = new SomeCallable<V>(); //由Callable<Integer>建立一個FutureTask<Integer>對象: FutureTask<V> oneTask = new FutureTask<V>(oneCallable); //注釋:FutureTask<Integer>是一個封裝器,它通過接受Callable<Integer>來建立,它同時實現了Future和Runnable介面。 //由FutureTask<Integer>建立一個Thread對象: Thread oneThread = new Thread(oneTask); oneThread.start(); //至此,一個線程就建立完成了。
4、使用ExecutorService、Callable、Future實現有返回結果的線程
ExecutorService、Callable、Future三個介面實際上都是屬於Executor架構。返回結果的線程是在JDK1.5中引入的新特徵,有了這種特徵就不需要再為了得到傳回值而大費周折了。而且自己實現了也可能漏洞百出。
可傳回值的任務必須實現Callable介面。類似的,無傳回值的任務必須實現Runnable介面。
執行Callable任務後,可以擷取一個Future的對象,在該對象上調用get就可以擷取到Callable任務返回的Object了。
注意:get方法是阻塞的,即:線程無返回結果,get方法會一直等待。
再結合線程池介面ExecutorService就可以實現傳說中有返回結果的多線程了。
言歸正傳,我這裡使用的是第一種,因為我不需要傳回值。
這裡面加入的是可以多個地址刷的思路,以及奇偶分請求方式,避免每次都是同一種請求方式,規避被系統列為惡意請求的風險。以及休眠時間可以在main設定。下面就來看看刷之前的閱讀量:
昨天晚上是寫完這個我就去睡了,電腦都沒有關,看看這一晚上請求到多少次了:
然後,我現在重新整理下列表頁,重新看看閱讀量:
看到沒,閱讀量現在已經是600多了,原先才300多。
這裡因為ip一直都是這個,所以中間的sleep時間有點長,如果能有ip供切換,加入切換邏輯,效果會更好。
理論上來說所有的閱讀量都是可以用這個刷的,當然要用戶端沒有做比較嚴格的同ip請求多次至算閱讀1次等策略。百度文庫的那些文章我不找到怎麼評為優秀文檔的,但是我想跟請求量肯定有一定關係,大家有機會可以按照這個思路試試。可以改造下搞兩個線程,交替進行,一個線程刷一個網站,哈哈。
不過如果封號了不要怪我,呵呵。