怎样利用CSDN论坛公开的API实现自己的论坛工具

csdn论坛公开了一些常用api,不过内部测试阶段,地址是http://forum.csdn.net/OpenApi/forumapi.asmx还有一个使用的demo,http://forum.csdn.net/OpenApi/ForumOpenAPIDemo.rar,源码在这里下载demo源码

总体概述:

 公开的方法如下:

至于获得帖子和获得帖子列表的方法,虽然没有提供独立的api,但是都可以借助论坛现有的资源,待会会单独讲到

上面的API除了GetForums外,都需要输入一个identity实体,表明你的身份,返回了一个bool型变量,表示操作是否完成,结果会以out变量的形式输出,同时输出的一般还有错误信息Error

identity的参考定义如下

     ///   <summary>
    
///  用户身份信息
    
///   </summary>
     public   struct  Identity{
        
///   <summary>
        
///  用户名
        
///   </summary>
         public   string  username;
        
///   <summary>
        
///  密码
        
///   </summary>
         public   string  password;
    }

他包含用于身份验证的用户名和密码,除获得论坛列表以外,其他的操作均要求此参数,调用者可以将用户信息加密存与本地,详细请参考账户管理


而错误信息的参考定义如下

 

  ///   <summary>
    
///  错误信息
    
///   </summary>
     public   struct  Error
    {
        
///   <summary>
        
///  错误id
        
///   </summary>
         public   int  errId;

        
private   string  _errInfo;
        
///   <summary>
        
///  错误信息
        
///   </summary>
         public   string  errInfo;

        
///   <summary>
        
///  描述
        
///   </summary>
         public   string  description;

}

   

这个实体存放了调用过程中返回的错误,如果返回结果为false,我们就可以查看或者错误信息:

比如下面的积分捐赠的代码段

Identity id = dp.GetDefaultAccount();
Error error;

if  ( ! openApiService.PointDonate(dp.GetDefaultAccount(), tbUserName.Text, point,  " abc " out  error))
 ErrorForm.ShowDialog(error);
else
 MessageBox.Show(
" 捐赠成功 " );

 

获得论坛GetForums

GetForums 非常的简单,没有传入参数,方法的返回值是一个Forum实体数组

Forum的参考定义和具体字段含义如下

     ///   <summary>
    
///  论坛信息
    
///   </summary>
     public   struct  Forum
    {
        
///   <summary>
        
///  论坛id
        
///   </summary>
         public  Guid forumId;
        
///   <summary>
        
///  父论坛id
        
///   </summary>
         public  Guid parentForumId;
        
///   <summary>
        
///  论坛名称
        
///   </summary>
         public   string  name;
        
///   <summary>
        
///  别名
        
///   </summary>
         public   string  alias;
        
///   <summary>
        
///  是否技术论坛
        
///   </summary>
         public   bool  IsTech;
        
///   <summary>
        
///  版主
        
///   </summary>
         public   string [] morderators;
        
///   <summary>
        
///  积分归属论坛
        
///   </summary>
         public  Guid pointBelongsToForumId;

    }


 

获得用户信息GetUserProfile :

方法定义如下:

         ///   <summary>
        
///  获得用户信息
    
///   </summary>
        
///   <param name="identity"> 用户身份信息 </param>
        
///   <param name="profile"> 用户信息 </param>
        
///   <param name="error"> 错误信息 </param>
        
///   <param name="username"> 需要获得用户信息的用户名 </param>
        
///   <returns> 操作是否成功 </returns>
         public   bool  GetUserProfile(Identity identity,  string  username,  out  UserProfile profile,  out  Error error)

 

此方法用于查询某用户的用户信息,包括用户昵称,可用分,用户技术专家分,非技术专家分,以及他在各个论坛的得分和级别(只展示用户在其有得分的论坛信息)

用户信息UserProfile的参考定义和字段含义如下

public   struct  UserProfile
    {
        
///   <summary>
        
///  可用分
        
///   </summary>
         public   int  point;
        
///   <summary>
        
///  技术专家分
        
///   </summary>
         public   int  techExpertPoint;
        
///   <summary>
        
///  用户在各个论坛的积分和级别信息
        
///   </summary>
         public  List < TopForum >  topForums;
        
///   <summary>
        
///  非技术专家分
        
///   </summary>
         public   int  nonTechExpertPoint;
        
///   <summary>
        
///  昵称
        
///   </summary>
         public   string  nickName;
        
///   <summary>
        
///  用户名
        
///   </summary>
         public   string  username;
    }

    
///   <summary>
    
///  用户在各个论坛的积分和级别
    
///   </summary>
     public   struct  TopForum{
        
///   <summary>
        
///  论坛
        
///   </summary>
         public  Guid forumId;
        
///   <summary>
        
///  专家分
        
///   </summary>
         public   int  expertPoint;
        
///   <summary>
        
///  星级
        
///   </summary>
         public   string  rank;
    }

发帖Post :

发帖方法定义如下

 

         /// <summary>
        
/// 发帖
        
/// </summary>
        
/// <param name="identity">用户身份证</param>
        
/// <param name="post">帖子</param>
        
/// <param name="error">错误信息</param>
        
/// <param name="topicUrl">帖子链接</param>
        
/// <returns>发帖是否成功</returns>

         public   bool  Post(Identity identity, Post post,  out  Error error,  out   string  topicUrl)

 

Post结构参考定义

 

///   <summary>
    
///  帖子
    
///   </summary>
     public   struct  Post
    {
        
///   <summary>
        
///  论坛id(发帖时必须)
        
///   </summary>
         public  Guid forumId;
        
///   <summary>
        
///  标题(发帖时必须)
        
///   </summary>
         public   string  subject;
        
///   <summary>
        
///  帖子内容(发帖时必须)
        
///   </summary>
         public   string  body;
        
///   <summary>
        
///  标签
        
///   </summary>
         public   string  tag;
        
///   <summary>
        
///  给分
        
///   </summary>
         public   int  point;
        
///   <summary>
        
///  是否问专家贴(发帖时必须)
        
///   </summary>
         public   bool  isAskExpert;
        
///   <summary>
        
///  专家用户名称(若isAskExpert,必须)
        
///   </summary>
         public   string  expertUserName;
        
///   <summary>
        
///  编辑器类型(发帖时必须),现只支持ubb类型
        
///   </summary>
         public  EditorType editor;
        
///   <summary>
        
///  帖子链接
        
///   </summary>
         public   string  url;

    }

回帖Reply :

 

         /// <summary>
        
/// 回复帖子
        
/// </summary>
        
/// <param name="identity">用户身份证</param>
        
/// <param name="reply">回复</param>
        
/// <param name="error">错误信息</param>
        
/// <param name="replyId">回复id</param>
        
/// <param name="layer">楼层</param>
        
/// <returns>回复是否成功</returns>

         public   bool  Reply(Identity identity, Reply reply,  out  Error error,  out   long  replyId,  out   int  layer)

 

回复实体参考定义如下

     ///   <summary>
    
///  回复
    
///   </summary>
     public   struct  Reply
    {
        
///   <summary>
        
///  论坛id(必须)
        
///   </summary>
         public  Guid forumId;
        
///   <summary>
        
///  帖子url(必须)
        
///   </summary>
         public   string  topicUrl;
        
///   <summary>
        
///  回复内容(必须)
        
///   </summary>
         public   string  body;
        
///   <summary>
        
///  是否需要ubb(必须)
        
///   </summary>
         public  EditorType editor;
    }

 

结帖CheckOutTopic:

 

        ///   <summary>
        
///  结贴
        
///   </summary>
        
///   <param name="identity"> 用户身份证 </param>
        
///   <param name="topicUrl"> 帖子链接 </param>
        
///   <param name="forumId"> 论坛id </param>
        
///   <param name="replyPoints"> 回复给分列表 </param>
        
///   <param name="error"> 错误 </param>
        
///   <returns> 结贴是否成功 </returns>
         public   bool  CheckOutTopic(Identity identity,  string  topicUrl, Guid forumId, List < ReplyPoint >  replyPoints,  out  Error error)

 

 List<ReplyPoint> replyPoints为回复id和给分数组

 

     ///   <summary>
    
///  回帖得分
    
///   </summary>
     public   struct  ReplyPoint
    {
        
///   <summary>
        
///  回复id
        
///   </summary>
         public   long  replyId;
        
///   <summary>
        
///  得分
        
///   </summary>
         public   int  point;
    }

积分捐赠PointDonate

 

         ///   <summary>
        
///  可用分捐赠
        
///   </summary>
        
///   <param name="identity"> 用户身份证 </param>
        
///   <param name="toUser"> 捐赠对象 </param>
        
///   <param name="point"> 捐赠积分 </param>
        
///   <param name="reason"> 原因 </param>
        
///   <param name="error"> 错误 </param>
        
///   <returns> 捐赠是否成功 </returns>
         public   bool  PointDonate(Identity identity,  string  toUser,  int  point,  string  reason,  out  Error error)

 

获得我的帖子,我参与的帖子,我得分的帖子,别人问我的帖子 GetTopicsOfUser

 

         ///   <summary>
        
///  获得我发表的帖子,我回复过的帖子,我得分的帖子
        
///   </summary>
        
///   <param name="listType"> 列表类型 </param>
        
///   <param name="forumId"> 论坛id </param>
        
///   <param name="posts"> 帖子列表 </param>
        
///   <param name="error"> 错误信息 </param>
        
///   <param name="identity"> 身份信息 </param>
        
///   <returns> 是否成功 </returns>
        [WebMethod]
        
public   bool  GetTopicsOfUser(Identity identity, UserTopicListType listType, Guid forumId,  out  List < Post >  posts,  out  Error error)

 

列表类型定义如下

    ///   <summary>
    
///  用户帖子列表类型
    
///   </summary>
     public   enum  UserTopicListType
    {
        
///   <summary>
        
///  用户的帖子
        
///   </summary>
        TopicOfUser,

        
///   <summary>
        
///  用户回复过的帖子
        
///   </summary>
        TopicUserJoined,

        
///   <summary>
        
///  用户得分的帖子
        
///   </summary>
        TopicUserRewarded,

        
///   <summary>
        
///  所有问专家
        
///   </summary>
        AllAskExpert
    }

 

获得帖子列表

获得帖子列表,包括

  • 待解决
  • 抢分区
  • 零回复
  • 热点区
  • 已解决
  • 精华区

    没有提供独立的Webservice,原因是这些帖子列表均提供了Rss,调用者通过Rss获得需要的信息

    一个列子列表的rss链接由论坛别名和列表类型两部分组成

    比如灌水乐园抢分区的Rss链接为http://forum.csdn.net/Rss/FreeZone/RobPointList/

    其中黄色部分(FreeZone)为论坛别名,红色部分(RobPointList)表明列表类型为抢分区,我们可以通过如下代码简单实现取得rss并转为dataset

     

    public  DataTable GetTopicListRss()
            {
                
    string  url  =   " http://forum.csdn.net/Rss/FreeZone/RobPointList/ " ;
                HttpWebRequest request 
    =  HttpWebRequest.Create(url)  as  HttpWebRequest;
                WebResponse response
    = request.GetResponse();
                DataSet result 
    =   new  DataSet();
                Stream rssStream 
    =  response.GetResponseStream();
                StreamReader sr 
    =   new  StreamReader(rssStream, Utility.GetEncoding());
                result.ReadXml(sr);
                
    return  result.Tables[ 2 ];
            }

     

    获得与解析帖子

    公开的API也没专门获得帖子的方法,主要是处于性能的考虑,想要获得帖子,就直接获取帖子html文件,如果需要帖子的信息,比如发帖人,分数,就必须解析帖子文件,文件中提供了一系列标识(csdnid),让解析者可以通过其找到对应的内容,并且在所附demo中,也提供了一个经过改造的解析模块,调用者可以使用这个模块,通过csdnid来找到帖子文件中具体的内容

    什么是csdnid?

    打开任意一个帖子文件,里面都会看到一些由csdnid标识的元素,这些元素的属性和内容一般都具有特殊的意义,比如帖子源文件中的下面html代码

     

    < meta  id ="topicViewUrl"  csdnid ="topicViewUrl"  content ="http://topic.csdn.net/u/20080328/15/ce3f9a96-7f91-4dea-83fb-23beffe36cb8.html" >
    < meta  csdnid ="sectionId"  content ="a3049f56-b572-48f5-89be-4797b70d71cd" >

     

    csdnid="topicViewUrl" 的meta元素的content属性,说明了帖子的url,为:http://topic.csdn.net/u/20080328/15/ce3f9a96-7f91-4dea-83fb-23beffe36cb8.html

    而csdnid="sectionId"的meta元素的content属性,说明了帖子的论坛id为:
    a3049f56-b572-48f5-89be-4797b70d71cd

    而<var csdnid="topicUsername" id="topicUserName">Orange1997</var>中,此元素的innerHTML为发帖用户名

    如何解析帖子文件并得到我们想要的信息

     解析html文件有很多方法,这里使用使用经过改进的开源html解析其HtmlAgilityPack,Demo中有此模块,

  • 基本使用方法

    加载Html文件

    下面方法可以把某个html加载进来

    HtmlDocument d = new HtmlDocument();
    d.Load("C:/test.html");

    Load方法还有多个重载,可以从Stream,StreamReader等对象中加载html文档

    加载后使用GetElementsbyCsdnId来获得指定csdnid标识的元素,比如

    d.GetElementsbyCsdnId("topicBody"),获得所有用csdnid="topicBody"标识的元素

    注意这里的返回值是一个元素数组,因为csdnid和id属性不同,是可以重复的;

    下面的代码是demo中用于解析帖子文件的方法,详细使用请看demo源码

    private  InternalTopic ParseFile(StreamReader reader){
                InternalTopic post 
    =   new  InternalTopic();
                HtmlDocument d 
    =   new  HtmlDocument();
                d.Load(reader);
                post.body
    = ((HtmlNode)d.GetElementsbyCsdnId( " topicBody " )[ 0 ]).InnerHtml;
                post.forumId 
    =   new  Guid(((HtmlNode)d.GetElementsbyCsdnId( " sectionId " )[ 0 ]).Attributes[ " content " ].Value);
                post.subject 
    =  ((HtmlNode)d.GetElementsbyCsdnId( " topicSubject " )[ 0 ]).InnerHtml;
                post.point 
    =   int .Parse(((HtmlNode)d.GetElementsbyCsdnId( " topicPoint " )[ 0 ]).InnerHtml);
                post.tags 
    =  ((HtmlNode)d.GetElementsbyCsdnId( " keywords " )[ 0 ]).Attributes[ " content " ].Value;
                post.username 
    =  ((HtmlNode)d.GetElementsbyCsdnId( " topicUsername " )[ 0 ]).InnerHtml;
                post.postDate 
    =  DateTime.Parse(((HtmlNode)d.GetElementsbyCsdnId( " topicPostDate " )[ 0 ]).InnerHtml);
                post.topicUrl 
    =  ((HtmlNode)d.GetElementsbyCsdnId( " topicViewUrl " )[ 0 ]).Attributes[ " content " ].Value;
                Guid topicId;
                DateTime postDate;
                
    if  ( ! Utility.TryParseTopicUrl(post.topicUrl,  out  postDate,  out  topicId))
                {
                    
    throw   new  ArgumentException( " 错误的帖子链接 " );
                }
                ArrayList replylist 
    =  d.GetElementsbyCsdnId( " replyId " );
                
    if  (replylist  !=   null )
                {
                    
    foreach  (HtmlNode n  in  replylist)
                    {
                        
    long  rid  =   long .Parse(n.Attributes[ " name " ].Value);
                        post.replies.Add(ParseReply(d, rid));
                    }
                }
                
    string  dataPath  =  Utility.WriteData(topicId.ToString()  +   " .xml " typeof (InternalTopic), post);
                
    return  post;
            }
            
    ///   <summary>
            
    ///  解析回复
            
    ///   </summary>
            
    ///   <param name="d"> html文件 </param>
            
    ///   <param name="rid"> 回复id </param>
            
    ///   <returns></returns>
             private  InternalReply ParseReply(HtmlDocument d, long  rid)
            {
                HtmlNode replyTable 
    =  d.GetElementsbyCsdnId( " reply_ "   +  rid.ToString())[ 0 as  HtmlNode;
                HtmlDocument replyHtml 
    =   new  HtmlDocument();
                replyHtml.LoadHtml(replyTable.OuterHtml);
                InternalReply reply 
    =   new  InternalReply();
                reply.replyId
    = rid;
                reply.username 
    =  ((HtmlNode)replyHtml.GetElementsbyCsdnId( " replyUsername " )[ 0 ]).InnerHtml;
                reply.replyDate 
    =  DateTime.Parse(((HtmlNode)replyHtml.GetElementsbyCsdnId( " replyDate " )[ 0 ]).InnerHtml);
                reply.body 
    =  ((HtmlNode)replyHtml.GetElementsbyCsdnId( " replyBody " )[ 0 ]).InnerHtml;
                reply.point 
    =   int .Parse(((HtmlNode)replyHtml.GetElementsbyCsdnId( " replyPoint " )[ 0 ]).InnerHtml);
                reply.layer 
    =   int .Parse(((HtmlNode)replyHtml.GetElementsbyCsdnId( " replyLayer " )[ 0 ]).InnerHtml);
                
    return  reply;
            }

  • 常用csdnid参考

    csdnid属性描述
    topicPostDateInnerHTML发帖时间
    topicBodyInnerHTML帖子内容
    sectionIdcontent论坛id
    isPrimeclass是否精华,为空则不是精华
    isCheckOutInnerHTML是否已结,为空则未结
    topicPointInnerHTML给分
    topicUsernameInnerHTML发帖用户
    descriptioncontent标题
    topicViewUrlcontent帖子Url
    replyIdname回复id
    replyCountInnerHTML回复数
    reply_{id}OuterHTML指定id的回复区域
    replyUsernameInnerHTML回复用户名
    replyNicknameInnerHTML回复用户昵称
    replyDateInnerHTML回复日期
    replyLayerInnerHTML回复楼层
    replyPointInnerHTML回复得分
    replyBodyInnerHTML回复内容

     

    错误ID

    错误id由四位二进制数表示,前两位为功能号,后两位为具体错误号,比如错误0301,表明为回复功能的内容为空错误

    功能号列表

    00:通用

    01:结贴

    02:发帖

    03:回复

    04:积分捐赠

    每个功能号的具体错误,将另行文档说明

  • 0
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值