使用wikipedia提供的API获取维基百科数据

  维基百科(Wikipedia)作为一个自由、免费、内容开放的百科全书协作计划,包含人类所有知识领域的信息,其内容中立不偏不倚,深受广大用户的喜爱。最近我需要搜集一些研究机构的信息概览,维基百科自然成了首选。欣喜之中怅然发现有关维基百科开放平台的相关资料和代码十分稀少,好在经过一番努力终于成功的将数据抓取下来,这里分享一些片段。

  一、维基百科开放平台:

  维基百科目前开放一些基于HTTP连接的API共用户使用,连接端点地址:

  http://www.mediawiki.org/w/api.php

  查询不同语言版本只需要将地址中的www更换成相应语言标志即可,比如查找英语资料可以连接:http://en.wikipedia.org/w/api.php

  当然,仅仅只有连接地址服务器是不知道用户需求的,我们还需要添加一些命令参数。这里对查询语句做一些简单介绍: action= query。这个命令表示用户向维基百科发出查询请求,另外用户还可以通过类似的方式更改百科的内容。query命令里包含丰富的参数:可以用prop = ….来标识。

  1.prop = info  检索基本的页面信息。info里的参数通过inprop=…来选择,比如:

      inprop=url : 查询页面的完整地址和编辑地址

      inprop=protection: 查询页面的保护等级

    命令中会默认包含一些参数,比如pageid,ns(namespace),title等等。

 

  2. prop = revisions&rvprop=content 查询最新的页面内容。 rvrevisions和rvprop还可以设为其它参数,这里不一一列举。

  3.prop=images 获得页面中的图片信息(图片的名称),可以作为作为获取图片详细信息的参数

    prop=imageinfo,imageinfo还可以设置参数比如: iiprop=url(获取图片的完整地址),iiprop=size(图片大小),等等。

 

    这里需要特别强调的是维基百科要求HTTP连接时提供用户的代理,这里给出两种典型的HTTP连接配置:

    (1) 使用webcliet:

1 WebClient client = new WebClient(); 
2 
3 client.Headers.Add("User-Agent", "Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)");
4  client.Encoding = System.Text.Encoding.UTF8;    //使用UTF8编码格式     
5 Uri orgUri = new Uri(“http://en.wikipedia.org/w/api.php?action=query&prop=info&inprop=url&format=xml&titles=Albert Enistein” , UriKind.Absolute);
6 string s = client.DownloadString(orgUri);

   

(2)使用HTTPRequest

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(orgUri);

request.UserAgent = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 5.2; .NET CLR 1.0.3705)";

HttpWebResponse response = (HttpWebResponse)request.GetResponse();

Stream receiveStream = response.GetResponseStream();
StreamReader readstream = new StreamReader(receiveStream, Encoding.UTF8);
char[] readtext = new char[50240];
int numOfCharacters = readstream.Read(readtext, 0, 50240);

string s = new string(readtext, 0, numOfCharacters);

  
       这里只是一个简单介绍,具体的技术文档可以参见http://www.mediawiki.org/wiki/API:Properties#images_.2F_im

  二、示例分析:

  获取机构在维基百科的地址,代表图片,简介(其实就是维基百科中开头几句话,可以作为一个概览提供给用户,而不需要用户每个机构都得点到维基百科里)

  1.机构的地址

英文维基百科镜像 2024_xml

英文维基百科镜像 2024_维基百科_02

View Code

1 static string searchOrgURLInWiki(string name)
 2         {
 3             WebClient client = new WebClient();
 4             client.Headers.Add("User-Agent", "Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)");           
 5             Uri orgUri = new Uri("http://en.wikipedia.org/w/api.php?action=query&prop=info&inprop=url&format=xml&titles=" + name,
 6                  UriKind.Absolute);
 7             string s = "";
 8 
 9             Console.WriteLine("searching the organization" + name + "'s Url.......");
10             try
11             {
12                 s = client.DownloadString(orgUri);
13                 StreamWriter outfile = new StreamWriter(@"D:\orgURl.xml");
14                 outfile.Write(s);
15                 outfile.Close();
16             }
17             catch (Exception ex)
18             {
19                 Console.WriteLine(ex.Message);
20                 return "";
21             }
22             finally
23             {
24                 client.Dispose();
25             }
26 
27             if (s.Length == 0)
28             {
29                 Console.WriteLine("not found...");
30                
31                 return "";
32             }
33              
34 
35             String xmlString = s;
36             string orgUrl = "";
37           
38             using (XmlReader reader = XmlReader.Create(new StringReader(xmlString)))
39             {
40                 reader.ReadToFollowing("page");
41                 //   reader.MoveToFirstAttribute();
42                 reader.MoveToAttribute("fullurl");
43                 orgUrl = reader.Value;
44 
45                 reader.MoveToAttribute("title");
46                 name = reader.Value;
47             }
48 
49             if (orgUrl.Length == 0)
50             {
51                 Console.WriteLine("not found...");                
52                 return "";
53             }
54 
55             Console.WriteLine("organization Url in wikiPedia:");
56             Console.WriteLine(orgUrl);
57             Console.WriteLine("Getting organization url finished!");
58            
59             return orgUrl;
60         }

  

  这段代码是最基本的一个应用,先从wiki获得页面xml格式的的基本信息,然后从xml中读取fullurl属性的值

 

  2.获取机构的图片:

  (1)首先必须知道机构所在页面中包含哪些图片,同示例的代码基本一样,只需要更改查询URL中的几个参数:

static private string searchOrgImageURL(string name)
        {
           ………
             Uri orgUri = new Uri("http://en.wikipedia.org/w/api.php?action=query&prop=images&format=xml&titles=" + name,
                  UriKind.Absolute);

………
             Console.WriteLine("images found!");
             Console.WriteLine("searching logo.......");

string imageURL = getLogoImage(name,xmlDocPath);
                                ………           

return imageURL;
        }

  

  上面这段代码最核心的部分其实是getLogoImage这个函数,也就是在一堆可选的图片里面选择最合适的。对于一个机构,最合适的图片一般是logo,gate,campus,building,flag。为了达到比较好的效果,我将图片的名称经过一个过滤和优先级选择,凡是包含commons-logo的图片直接pass(大多页面中都包含,这只是目前小数据量下的stop-list,数据量增大时可以增加这个stop-list),凡是包含universi,logo,campus,gate等词的可以直接选择。

英文维基百科镜像 2024_xml

英文维基百科镜像 2024_维基百科_02

View Code

static private string getLogoImage(string org,string xmlDocPath)
        {
string logoName = "";
string logoNameTemp = "";

string imageUrl = "";

            XmlDocument xmldoc= new XmlDocument();
            xmldoc.Load(xmlDocPath);

//得到顶层节点列表
            XmlNodeList topM=xmldoc.DocumentElement.ChildNodes;
            XmlNodeList test = xmldoc.SelectNodes("descendant::images[im]");
foreach (XmlElement element in test)
            {
if (element.Name.ToLower() == "images")
                {

//得到该节点的子节点
                    XmlNodeList nodelist = element.ChildNodes;

if (nodelist.Count > 0)
                    {
foreach (XmlElement el in nodelist)//读元素值
                        {
                            logoNameTemp = el.Attributes["title"].Value;
                            logoName = logoNameTemp;
                            logoNameTemp = logoNameTemp.ToLower();

if (logoNameTemp.Contains("commons-logo") || logoNameTemp.Contains("big ten conference logo"))
continue;

if (logoNameTemp.Contains("logo") || logoNameTemp.Contains("campus") || logoNameTemp.Contains("gate")
|| logoNameTemp.Contains("university") || logoNameTemp.Contains("flag"))
                                {
                                    imageUrl = readImageUrl(logoName);
if (imageUrl.Length != 0)
                                    {
if (DocumentWorker.saveimage(imageUrl, logoName, org) == true)
                                        {
                                            Console.WriteLine(imageUrl);
return "/AcademicMap;component/Images/orgImages/" + org + ".jpg";
                                        }
                                    }
                                }

                        }
foreach (XmlElement el in nodelist)//读元素值
                        {
                            logoNameTemp = el.Attributes["title"].Value;
                            logoName = logoNameTemp;
                            logoNameTemp = logoNameTemp.ToLower();

if (logoNameTemp.Contains("commons-logo"))
continue;

                            imageUrl = readImageUrl(logoName);
if (imageUrl.Length != 0)
                            {
if (DocumentWorker.saveimage(imageUrl, logoName, org) == true)
                                {
                                    Console.WriteLine(imageUrl);
return "/AcademicMap;component/Images/orgImages/" + org + ".jpg";
                                }
                            }  
                        }
                    }
                }
            }

return "";
        }

  

  上面用到一个readImageUrl函数,和searchOrgImageURL只有参数选择上的差异,这里不详细介绍。

 

  3、获得机构的介绍,这个工作比较复杂,我们可以获得文件格式包括html,php,xml,yaml等等,但是多数情况下xml文件都能够满足要求,这里不给出具体代码(只是我要获取特定的信息,不具有普遍的参考价值),只是介绍一下一般情况下返回来的文件结构(以机构为例):

<?xml version=”1.0”…….>
{{Redirect|Harvard}}     
{{Infobox university……
}}
<!--以上是机构的一些基本信息,对应wiki中右侧的那一栏- ->
<!-- 以下是机构的introduction- ->
………
==History==
…
====Religion and philosophy====
……

  可以发现,文件的结构特征很明显,查询不同模块的信息只需要找到相应模块的关键字即可,比如要查询历史信息,只需要匹配到==History==一般问题就不大了。当然,相对比较纠结一点的是获取introduction,需要准确定位到它上面那个“}}”,InfoBox 里面一般还嵌套有“{{ }}”,所以定位是不能简单的找到“}}”,可能需要利用一个栈结构来决定当前花括号的匹配情况。

 

  三、结果示例: 比如查询中国科学院的信息,会得到一下结果:

searching the organizationChinese Academy of Sciences's Url....... organization Url in wikiPedia:
http://en.wikipedia.org/wiki/Chinese_Academy_of_Sciences
Getting organization url finished!

searching the organization Chinese Academy of Sciences's introduction....... introduction:
'''Chinese Academy of Sciences''' ('''CAS''') ( ), formerly known as '''Academia
Sinica''', is the national academy for the natural sciences of the People's Rep
ublic of China. It is an institution of the State Council of China. It is headqu
artered in Beijing, with institutes all over the People's Republic of China. It
has also created hundreds of commercial enterprises, Lenovo being one of them.

==Organization==
The Chinese Academy of Sciences has six sections:

*Mathematics and Physics,
*Chemistry,
*Life Sciences and Medicine,
*Earth Sciences,
*Information Technical Sciences,  and
*Technological Sciences.

The CAS has eleven regional branches at Shenyang, Changchun, Shanghai, Nanjing,
Wuha
Getting Chinese Academy of Sciences's introduction finished!

searching the organization images....... images found!
searching logo.......
getting the image URL.......
File:Chinese Academy of Sciences logo.jpg download succeed
http://upload.wikimedia.org/wikipedia/en/9/9c/Chinese_Academy_of_Sciences_logo.j
pg
Getting image URL finished!

搜索到的图片:

英文维基百科镜像 2024_英文维基百科镜像 2024_05