1 寫在前面
最近想要在百度網盤里面搜索一些pdf資源,打開以前保存的一個專門搜索百度網盤資源的頁面so.baiduyun.me ,頁面轉了好久,終於出來,但是出現的卻是Error 522,鏈接失效了。最后,在網上找到一個可以用的地址http://pan.java1234.com/,這個地址確實可以搜索百度網盤資源,但是廣告超級多,稍有不慎,就進入了一個廣告頁面,神煩。當時就想能不能尋找到這個網頁中資源搜索的地址,然后自己根據這個地址來模擬請求,從而獲得查詢結果。打開瀏覽器的調試工具,隨意輸入一個關鍵字進行查詢,點擊查詢,然后進行分析。分析發現了一個url請求返回的正是百度網盤搜索結果,數據是json格式。找到了這個獲取搜索結果url之后就好辦了。我們可以完全自己寫一個Winform界面,然后通過這個url去模擬請求,獲取結果,這樣就沒有廣告了,想怎么弄就怎么弄,下面介紹一下,如何完成這一系列的過程。
2 分析
2.1 獲取請求頭信息
實現這個程序的關鍵就是如何獲取http://pan.java1234.com/百度網盤搜索結果的url,首先我們打開這個頁面,啟動瀏覽器調試,然后隨意輸入一個關鍵字,點擊查詢。

上圖我們可以看到,有一個請求url,返回來的結果就是頁面上顯示的搜索結果。我們可以看看它的請求地址以及請求頭信息。

通過查看headers面板可以知道請求信息如下:
- 請求地址:http://pan1234.com/server3?jsoncallback=jQuery19109864917922941505_1478436979648&q=win7&start=0&_=1478436979649
- User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36
- Reference:http://pan.java1234.com/result2.jsp?wp=0&op=0&ty=gn&q=win7
- Host:pan1234.com
知道請求地址,user-agent,host,referer請求頭信息,我們就可以構造出一個搜索資源的請求,現在我們來分析一下這個請求地址的特點,這個請求地址有一個查詢參數q=win7,而我們知道先前在搜索框里面輸入的關鍵字就是win7,由此可以判斷,該查詢參數代表的搜索關鍵字。我們可以把這個請求地址在瀏覽器中打開,然后去去更改這些查詢參數,來分析這些查詢參數各有什么作用。
經過分析,請求地址中的q參數代表的是搜索關鍵字;start參數代表的是搜索頁面,一共有10頁,0代表第一頁,10代表第二頁,···,90代表第十頁,該網頁最高顯示100條資源結果;而最后的&_=1478436979649可以刪掉,在請求中沒有實質的作用。
2.2 分析返回的搜索結果格式
經過2.1節分析,我們知道搜索結果的url地址,現在我們隨意的構造一個如下。
http://pan1234.com/server3?jsoncallback=jQuery19109864917922941505_1478436979648&q=win7&start=0
在瀏覽器中顯示的效果如下:

我們可以知道搜索結果是以json字符串的格式返回的。返回的是一個對象數組,每個資源對象都包含了title,content,unescapedUrl三個屬性。
知道了返回的json格式結構,我們就可以在c#中建立相對應的類,然后將這些json數據經過預處理,之后便可以反序列化成為相對應的對象。
3.程序實現
下面將貼出實現該程序的關鍵代碼,源代碼可以到本文章的末尾自行下載。
3.1 數據實體類
public class SearchResult
{
public BDWPResource[] resources { get; set; }
}
public class BDWPResource
{
public string title { get; set; }
public string content { get; set; }
public string unescapedUrl { get; set; }
}
3.2 數據請求及預處理
class HttpHelper
{
static readonly string urlTemplate = "http://pan1234.com/server3?jsoncallback=jQuery191042552483269501273_1478315152726&q={0}&start={1}";
public static SearchResult Requset(string key, string start)
{
string url = string.Format(urlTemplate, key, start);
HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(url);
httpRequest.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8";
httpRequest.UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36";
httpRequest.Host = "pan1234.com";
httpRequest.Referer = "http://pan.java1234.com/result.jsp?wp=0&op=0&ty=gn&q=" + Uri.EscapeUriString(key);
try
{
HttpWebResponse httpResponse = (HttpWebResponse)httpRequest.GetResponse();
Stream s = httpResponse.GetResponseStream();
StreamReader sr = new StreamReader(s);
string jsonString = sr.ReadToEnd();
string jsonProcessed = null;
if ((jsonProcessed = JsonPreProcessing(jsonString)) != null)
{
SearchResult searchResult = UtilityClass.GetObject<SearchResult>(jsonProcessed);
return searchResult;
}
return null;
}
catch
{
return null;
}
}
public static string JsonPreProcessing(string jsonString)
{
int startIndex = jsonString.IndexOf("(");
if (startIndex > 0)
{
string json = jsonString.Substring(startIndex + 1);
return "{\"resources\":" + json.Remove(json.Length - 3) + "}";
}
else
{
return null;
}
}
}
3.3 json數據反序列化對象
class UtilityClass
{
public static T GetObject<T>(string json)
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(json));
T obj = (T)serializer.ReadObject(ms);
return obj;
}
}
3.4 界面
界面設計如下:

將網絡請求的代碼放到任務線程中進行執行。代碼如下:
Thread thread = new Thread(() =>
{
for (int i = 0; i < 100; i += 10)
{
if (isSearch)
{
SearchResult sr = HttpHelper.Requset(key, i.ToString());
if (sr != null)
{
foreach (BDWPResource resource in sr.resources)
{
BindResource(resource);
}
}
}
else break;
}
//搜索完成
SearchOver();
});
thread.IsBackground = true;
thread.Start();
//綁定數據代碼
private void BindResource(BDWPResource resource)
{
string title = resource.title.Replace("</b>", "").Replace("<b>","");
string content = resource.content.Replace("</b>", "").Replace("<b>", "");
this.Invoke(new Action<string, string, string>((tle, ctt, url) =>
{
this.dataGridView1.Rows.Add(tle, ctt, url);
this.lblResult.Text = (Int32.Parse(this.lblResult.Text) + 1).ToString();
this.pgsBar.Value++;
}), title, content, resource.unescapedUrl);
}
//搜索完成
private void SearchOver()
{
this.Invoke(new Action(() => {
this.btnSearch.Text = "開始搜索";
this.btnSearch.Enabled = true;
this.btnStop.Enabled = false;
this.isSearch = true;
}));
}
3.5 程序運行結果


4 結論
該程序搜索速度有時候比較慢,有時間快,剛開始點擊搜索一般都要等一會才有結果,可能有網絡延遲的原因。但發現搜索一會還沒結果的時候,可以先停止搜索,然后再點擊開始搜索,就會有搜索結果出來了。
