前言:
百度百科上偽原創的定義是“所謂偽原創就是把一篇文章進行再加工,使其讓搜索引擎認為是一篇原創文章,從而提高網站權重”。其實對於程序猿來說,偽原創就是“對文章進行大量的同義詞替換”。
做SEO的朋友——尤其是黑帽SEO的朋友——一定知道,偽原創對於搜索引擎優化至關重要。英文的偽原創稱為“Spin”,成熟的英文偽原創工具有TBS、Spinnerchief等等,TBS的售價還挺貴。而成熟、靠譜中文偽原創工具,卻一直罕有。在百度搜索“中文偽原創”,首頁的幾個工具我都試過了,效果差強人意。
於是我開發了伯樂偽原創,http://www.bolewei.com/ ,有興趣的朋友可以先體驗。(但必須說明的是,這只是測試版本,離正式版還很遙遠哦 O(∩_∩)O哈哈~)
中文偽原創工具需要考慮的問題
我開始思考,目前已有的中文偽原創工具,效果差在哪些地方呢?我想到以下幾個:
一、分詞問題。
中文和英文不同,無論是搜索引擎的蜘蛛,還是其他自然語言處理的語料分析,都是需要分詞的。如果不先進行分詞的預處理就開始“偽原創”,肯定是不靠譜。舉個例子:“天真”和“純潔”是近義詞。在不分詞的情況下,“我有一個天真的表妹”仍然可以偽原創為“我有個純潔的妹妹”,但“今天真熱”處理為“今純潔熱”就是嚴重不靠譜。
二、順序執行引發的單一化。
無論是網上流行的中文偽原創詞庫,還是現成的中文偽原創工具,我都試過了,他們的詞庫格式如下:
普通的算法是按照順序依次替換,那么,如圖所示,“凡間”的同義詞原本有“塵寰”“塵間”“塵世”三個,但它永遠不會被替換成后兩個詞。
最最理想的狀態是能夠根據語境,替換為合適的詞。例如“天真”的同義詞有“無邪 ”“純真 ”“純潔 ”“純朴”等等,並非每個詞在所有語境下都能夠完全替換。當然,結合語境是高級自然語言處理的范疇,簡單得偽原創能達到次理想狀態就算OK:遇到多個同義詞的情況,隨機替換其中的一個。
三、詞庫打架的問題
我下載了網上流傳的大部分詞庫,收費的、免費的,都嘗試了。發現沒有人去解決詞庫打架問題。
什么叫做“詞庫打架問題”?很簡單,看這兩組詞。
順序執行替換后,會發現文字兜了一個圈回到了原點……這顯然不是我們想要的,但,這個問題在現有的詞庫、偽原創工具中,非常非常普遍。
四、可讀性太差
為什么會可讀性太差?因為現有的中文偽原創工具,都是通篇全部替換。如果詞庫里有10萬組同義詞,程序會遍歷一次,把原文中所有能夠替換的字符串“榨干”。這樣一來雖然偽原創成功了,但可讀性無限趨近於零。讓我們看這樣一組例子:
偽原創后:
如果讀者直接閱讀偽原創后的文字,能夠理解嗎?
怎樣解決這個問題呢,我想,可以設置一個百分比,或叫做偽原創等級。例如“輕微 柔和 適中 猛烈 變態 面目全非 魂飛魄散”七個等級。用戶選擇“輕柔”時,只替換100個可替換同義詞中的隨機10個, 選擇“適中”中,替換100個可替換同義詞中的隨機50個,以此類推。這樣就可以讓用戶自己在“可讀性”“原創度”之前自由權衡。
我心中的完美中文偽原創工具
| 功能模塊 | 功能說明 | 技術實現 |
| 智能分詞 | 避免“今天真熱”變成“今純潔熱”的問題。 | 可以調用現有的中文分詞開源組件。 |
| 隨機性 | 既便是同一篇文章,每次進行偽原創的結果都不一樣。 | 引入隨機取詞條。 |
| 偽原創力度調節 | 定義偽原創的百分比,讓用戶在“可讀性”和“原創度”之間自由權衡。 | 引入等級設置、隨機取詞條。 |
| 詞庫不要打架 | 避免或降低“發誓”被替換為“立誓”后又被替換回“發誓”的情況發生。 | 放棄順序執行。 |
| 統計 | 統計偽原創后替換了多少詞 | 替換時插入標記 |
| 標記 | 標記被替換的詞,方便查看、校對 | 替換時插入標記 |
核心程序實現
考慮以上提到的很多方面的問題,程序還是比較長,接近一萬行。下面我只列幾段核心的代碼供大家參考、討論。
一、分詞。
分詞其實很容易,因為有很懂開源組件可以使用。我最喜歡的是SCWS。官網地址是http://www.ftphp.com/scws/
SCWS本來是PHP中文分詞解決方案,但它提供了API,我們C#程序猿也可以毫無壓力的調用。
View Code
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
try
{
string s = string.Empty;
System.Net.CookieContainer cookieContainer = new System.Net.CookieContainer();
// 將提交的字符串數據轉換成字節數組
byte[] postData = System.Text.Encoding.ASCII.GetBytes( " data= " + System.Web.HttpUtility.UrlEncode(str) + " &respond=json&charset=utf8&ignore=yes&duality=no&traditional=no&multi=0 ");
// 設置提交的相關參數
System.Net.HttpWebRequest request = System.Net.WebRequest.Create( " http://www.ftphp.com/scws/api.php ") as System.Net.HttpWebRequest;
request.Method = " POST ";
request.KeepAlive = false;
request.ContentType = " application/x-www-form-urlencoded ";
request.CookieContainer = cookieContainer;
request.ContentLength = postData.Length;
// 提交請求數據
System.IO.Stream outputStream = request.GetRequestStream();
outputStream.Write(postData, 0, postData.Length);
outputStream.Close();
// 接收返回的頁面
System.Net.HttpWebResponse response = request.GetResponse() as System.Net.HttpWebResponse;
System.IO.Stream responseStream = response.GetResponseStream();
System.IO.StreamReader reader = new System.IO.StreamReader(responseStream, System.Text.Encoding.GetEncoding( " utf-8 "));
string val = reader.ReadToEnd();
Newtonsoft.Json.Linq.JObject results = Newtonsoft.Json.Linq.JObject.Parse(val);
foreach ( var item in results[ " words "].Children())
{
Newtonsoft.Json.Linq.JObject word = Newtonsoft.Json.Linq.JObject.Parse(item.ToString());
sb.Append(word[ " word "].ToString() + " ");
}
}
catch
{
}
return sb.ToString();
}
二、解決詞庫打架問題。
這沒什么好說的。程序也只有一句話。
三、根據百分比,隨機取x條記錄。
取隨機記錄,最方便的是Mysql數據庫,內置的rand()函數可以在select中使用。如果使用SQL Server稍微麻煩些,效率也會低一些。
參考http://www.rndblog.com/how-to-select-random-rows-in-mysql/
四、替換同義詞主函數。
請看代碼里的注釋。
{
string newArticle = old ;
int wordsAmount = 180482; // 詞庫總量
int kwcount = Convert.ToInt32(strength * 1.0 / 100 * wordsAmount); // 根據傳入的百分比,計算需要取多少個詞
var dataset = SQLHelper.ExecuteDataset(SQLHelper.connectionString, System.Data.CommandType.Text, " select * from words order by rand() limit " + kwcount); // 隨機取kwcount組詞
foreach (DataRow r in dataset.Tables[ 0].Rows)
{
// 隨機。對於詞典中A->B的詞組。隨機決定本次替換是Replace(A,B)還是Replace(B,A)
int i = new Random().Next( 0, 1);
newArticle = newArticle.Replace(r[i].ToString()
, string.Format( " <b>{0}</b> ", r[ 1 - i].ToString()));
}
// 數被替換的詞。
replacedcount = newArticle.Split( new string[] { " </b> " }, StringSplitOptions.None).Length - 1;
if (!markRed)
{
// 如果用戶不要求標記,則去掉<b>標記。
newArticle = newArticle.Replace( " <b> ", string.Empty).Replace( " </b> ", string.Empty);
}
return newArticle;
}
最終程序界面
最后
如前文所說,中文偽原創幾乎是一片空白。希望本文能夠啟到拋磚引玉的作用,更希望有興趣的同學能夠與我一起繼續不斷的完善、改進它。






