因为项目需求一个省市县三级数据库结构并且要求市的院校信息及院校的院系信息。百度了一圈并没有找到合适的。无意中发现QQ校友录的院校选择地址并没有做限制(http://api.pengyou.com/index.php?mod=school&act=selectorpage&type=3)于是想通过这个页面来抓取信息,尝试了一下,院校信息可以抓取,但是院系信息没办法抓取过来(水平问题,院系地址是http://api.pengyou.com/html/select_collage.html,因为不是Get参数,而是通过一个hidden来传递过去的院校ID,所以没有实现,让自己技术水平在菜一会……)。后来转到人人网,无意中发现它的院校信息是写到一个js文件里面(http://s.xnimg.cn/a13819/allunivlist.js),并发现院系查询页面没有做登录验证(人人 - 加入人人,找到老同学,结识新朋友)而且是Get的参数。于是下载这个Js文件看了一下,是16进制转换过的,而且不仅有中国的院校,还有国外的院校信息:)。
但是我用不到国外的院校信息,而且不喜欢这样转换过的数据(因为要调试数据什么的,还是直接看中国字比较好)。所以先写了个函数把16进制转成中国字。
private void button1_Click(object sender, EventArgs e)
{
StringBuilder sb = new StringBuilder();
StreamReader sr = new StreamReader(Application.StartupPath + "\\school.js", Encoding.Default);
sb.Append(sr.ReadToEnd());
sr.Close();
ConverToGB(sb.ToString(),16);
textBox1.Text = sb.ToString();
}
/// <summary>
/// 转换为中文
/// </summary>
/// <param name="name">要转换的字符串</param>
/// <param name="fromBase">进制后期有用</param>
/// <returns></returns>
public string ConverToGB(string text, int fromBase)
{
string value = text;
MatchCollection mc;
mc = Regex.Matches(text, @"\\u([\w]{2})([\w]{2})", RegexOptions.Compiled | RegexOptions.IgnoreCase);
if (mc != null && mc.Count > 0)
{
StringBuilder sb = new StringBuilder();
foreach (Match m2 in mc)
{
string v = m2.Value;
string w = v.Substring(2);
byte[] c = new byte[2];
int c1 = Convert.ToInt32(w.Substring(0, 2), 16);
int c2 = Convert.ToInt32(w.Substring(2), 16);
c[0] = (byte)c2;
c[1] = (byte)c1;
sb.Append(Encoding.Unicode.GetString(c));
}
value = sb.ToString();
}
return value;
}
然后把textbox1.Text的内容复制到一个新的js文件里面,并把开头的var allUnivList =和国外的信息都删除掉(我不需要外国的数据),最终只保留中国的院校信息的JSon格式数据(最后的结尾是"name": "台湾"}]}])。
然后给VS2010下载Newtonsoft.Json 4.5.11,步骤如下:
1、直接去官网下载(百度一下)。
2、点击VS2010的 视图--其它窗口--Package Manager Console 然后在下面的Package Manager Console的PM>后面输入Install-Package Newtonsoft.Json 等待下载完成(和网速有关系)。
下面我们要通过Newtonsoft.Json来读取我们刚才保存的人人网的省信息、院校信息。
最新的Newtonsoft.Json做了以下调整
原来的JavaScriptArray变成了JArray
原来的JavaScriptConvert变成了JsonConvert
原来的JavaScriptObject变成了JObject
PS:以上三个信息来自(Newtonsoft.Json.4.5.11使用方法总结---反序列化json字符串_江下飞雪的博客-CSDN博客),在此表示十分感谢!!
人人网的院系查找接口(人人 - 加入人人,找到老同学,结识新朋友)直接返回的是一个<select>Html控件,并且内容用十进制表示。这里我需要把十进制转成中文(直接看十进制实在是看不懂)。重写了ConverToGB函数如下。
/// <summary>
/// 转换为中文
/// </summary>
/// <param name="name">要转换的字符串</param>
/// <param name="fromBase">进制</param>
/// <returns></returns>
public string ConverToGB(string text, int fromBase)
{
string value = text;
MatchCollection mc;
switch (fromBase)
{
case 10:
mc = Regex.Matches(text, @"<option value='(?<value>&#([\d]{5})[^']+).*?>", RegexOptions.Compiled | RegexOptions.IgnoreCase);
if (mc != null && mc.Count > 0)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < mc.Count; i++)
{
sb.Append("---");
string v = mc[i].Groups["value"].Value;
MatchCollection mc1 = Regex.Matches(v,@"&#([\d]{5})", RegexOptions.Compiled | RegexOptions.IgnoreCase);
foreach (Match _v in mc1)
{
string w = _v.Value.Substring(2);
w = Convert.ToString(int.Parse(w), 16);
byte[] c = new byte[2];
string ss = w.Substring(0, 2);
int c1 = Convert.ToInt32(w.Substring(0, 2), 16);
int c2 = Convert.ToInt32(w.Substring(2), 16);
c[0] = (byte)c2;
c[1] = (byte)c1;
sb.Append(Encoding.Unicode.GetString(c));
}
sb.Append(Environment.NewLine);
}
value = sb.ToString();
}
break;
case 16:
mc = Regex.Matches(text, @"\\u([\w]{2})([\w]{2})", RegexOptions.Compiled | RegexOptions.IgnoreCase);
if (mc != null && mc.Count > 0)
{
StringBuilder sb = new StringBuilder();
foreach (Match m2 in mc)
{
string v = m2.Value;
string w = v.Substring(2);
byte[] c = new byte[2];
int c1 = Convert.ToInt32(w.Substring(0, 2), 16);
int c2 = Convert.ToInt32(w.Substring(2), 16);
c[0] = (byte)c2;
c[1] = (byte)c1;
sb.Append(Encoding.Unicode.GetString(c));
}
value = sb.ToString();
}
break;
}
return value;
}
上面那个@"<option value='(?<value>&#([\d]{5})[^']+).*?>"的正则估计不是太好,凑合用吧。
然后通过Http提交数据挨个返回院校的信息(这里比较慢,因为没用多线程,光循环了)。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Text.RegularExpressions;
using System.Web;
using System.Net;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
private void button1_Click(object sender, EventArgs e)
{
StringBuilder sb = new StringBuilder();
StreamReader sr = new StreamReader(Application.StartupPath + "\\school.js", Encoding.Default);
sb.Append(sr.ReadToEnd());
sr.Close();
JArray ja = (JArray)JsonConvert.DeserializeObject(sb.ToString());//国家
sb.Clear();
for (int i = 0; i < ja.Count; i++)
{
JObject obj = (JObject)ja[i];
sb.Append("id:" + obj["id"].ToString());
sb.Append("univs:" + obj["univs"].ToString());
sb.Append("name:" + obj["name"].ToString() + Environment.NewLine);
JArray json = (JArray)obj["provs"];
for (int j = 0; j < json.Count; j++)//省
{
JObject jsonobj = (JObject)json[j];
sb.Append("-id:" + jsonobj["id"].ToString());
sb.Append(" name:" + jsonobj["name"].ToString());
sb.Append(" country_id:" + jsonobj["country_id"].ToString() + Environment.NewLine);
JArray json1 = (JArray)jsonobj["univs"];//学校
for (int k = 0; k < json1.Count; k++)
{
JObject jsonobj1 = (JObject)json1[k];
sb.Append("--id:" + jsonobj1["id"].ToString());
sb.Append(" name:" + jsonobj1["name"].ToString() + Environment.NewLine);
//下面是获取院系
String yxUrl = "http://www.renren.com/GetDep.do?id=" + jsonobj1["id"].ToString() + "";
HttpWebRequest get = (HttpWebRequest)WebRequest.Create(yxUrl);
StringBuilder sbde = new StringBuilder();
HttpWebResponse hp = (HttpWebResponse)get.GetResponse();
Stream stream = hp.GetResponseStream();
sr = new StreamReader(stream, Encoding.Default);
sbde.Append(sr.ReadToEnd());
sr.Close();
sb.Append(ConverToGB(sbde.ToString(), 10));
}
}
}
textBox1.Text = sb.ToString();
}
至此,就获取了全国的院校的院系信息,程序在改进一下就可以直接生成SQL脚本文件了。
PS:朋友网的数据更多,不但有高校的,还有中专中职,高中,中学,小学的院系和班级信息,可惜水平比较菜,没有办法抓取下来(http://api.pengyou.com/index.php?mod=school&act=selectorpage&type=3更改type后面数字)。