怎样利用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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值