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 结论
该程序搜索速度有时候比较慢,有时间快,刚开始点击搜索一般都要等一会才有结果,可能有网络延迟的原因。但发现搜索一会还没结果的时候,可以先停止搜索,然后再点击开始搜索,就会有搜索结果出来了。