接着上一篇的《博客備份小工具3》我有提到“其實想了想,轉發博客干嘛非要在本地客戶端轉發,直接在博客園的頁面用js不就可以達到目的么。想是這么想,還沒嘗試。等我寫完了這個博客就去試試。。”。想法很天真,現實很殘忍。本以為,直接ajax異步post請求就可以把當前頁面的內容發布。可是,問題來了。我們瀏覽的頁面域名是cnblogs.com,而我們后台發布的域名是i.cnblogs.com。跨域了,親。問題既然來了,總不能半途而廢吧。程序的世界沒有辦不到,只有想不到。jsonp專門來干這事的。(jsonp資料傳送門)。 為什么不用《博客備份小工具3》,因為它是CS的。要是可以直接在瀏覽頁面有個按鈕一鍵轉發豈不是爽歪歪。貌似Chrome插件可以專門來干這等壞事。(chrome插件介紹傳送門)。好了就這兩個重要的點了。
下面來說說主要的實現思路,首先通過插件在瀏覽頁面給自己找塊地盤(添加一個div)。然后div中可以輸入用戶名、密碼登錄,取得文章類型。接着就一鍵發布,把當前頁面的內容通過jsonp跨域傳到自己開發的后台發布~是不是很簡單呢?哈哈,其實我覺得挺難的。中間遇到了很多問題。就現在,估計還有很多的bug。
好了,先看看效果圖。感覺爽嗎?要是當心安全問題,下面我會把所有源碼開放。大伙可以改進。^_^
一、開辟一片空間
插件content_script中配置的content_script.js,在content_script.js中可以直接操作當前瀏覽頁。哈哈,這還了得,這豈不是到哪里都隨心所欲了。好吧,那么我們給自己開辟一片空間來做想要的操作。
var mydata = ""; mydata += "&url=" + document.location.href; mydata += "&type=mytype"; mydata += "&tag=mytag"; var html = " <div id='chrome_test_div' style='display:none;background-color:#0094ff; position: fixed; top: 0px; left: 0px; width: 100%;z-index:11'>\ <table style='width:100%'>\ <tr>\ <td>用戶名:</td>\ <td><input id='chrome_test_user' type='text' value='' /></td>\ <td>密碼:</td>\ <td><input id='chrome_test_pass' type='password' value='' /></td>\ <td>\ <a href='javascript:void(0);' id='chrome_test_a' >\ 登錄\ </a>\ </td>\ <td>\ 文章:\ </td>\ <td>\ <span id='chrome_content_title'></span>\ </td>\ \ <td>個人分類:</td>\ <td>\ <select id='pop_sel_type_text'></select>\ </td>\ \ <td>\ Tag標簽:\ </td>\ <td>\ <input type='text' value='' list='pop_sel_tag_text' id='id_pop_sel_tag_text'>\ <input type='hidden' id='myhidden' />\ <!--<datalist id='pop_sel_tag_text'></datalist>-->\ </td>\ <td colspan='2'><input type='button' id='chrome_test_button' value='一鍵轉發' /></td>\ <td id='chrome_meg_td'></td>\ </tr>\ </table>\ <script src='https://git.oschina.net/zhaopeiym/Demo/raw/master/resource/cnblogs/cnblog.Chrome.js?v=123'></script>\ </div>"; $("body").prepend(html).css("margin-top", "70px"); $("#chrome_content_title").text($("#cb_post_title_url").text()); document.body.scrollTop = 30; window.onscroll = function () { if (true) { var top = document.body.scrollTop; if (top <= 0) { $("#chrome_test_div").slideDown(200); } else if (top >= 30) { $("#chrome_test_div").slideUp(400); } } }
直接添加一個div,然后在div中添加一個table。畫上登錄要的用戶名、密碼、文章標題、后台發布的文章類型、tag標簽、、、等。
二、登錄 獲取 你所有的文章分類。
1、用jsonp發送請求
不知道同學們有沒有注意到上面的代碼中有一段
<script src='https://git.oschina.net/zhaopeiym/Demo/raw/master/resource/cnblogs/cnblog.Chrome.js?v=123'></script>
是的,我所以當前操作頁的js都在這個路徑下。
function chrome_test_login() { var username = $("#chrome_test_user").val(); var password = $("#chrome_test_pass").val(); var Section_url = "&username=" + username + "&password=" + password; $.getJSON(getjsonUrl + '/BolghelpWeb/Handler1.ashx?OperationCMD=login' + Section_url + '&callback=?', function (data) { test(data); }); }
登錄的js。ajax的jsonp使用起來還是蠻方便的。
2、后台代碼的登錄和取文章分類
登錄:
/// <summary> /// 登錄 /// </summary> /// <param name="context"></param> public void PostLogin(HttpContext context, string username, string password) { username = context.Request.QueryString["username"]; password = context.Request.QueryString["password"]; string loginurl = "http://passport.cnblogs.com/login.aspx?ReturnUrl=http://www.cnblogs.com/";// string result = htmlWeb.Load(loginurl).DocumentNode.InnerHtml; String __EVENTVALIDATION = new Regex("id=\"__EVENTVALIDATION\" value=\"(.*?)\"").Match(result).Groups[1].Value; String __VIEWSTATE = new Regex("id=\"__VIEWSTATE\" value=\"(.*?)\"").Match(result).Groups[1].Value; String LBD_VCID_c_login_logincaptcha = new Regex("id=\"LBD_VCID_c_login_logincaptcha\" value=\"(.*?)\"").Match(result).Groups[1].Value; StringBuilder str_content = new StringBuilder(); str_content.Append(@"__EVENTTARGET="); str_content.Append(@"&__EVENTARGUMENT="); str_content.Append(@"&__VIEWSTATE=" + System.Web.HttpUtility.UrlEncode(__VIEWSTATE, Encoding.UTF8)); str_content.Append(@"&__VIEWSTATEGENERATOR=C2EE9ABB"); str_content.Append(@"&__EVENTVALIDATION=" + System.Web.HttpUtility.UrlEncode(__EVENTVALIDATION, Encoding.UTF8)); str_content.Append(@"&tbUserName=" + System.Web.HttpUtility.UrlEncode(username, Encoding.UTF8)); str_content.Append(@"&tbPassword=" + password); str_content.Append(@"&LBD_VCID_c_login_logincaptcha=" + LBD_VCID_c_login_logincaptcha); str_content.Append(@"&LBD_BackWorkaround_c_login_logincaptcha="); str_content.Append(@"&btnLogin=登 錄"); str_content.Append(@"&txtReturnUrl=http://www.cnblogs.com/"); httphelp.PostHtml(loginurl, null, str_content.ToString(), Encoding.UTF8, true); }
取文章分類:
/// <summary> /// 取文章類型 /// </summary> /// <param name="context"></param> public void PostGetType(HttpContext context) { PostLogin(context, "", ""); string TypeUrl = "http://i.cnblogs.com/EditArticles.aspx?opt=1";//地址 var typeHtml = httphelp.PostHtml(TypeUrl, null, "", Encoding.UTF8, true); HtmlAgilityPack.HtmlDocument response = new HtmlDocument(); response.LoadHtml(typeHtml); var html_trS = response.DocumentNode.SelectNodes("//*[@id='Editor_Edit_APOptions_Advancedpanel1_cklCategories']/tr"); List<object> objs = new List<object>(); foreach (var item in html_trS) { var html_tdS = item.SelectNodes(item.XPath + "/td"); foreach (var item_td in html_tdS) { if (item_td.SelectSingleNode(item_td.XPath + "/input") != null) { var value = item_td.SelectSingleNode(item_td.XPath + "/input").Attributes["value"].Value; var name = item_td.SelectSingleNode(item_td.XPath + "/input").Attributes["name"].Value; var text = item_td.SelectSingleNode(item_td.XPath + "/label").InnerText; objs.Add(new { value = value, text = text, name = name }); } } } context.Response.ContentType = "application/json"; string callback = context.Request.QueryString["callback"]; context.Response.Write(callback + "(" + objs.ToJson() + ")"); }
ok,在此就登錄,並取到了所有的文章類型。
三、一鍵發布
其實在發布之前又登錄的一次。為什么呢?因為發布需要登錄,之前登錄的是上一次請求。而上一次請求的session,在這一個是讀不到的。可能是因為跨域請求的原因。那沒辦法的,那就再登錄一次吧。反正登錄的反法已經獨立出來了。只是電腦多干事了。
1、首頁在前台頁面取得要轉發的正文內容
//一鍵轉發 $("#chrome_test_button").click(function () { $("#chrome_meg_td").html(""); var type = $("#pop_sel_type_text").val().split('%')[0]; var name = $("#pop_sel_type_text").val().split('%')[1]; var username = $("#chrome_test_user").val(); var password = $("#chrome_test_pass").val(); var tag = $("#id_pop_sel_tag_text").val(); var Section_url = "&type=" + type + "&tag=" + tag + "&name=" + name + "&password=" + password + "&username=" + username; $.getJSON(getjsonUrl + '/BolghelpWeb/Handler1.ashx?OperationCMD=Publishing&callback=?' + Section_url + '&url=' + document.location.href, function (data) { $("#chrome_meg_td").html("發布成功~<a href='http://i.cnblogs.com/EditArticles.aspx' target='_blank'>后台查看~</a>"); $("#chrome_test_div a").css("color", "#fff"); }); });
2、然后是后台發布
/// <summary> /// 發布 /// </summary> /// <param name="context"></param> public void PostPublishing(HttpContext context) { string url = "http://i.cnblogs.com/EditArticles.aspx?opt=1";//地址 string callback = context.Request.QueryString["callback"]; string mydataurl = context.Request.QueryString["url"]; string mydatatype = context.Request.QueryString["type"]; string mydatatag = context.Request.QueryString["tag"]; string mydataname = context.Request.QueryString["name"]; PostLogin(context, "", ""); var html = httphelp.PostHtml(url, null, "", Encoding.UTF8, true); String __VIEWSTATE = new Regex("id=\"__VIEWSTATE\" value=\"(.*?)\"").Match(html).Groups[1].Value; string title = "test", body = "test"; GetRequest(mydataurl, ref body, ref title); body += "</br>==================================<a href='" + mydataurl + "' target='_blank'>原文鏈接</a>===此文章由<a href='http://www.cnblogs.com/zhaopei/' target='_blank'>博客轉發插件</a>轉發=================================="; StringBuilder str_content = new StringBuilder(); str_content.Append(@"__VIEWSTATE=" + System.Web.HttpUtility.UrlEncode(__VIEWSTATE, Encoding.UTF8));//隨便分類信息和__VIEWSTATE有關 所以 分類 不好弄 str_content.Append(@"&__VIEWSTATEGENERATOR=FE27D343");//FE27D343 0512620B str_content.Append(@"&Editor$Edit$txbTitle=" + System.Web.HttpUtility.UrlEncode("【轉】" + title, Encoding.UTF8)); str_content.Append(@"&Editor$Edit$EditorBody=" + System.Web.HttpUtility.UrlEncode(body, Encoding.UTF8)); str_content.Append(@"&" + mydataname + "=" + mydatatype); str_content.Append(@"&Editor$Edit$Advanced$ckbPublished=on");//發布 str_content.Append(@"&Editor$Edit$Advanced$chkDisplayHomePage=on");//博客首頁顯示 str_content.Append(@"&Editor$Edit$Advanced$chkComments=on");//允許評論 str_content.Append(@"&Editor$Edit$Advanced$chkMainSyndication=on");//顯示在RSS中 str_content.Append(@"&Editor$Edit$Advanced$txbEntryName=");//友好地址名,只能使用字母、數字、-連字符、_下划線,不超過150個字符 str_content.Append(@"&Editor$Edit$Advanced$txbExcerpt=");//插入摘要右側圖片 str_content.Append(@"&Editor$Edit$Advanced$txbTag=" + mydatatag);// Tag標簽 str_content.Append(@"&Editor$Edit$Advanced$tbEnryPassword=");//密碼保護 str_content.Append(@"&Editor$Edit$lkbPost=發布"); var srcString = httphelp.PostHtml(url, null, str_content.ToString(), Encoding.UTF8, true);//發布 context.Response.ContentType = "application/json"; //輸出:回調函數名(json數據) if (srcString.Contains("發布成功")) context.Response.Write(callback + "('ok')"); else context.Response.Write(callback + "('no')"); }
基本上就此完工了。哈哈~
四、怎么使用
有人可能還不知道怎么安裝插件。360瀏覽器你只有把插件直接拖到瀏覽器里面就可以了。如果是谷歌原版瀏覽器那么就拖到chrome://extensions/這個頁面。還有問題就百度怎么安裝插件吧。
不想看源碼的 可以直接下載插件使用,安裝后打開任何一個博客園文章頁面,然后把滾動條滾到最上就可以看到效果了(效果比較隱藏,為了不影響大家正常瀏覽頁面內容)。 【下載地址】
五、源碼下載
全部源碼下載(包括插件源碼、后台源碼和引用的外部js)。親,老規矩。如果覺得對您有用,而您又下載了。請您輕輕的點個贊唄~~
PS:這篇文章本來是寫於2015-04-02 20:25,准備第二天發布。然,第二天發現登錄不了了。原來正好遇上的博客園修改登錄方式。整了老半天也沒有整出怎么登錄,無意看到了一篇文章,借鑒了下思路。搞定!!這里主要也是弄着玩玩,還有很多功能后續再繼續完善。如:記住密碼、自動登錄取分類數據、驗證碼問題(一般只有晚上才需要)、當然肯定還有很多bug,先這樣吧,之后再慢慢修改。