不知道多久以前就有過寫個自動回帖的小軟件一直沒有實現(xiàn),最近閑下來了遂研究了下,本人小菜對于HTTP協(xié)議一知半解只能在請教google大神了,把我的想法跟google大神說了之后,google大神說這小子不錯,這是為防火事業(yè)做貢獻啊!特賜予小弟以下神器:
1、 HttpClient 4.3.1 (GA)
以下列出的是 HttpClient 提供的主要的功能,要知道更多詳細的功能可以參見 HttpClient 的主頁。
- 實現(xiàn)了所有 HTTP 的方法(GET,POST,PUT,HEAD 等)
- 支持自動轉(zhuǎn)向
- 支持 HTTPS 協(xié)議
- 支持代理服務(wù)器等
2、Jsoup
jsoup 的主要功能如下
- 從一個 URL,文件或字符串中解析 HTML
- 使用 DOM 或 CSS 選擇器來查找、取出數(shù)據(jù)
- 可操作 HTML 元素、屬性、文本
- 使用與jquery幾乎一樣的語法
廢話不多說直接進入正題,在HTTPClient源碼包內(nèi)包含example文件夾此文件夾內(nèi)包含一些基本用法這些例子入門足夠了找到ClientFormLogin.java具體解釋注釋已經(jīng)很清楚了大致意思就是模擬HTTP請求存儲cookies。
測試網(wǎng)站: http://bbs.dakele.com/
因為此網(wǎng)站對登錄做了特殊處理所以與標(biāo)準(zhǔn)的DZ論壇可能會有些出入請自行修改
對網(wǎng)站的分析使用的chrome自帶的審查元素,這個折騰了不少時間
登錄地址: http://passport.dakele.com/login.do?product=bbs
輸入錯誤的用戶名和密碼會發(fā)現(xiàn)實際登錄地址為 http://passport.dakele.com/logon.do 注意【i/n的區(qū)別剛開始沒注意以為見鬼了】
返回錯誤信息
{"err_msg":"帳號或密碼錯誤"}
輸入正確信息返回
{"result":true,"redirect": http://bbs.dakele.com/member.php?mod=logging &action =login &loginsubmit =yes &infloat =yes &lssubmit =yes &inajax =0 &fastloginfield =username &quickforward =yes &handlekey =ls &cookietime =2592000 &remember =0 &username =youname &AccessKey = []}
直接輸入rediret連接和正常登錄
獲取跳轉(zhuǎn)鏈接:
private LoginResult getRedirectUrl(){ LoginResult loginResult = null ; CloseableHttpClient httpClient = HttpClients.createDefault(); HttpPost httpost = new HttpPost(LOGINURL); httpost.setHeader( "Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8" ); httpost.setHeader( "Accept-Language", "zh-CN,zh;q=0.8" ); httpost.setHeader( "Cache-Control", "max-age=0" ); httpost.setHeader( "Connection", "keep-alive" ); httpost.setHeader( "Host", "passport.dakele.com" ); httpost.setHeader( "User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36" ); List <NameValuePair> nvps = new ArrayList <NameValuePair> (); nvps.add( new BasicNameValuePair("product", "bbs" )); nvps.add( new BasicNameValuePair("surl", "http://bbs.dakele.com/" )); nvps.add( new BasicNameValuePair("username", "yourname")); // 用戶名 nvps.add( new BasicNameValuePair("password", "yourpass")); // 密碼 nvps.add( new BasicNameValuePair("remember", "0" )); httpost.setEntity( new UrlEncodedFormEntity(nvps, Consts.UTF_8)); CloseableHttpResponse response2 = null ; try { response2 = httpClient.execute(httpost); if (response2.getStatusLine().getStatusCode()==200 ){ HttpEntity entity = response2.getEntity(); String entityString = EntityUtils.toString(entity); JSONArray jsonArray = JSONArray.fromObject("["+entityString+"]" ); JsonConfig jsonConfig = new JsonConfig(); jsonConfig.setArrayMode(JsonConfig.MODE_OBJECT_ARRAY); jsonConfig.setRootClass(LoginResult. class ); LoginResult[] results = (LoginResult[]) JSONSerializer.toJava( jsonArray, jsonConfig ); if (results.length==1 ){ loginResult = results[0 ]; } } } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { response2.close(); httpClient.close(); } catch (IOException e) { e.printStackTrace(); } } return loginResult; }
登錄代碼:
public boolean login(){ boolean flag = false ; LoginResult loginResult = getRedirectUrl(); if (loginResult.getResult().equals("true" )){ cookieStore = new BasicCookieStore(); globalClient = HttpClients.custom().setDefaultCookieStore(cookieStore).build(); HttpGet httpGet = new HttpGet(loginResult.getRedirect()); httpGet.setHeader( "Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8" ); httpGet.setHeader( "Accept-Language", "zh-CN,zh;q=0.8" ); httpGet.setHeader( "Connection", "keep-alive" ); httpGet.setHeader( "Host" , HOST); httpGet.setHeader( "User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36" ); try { globalClient.execute(httpGet); } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } List <Cookie> cookies2 = cookieStore.getCookies(); if (cookies2.isEmpty()) { log.error( "cookie is empty" ); } else { for ( int i = 0; i < cookies2.size(); i++ ) { } } } return flag; }
到此已經(jīng)登錄成功可以進行只有登錄號才能做的事了,什么?你不知道當(dāng)然是滅火了
首先取得需要回復(fù)的帖子地址,列表頁比較有規(guī)律所有沒有寫自動發(fā)現(xiàn)的所以寫了個循環(huán)@1
for ( int i=1;i<200;i++ ){ String basurl ="http://bbs.dakele.com/forum-43-"+i+".html" ; log.info(basurl); List <String> urls = dakele.getThreadURLs(basurl); for (String url:urls){ // log.info(url); ReplayContent content = dakele.preReplay(url); if (content!= null ){ log.info(content.getUrl()); log.info(content.getMessage()); // dakele.replay( content); // Thread.sleep(15300); } } }
在列表頁內(nèi)獲取帖子地址:
String html = EntityUtils.toString(entity); Document document = Jsoup.parse(html,HOST); Elements elements =document.select("tbody[id^=normalthread_] > tr > td.new > a.xst" ); for ( int i=0;i<elements.size();i++ ){ Element e = elements.get(i); urList.add(e.attr( "abs:href" )); }
在需要回復(fù)的帖子內(nèi)獲得需要提交的form表單地址以及構(gòu)造回復(fù)內(nèi)容
public ReplayContent preReplay(String url){ ReplayContent content = null ; HttpGet get = new HttpGet(url); get.setHeader( "Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8" ); get.setHeader( "Accept-Language", "zh-CN,zh;q=0.8" ); get.setHeader( "Connection", "keep-alive" ); get.setHeader( "Host" , HOST); get.setHeader( "User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36" ); try { CloseableHttpResponse response = globalClient.execute(get); HttpEntity entity = response.getEntity(); String html = EntityUtils.toString(entity); Document document = Jsoup.parse(html, HOST); Element postForm = document.getElementById("fastpostform" ); if (!postForm.toString().contains("您現(xiàn)在無權(quán)發(fā)帖" )){ content = new ReplayContent(); content.setUrl(url); log.debug(postForm.attr( "abs:action" )); content.setAction(postForm.attr( "abs:action" )); //////// Elements teElements = document.select("td[id^=postmessage_]" ); String message = "" ; for ( int i=0;i<teElements.size();i++ ){ String temp = teElements.get(i).html().replaceAll( "(?is)<.*?>", "" ); if (temp.contains("發(fā)表于" )){ String[] me = temp.split("\\s+" ); temp = me[me.length-1 ]; } message +=temp.replaceAll("\\s+", "" ); } log.debug(message.replaceAll( "\\s+", "" )); ////////////// / /* 取最后一條評論 Element messageElement= document.select("td[id^=postmessage_]").last(); // String message = messageElement.html().replaceAll("\\&[a-zA-Z]{1,10};", "").replaceAll("<[^>]*>", "").replaceAll("[(/>)<]", ""); String message = messageElement.html().replaceAll( "(?is)<.*?>", ""); */ if (message.contains("發(fā)表于" )){ String[] me = message.split("\\s+" ); message = me[me.length-1 ]; } content.setMessage(message.replaceAll( " ", "").replaceAll("上傳", "").replaceAll("附件", "").replaceAll("下載", "" )); Elements inputs = postForm.getElementsByTag("input" ); for (Element input:inputs){ log.debug(input.attr( "name")+":"+input.attr("value" )); if (input.attr("name").equals("posttime" )){ content.setPosttime(input.attr( "value" )); } else if (input.attr("name").equals("formhash" )){ content.setFormhash(input.attr( "value" )); } else if (input.attr("name").equals("usesig" )){ content.setUsesig(input.attr( "value" )); } else if (input.attr("name").equals("subject" )){ content.setSubject(input.attr( "value" )); } } } else { log.warn( "您現(xiàn)在無權(quán)發(fā)帖:"+ url); } } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return content; }
地址有了,內(nèi)容有了接下來開始放水了
public void replay(ReplayContent content){ HttpPost httpost = new HttpPost(content.getAction()); httpost.setHeader( "Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8" ); httpost.setHeader( "Accept-Language", "zh-CN,zh;q=0.8" ); httpost.setHeader( "Cache-Control", "max-age=0" ); httpost.setHeader( "Connection", "keep-alive" ); httpost.setHeader( "Host" , HOST); httpost.setHeader( "User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36" ); List <NameValuePair> nvps = new ArrayList <NameValuePair> (); nvps.add( new BasicNameValuePair("posttime" , content.getPosttime())); nvps.add( new BasicNameValuePair("formhash" , content.getFormhash())); nvps.add( new BasicNameValuePair("usesig" , content.getUsesig())); nvps.add( new BasicNameValuePair("subject" , content.getSubject())); nvps.add( new BasicNameValuePair("message" , content.getMessage())); httpost.setEntity( new UrlEncodedFormEntity(nvps, Consts.UTF_8)); // HTTP 三次握手 必須處理響應(yīng)剛開始沒注意卡在這了 CloseableHttpResponse response2 = null ; try { response2 = globalClient.execute(httpost); // log.info(content.getAction()); // log.info(content.getMessage()); HttpEntity entity = response2.getEntity(); EntityUtils.consume(entity); // BufferedWriter bw= new BufferedWriter(new FileWriter("d:/tt1.html")); // bw.write(EntityUtils.toString(response2.getEntity())); // bw.flush(); // bw.close(); // System.out.println(EntityUtils.toString(response2.getEntity())); } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
當(dāng)然這只適用于沒有驗證碼的論壇對于有驗證碼的只能繞道了,
對于回復(fù)內(nèi)容剛開始只取了當(dāng)前帖子內(nèi)最后一條評論然后進行回復(fù),被警告!然后使用IK分詞獲取關(guān)鍵字代碼是貼來的 請移步
參考連接:
缺點:沒有使用多線程、沒有進行充分測試
代碼整理中盡快提供
后期計劃:加入簽到、做任務(wù)功能、把@1循環(huán)改為自動發(fā)現(xiàn)
小弟第一次發(fā)帖其中有不足之處望批評指正
------------------------------------------
下載地址http://pan.baidu.com/s/1jGjwA5g
早上把代碼整理了下,現(xiàn)在分享給大家,直接對Myeclipse工程進行的打包解壓后可直接導(dǎo)入
修改IKFenci.java 內(nèi)用戶名和密碼可直接運行
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
