csdn论坛公开了一些常用api,不过内部测试阶段,地址是http://forum.youkuaiyun.com/OpenApi/forumapi.asmx还有一个使用的demo,http://forum.youkuaiyun.com/OpenApi/ForumOpenAPIDemo.rar,源码在这里下载demo源码
总体概述:
公开的方法如下:
- CheckOutTopic :结贴
- GetForums :获得论坛列表
- GetTopicsOfUser :获得我的帖子,我参与的帖子,我得分的帖子,别人问我的帖子
- GetUserProfile :获得用户资料
- PointDonate :积分捐赠
- Post :发帖
- Reply :回帖
至于获得帖子和获得帖子列表的方法,虽然没有提供独立的api,但是都可以借助论坛现有的资源,待会会单独讲到
上面的API除了GetForums外,都需要输入一个identity实体,表明你的身份,返回了一个bool型变量,表示操作是否完成,结果会以out变量的形式输出,同时输出的一般还有错误信息Error
identity的参考定义如下
/// 用户身份信息
/// </summary>
public struct Identity{
/// <summary>
/// 用户名
/// </summary>
public string username;
/// <summary>
/// 密码
/// </summary>
public string password;
}
他包含用于身份验证的用户名和密码,除获得论坛列表以外,其他的操作均要求此参数,调用者可以将用户信息加密存与本地,详细请参考账户管理
而错误信息的参考定义如下
/// 错误信息
/// </summary>
public struct Error
{
/// <summary>
/// 错误id
/// </summary>
public int errId;
private string _errInfo;
/// <summary>
/// 错误信息
/// </summary>
public string errInfo;
/// <summary>
/// 描述
/// </summary>
public string description;
}
这个实体存放了调用过程中返回的错误,如果返回结果为false,我们就可以查看或者错误信息:
比如下面的积分捐赠的代码段








获得论坛GetForums
GetForums 非常的简单,没有传入参数,方法的返回值是一个Forum实体数组
Forum的参考定义和具体字段含义如下
/// 论坛信息
/// </summary>
public struct Forum
{
/// <summary>
/// 论坛id
/// </summary>
public GuidforumId;
/// <summary>
/// 父论坛id
/// </summary>
public GuidparentForumId;
/// <summary>
/// 论坛名称
/// </summary>
public string name;
/// <summary>
/// 别名
/// </summary>
public string alias;
/// <summary>
/// 是否技术论坛
/// </summary>
public bool IsTech;
/// <summary>
/// 版主
/// </summary>
public string []morderators;
/// <summary>
/// 积分归属论坛
/// </summary>
public GuidpointBelongsToForumId;
}
获得用户信息GetUserProfile :
方法定义如下:
/// 获得用户信息
/// </summary>
/// <paramname="identity"> 用户身份信息 </param>
/// <paramname="profile"> 用户信息 </param>
/// <paramname="error"> 错误信息 </param>
/// <paramname="username"> 需要获得用户信息的用户名 </param>
/// <returns> 操作是否成功 </returns>
public bool GetUserProfile(Identityidentity, string username, out UserProfileprofile, out Errorerror)
此方法用于查询某用户的用户信息,包括用户昵称,可用分,用户技术专家分,非技术专家分,以及他在各个论坛的得分和级别(只展示用户在其有得分的论坛信息)
用户信息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 GuidforumId;
/// <summary>
/// 专家分
/// </summary>
public int expertPoint;
/// <summary>
/// 星级
/// </summary>
public string rank;
}
发帖Post :
发帖方法定义如下










Post结构参考定义
/// 帖子
/// </summary>
public struct Post
{
/// <summary>
/// 论坛id(发帖时必须)
/// </summary>
public GuidforumId;
/// <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 EditorTypeeditor;
/// <summary>
/// 帖子链接
/// </summary>
public string url;
}
回帖Reply :











回复实体参考定义如下
/// 回复
/// </summary>
public struct Reply
{
/// <summary>
/// 论坛id(必须)
/// </summary>
public GuidforumId;
/// <summary>
/// 帖子url(必须)
/// </summary>
public string topicUrl;
/// <summary>
/// 回复内容(必须)
/// </summary>
public string body;
/// <summary>
/// 是否需要ubb(必须)
/// </summary>
public EditorTypeeditor;
}
结帖CheckOutTopic:
/// 结贴
/// </summary>
/// <paramname="identity"> 用户身份证 </param>
/// <paramname="topicUrl"> 帖子链接 </param>
/// <paramname="forumId"> 论坛id </param>
/// <paramname="replyPoints"> 回复给分列表 </param>
/// <paramname="error"> 错误 </param>
/// <returns> 结贴是否成功 </returns>
public bool CheckOutTopic(Identityidentity, string topicUrl,GuidforumId,List < ReplyPoint > replyPoints, out Errorerror)
List<ReplyPoint> replyPoints为回复id和给分数组
/// 回帖得分
/// </summary>
public struct ReplyPoint
{
/// <summary>
/// 回复id
/// </summary>
public long replyId;
/// <summary>
/// 得分
/// </summary>
public int point;
}
积分捐赠PointDonate
/// 可用分捐赠
/// </summary>
/// <paramname="identity"> 用户身份证 </param>
/// <paramname="toUser"> 捐赠对象 </param>
/// <paramname="point"> 捐赠积分 </param>
/// <paramname="reason"> 原因 </param>
/// <paramname="error"> 错误 </param>
/// <returns> 捐赠是否成功 </returns>
public bool PointDonate(Identityidentity, string toUser, int point, string reason, out Errorerror)
获得我的帖子,我参与的帖子,我得分的帖子,别人问我的帖子 GetTopicsOfUser
/// 获得我发表的帖子,我回复过的帖子,我得分的帖子
/// </summary>
/// <paramname="listType"> 列表类型 </param>
/// <paramname="forumId"> 论坛id </param>
/// <paramname="posts"> 帖子列表 </param>
/// <paramname="error"> 错误信息 </param>
/// <paramname="identity"> 身份信息 </param>
/// <returns> 是否成功 </returns>
[WebMethod]
public bool GetTopicsOfUser(Identityidentity,UserTopicListTypelistType,GuidforumId, out List < Post > posts, out Errorerror)
列表类型定义如下
/// 用户帖子列表类型
/// </summary>
public enum UserTopicListType
{
/// <summary>
/// 用户的帖子
/// </summary>
TopicOfUser,
/// <summary>
/// 用户回复过的帖子
/// </summary>
TopicUserJoined,
/// <summary>
/// 用户得分的帖子
/// </summary>
TopicUserRewarded,
/// <summary>
/// 所有问专家
/// </summary>
AllAskExpert
}
获得帖子列表
获得帖子列表,包括
待解决 抢分区 零回复 热点区 已解决 精华区没有提供独立的Webservice,原因是这些帖子列表均提供了Rss,调用者通过Rss获得需要的信息
一个列子列表的rss链接由论坛别名和列表类型两部分组成
比如灌水乐园抢分区的Rss链接为http://forum.youkuaiyun.com/Rss/FreeZone/RobPointList/
其中黄色部分(FreeZone)为论坛别名,红色部分(RobPointList)表明列表类型为抢分区,我们可以通过如下代码简单实现取得rss并转为dataset
{
string url = " http://forum.youkuaiyun.com/Rss/FreeZone/RobPointList/ " ;
HttpWebRequestrequest = HttpWebRequest.Create(url) as HttpWebRequest;
WebResponseresponse = request.GetResponse();
DataSetresult = new DataSet();
StreamrssStream = response.GetResponseStream();
StreamReadersr = new StreamReader(rssStream,Utility.GetEncoding());
result.ReadXml(sr);
return result.Tables[ 2 ];
}
获得与解析帖子
公开的API也没专门获得帖子的方法,主要是处于性能的考虑,想要获得帖子,就直接获取帖子html文件,如果需要帖子的信息,比如发帖人,分数,就必须解析帖子文件,文件中提供了一系列标识(csdnid),让解析者可以通过其找到对应的内容,并且在所附demo中,也提供了一个经过改造的解析模块,调用者可以使用这个模块,通过csdnid来找到帖子文件中具体的内容
什么是csdnid?
打开任意一个帖子文件,里面都会看到一些由csdnid标识的元素,这些元素的属性和内容一般都具有特殊的意义,比如帖子源文件中的下面html代码


csdnid="topicViewUrl" 的meta元素的content属性,说明了帖子的url,为:http://topic.youkuaiyun.com/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源码
InternalTopicpost = new InternalTopic();
HtmlDocumentd = 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 =