操作系统:windowAll

编程工具:visual studio 2013

编程语言:VC++

最近博文更新的较频繁,为了防止账号异常引起csdn博文丢失,所以花了点时间做了个小工具来导出博文,用做备份。本文将从源码分析整个实现过程。先看个截图:

操作步骤:

  1. 先在博客地址文本框输入博客地址例如:http://blog.csdn.net/yxstars/,http://blog.sina.com.cn/yxstars/,

    http://www.cnblogs.com/yxstars/
  2. 然后点击确定,将显示共有多少篇博文,例如:[19:32:47]博文113篇
  3. 点击文章列表:将显示所有博文,格式:title,href
  4. 点击导出博文:将导出博文,在当前目录下的blog文件夹中。博文格式为html。
  5. 遍历博文:将遍历所有博文并且显示出来。
  6. 刷新:刷新所有博文,不显示。
  7. 图片:导出的博文,图片下载到本地,博文图片链接到本地。
  8. 列表:支持自定义的列表链接博文(当前目录下有个list.ini,可以自定义链接)。
  9. 刷新次数:自定义,循环次数。
  10. 时间间隔:每次循环sleep时间。

源码分析:

1. 获取对应的url页面源代码,实现如下:

bool CBlogExportDlg::GetUrlStr(CString strUrl, CString& UrlData)
{
CInternetSession session;
CHttpFile *file = NULL;
try{
file = (CHttpFile*)session.OpenURL(strUrl);
}
catch (CInternetException *m_pException){
file = NULL;
m_pException->m_dwError;
m_pException->Delete();
session.Close();
ShowMes("网络连接错误...");
return false;
} if (!file){
ShowMes(strUrl + "获取失败...");
return false;
} CString sRecived;
while (file->ReadString(sRecived) != NULL) {
UrlData += sRecived + "\n";
}
session.Close();
file->Close();
delete file;
file = NULL;
return true;
}

2. 获取的html源码为utf8格式,需要转为ansi格式,C++实现代码如下:

int CBlogExportDlg::ConvUtf8ToAnsi(CString& strSource, CString& strChAnsi)
{
if (strSource.GetLength() <= 0)
return 0; CString strWChUnicode; strSource.TrimLeft();
strSource.TrimRight();
strChAnsi.Empty(); int iLenByWChNeed = MultiByteToWideChar(CP_UTF8, 0,
strSource.GetBuffer(0),
strSource.GetLength(), //MultiByteToWideChar
NULL, 0); int iLenByWchDone = MultiByteToWideChar(CP_UTF8, 0,
strSource.GetBuffer(0),
strSource.GetLength(),
(LPWSTR)strWChUnicode.GetBuffer(iLenByWChNeed * 2),
iLenByWChNeed); //MultiByteToWideChar strWChUnicode.ReleaseBuffer(iLenByWchDone * 2); int iLenByChNeed = WideCharToMultiByte(CP_ACP, 0,
(LPCWSTR)strWChUnicode.GetBuffer(0),
iLenByWchDone,
NULL, 0,
NULL, NULL); int iLenByChDone = WideCharToMultiByte(CP_ACP, 0,
(LPCWSTR)strWChUnicode.GetBuffer(0),
iLenByWchDone,
strChAnsi.GetBuffer(iLenByChNeed),
iLenByChNeed,
NULL, NULL); strChAnsi.ReleaseBuffer(iLenByChDone); if (iLenByWChNeed != iLenByWchDone || iLenByChNeed != iLenByChDone)
return 1; return 0;
}

3. 消息文本框显示

void CBlogExportDlg::ShowMes(CString mes)
{
CTime time;
time = CTime::GetCurrentTime();//Get the current time
CString Times = _T("[") + time.Format("%H:%M:%S") + "]";//Conversion time format int len = MesEdit.GetWindowTextLength();
MesEdit.SetSel(len, len);
MesEdit.ReplaceSel(Times + mes + _T("\r\n"));
}

4. 点击确定按钮后,实现代码

void CBlogExportDlg::OnBnClickedButtonOk()
{
GetDlgItemText(IDC_EDIT_ADDRESS, blogAdr);
ShowBlogAdr();
//blogAdr = ("http://blog.csdn.net/yxstars/");
int pos = blogAdr.Find("http://blog.csdn.net/");
if (pos == -1){
ShowMes("csdn blog地址不对...");
}
blogAdrs = blogAdr; CString urlData;
if (!GetUrlStr(blogAdr, urlData)){
return;
} CFile fs;
if (!fs.Open(strDirPath + "temp", CFile::modeCreate | CFile::modeWrite)){
return;
} fs.Write(urlData, urlData.GetLength());
fs.Close(); CString ansiUrlData;
ConvUtf8ToAnsi(urlData, ansiUrlData);
GetBlogInfo(ansiUrlData); }

5. 根据博客地址,获取源代码后分析,查找博文数目,和博文列表页数。

<!--显示分页 -->

<div id="papelist" class="pagelist">
<span> 113条数据 共6页</span><strong>1</strong> <a href="/yxstars/article/list/2">2</a> <a href="/yxstars/article/list/3">3</a> <a href="/yxstars/article/list/4">4</a> <a href="/yxstars/article/list/5">5</a> <a href="/yxstars/article/list/6">...</a> <a href="/yxstars/article/list/2">下一页</a> <a href="/yxstars/article/list/6">尾页</a>
</div>

从上面的代码中可以获取信息如下:

<span> 113条数据  共6页</span>, 共有113篇博文,共有6页。

<a href="/yxstars/article/list/3">,页面链接地址为/yxstars/article/list/
+ 要显示的页数。

C++代码实现如下:

void CBlogExportDlg::GetBlogInfo(CString& urlData)
{
int pos = urlData.Find("<div id=\"papelist\" class=\"pagelist\">");
if (pos == -1){
ShowMes("获取列表数目失败...");
return;
}
urlData = urlData.Mid(pos + 44);
pos = urlData.Find("条数据");
if (pos == -1){
ShowMes("获取列表条数失败...");
return;
} CString blogListNum = urlData.Left(pos); pos = urlData.Find("条数据 共");
int poss = urlData.Find("页</span>");
if ((poss == -1) || (pos == -1)){
ShowMes("获取列表页数失败...");
return;
} CString listPage = urlData.Mid(pos + 10, poss - pos - 10);
blogListPage = StrToInt(listPage);
ShowMes("博文" + blogListNum + "篇");
}

6. 当点击显示列表时,根据之前的页面地址获取信息。

void CBlogExportDlg::OnBnClickedButtonList()
{
clearMes();
CString urlData, ansiUrlData, listPage;
//http://blog.csdn.net/yxstars/article/list/1
FileListMap.clear();
listNum = 1; for (int i = 1; i < blogListPage + 1; i++){
urlData.Empty();
ansiUrlData.Empty();
listPage.Format("%d", i);
blogAdr = blogAdrs + "/article/list/" + listPage;
ShowBlogAdr();
if (!GetUrlStr(blogAdr, urlData)){
return;
} ConvUtf8ToAnsi(urlData, ansiUrlData);
GetFileList(ansiUrlData);
} }

7. 在每个页面获取文章列表和页面地址。

    <h1>
<span class="link_title"><a href="/yxstars/article/details/38469431">
<font color="red">[置顶]</font>
金融系列12《双币电子现金方案》
</a></span>
</h1>

从上面源码可以看出:

<span class="link_title">后面就是博文链接地址。

</a>前面的就是博文标题。

如果有置顶操作,会多出这部分<font color="red">[置顶]</font>

C++获取源码实现如下:

void CBlogExportDlg::GetFileList(CString& urlData)
{
CString strListNum;
int posF = urlData.Find("<span class=\"link_title\">");
while (posF != -1){
urlData = urlData.Mid(posF + 34);
int posE = urlData.Find("\"");
if (posE == -1){
ShowMes("获取列表失败...");
return;
} CString href = urlData.Left(posE);
posF = urlData.Find("</a>");
if (posF == -1){
ShowMes("获取列表失败...");
return;
} CString title = urlData.Mid(posE+2, posF-posE-2);
posF = title.ReverseFind('>');
if (posF != -1){
title = title.Mid(posF + 1);
}
title.Trim("\n").Trim();
href = "http://blog.csdn.net" + href;
FileListMap[title] = href;
strListNum.Format("%03d", listNum++);
strListNum = (strListNum + ":" + title + " ").Left(45);
ShowMes(strListNum + href);
posF = urlData.Find("<span class=\"link_title\">");
}
}

8. 当点击导出博文时,我们只需把源代码保存为html格式即可,采用多线程实现:

void CBlogExportDlg::OnBnClickedButtonExport()
{
clearMes();
unsigned tid;
unsigned long thd = _beginthreadex(NULL, 0, CBlogExportDlg::WriteCycle, this, 0, &tid);
if (thd != NULL)
{
CloseHandle((HANDLE)thd);
} } unsigned __stdcall CBlogExportDlg::WriteCycle(void* p)
{
CBlogExportDlg* dlg = (CBlogExportDlg*)p;
CString blogFolderPath = dlg->strDirPath + "Blog\\";
if (!PathIsDirectory(blogFolderPath))
{
if (!CreateDirectory(blogFolderPath, NULL))
{
dlg->ShowMes(blogFolderPath + "创建失败...");
return 1;
}
} dlg->stopRun = false;
CString urlData, strList;
int iList = 1;
CFile cf;
std::map<CString, CString>::iterator iter;
for (iter = dlg->FileListMap.begin(); iter != dlg->FileListMap.end(); iter++){
//dlg->blogAdr = iter->second;
//dlg->ShowBlogAdr();
urlData.Empty();
if (!dlg->GetUrlStr(iter->second, urlData)){
return 1;
}
strList.Format("%3d", iList++);
dlg->ShowMes("正在导出第" + strList + "篇博文:" + iter->first);
CString blogPath(iter->first);
blogPath.Replace('\\', '_');
blogPath.Replace('/', '_');
blogPath = blogFolderPath + blogPath + ".html";
if (!cf.Open(blogPath, CFile::modeCreate | CFile::modeWrite)){
dlg->ShowMes("创建文件失败" + blogPath);
return 2;
}
cf.Write(urlData, urlData.GetLength());
cf.Close(); if (dlg->stopRun){
return 1;
} }
return 0;
}

9. 遍历博文时,只需依次访问之前保存的链接即可,实现如下:

void CBlogExportDlg::OnBnClickedButtonRead()
{
clearMes();
unsigned tid;
unsigned long thd = _beginthreadex(NULL, 0, CBlogExportDlg::ReadCycle, this, 0, &tid);
if (thd != NULL)
{
CloseHandle((HANDLE)thd);
}
} unsigned __stdcall CBlogExportDlg::ReadCycle(void* p)
{
CBlogExportDlg* dlg = (CBlogExportDlg*)p;
dlg->stopRun = false;
std::map<CString, CString>::iterator iter;
for (iter = dlg->FileListMap.begin(); iter != dlg->FileListMap.end(); iter++){
dlg->blogAdr = iter->second;
dlg->ShowBlogAdr();
dlg->ShowMes("正在遍历博文:" + iter->first);
Sleep(3000);
if (dlg->stopRun){
return 1;
} }
return 0;
}

CSDN免积分下载地址:

2014.08.01更新: http://download.csdn.net/detail/yxstars/7786309

2014.09.05更新:http://download.csdn.net/detail/yxstars/7867583

文/yanxin8原创,获取更多信息请访问http://yanxin8.com/222.html

博客导出工具(C++实现,支持sina,csdn,自定义列表)的更多相关文章

  1. 用Python编写博客导出工具

    用Python编写博客导出工具 罗朝辉 (http://kesalin.github.io/) CC 许可,转载请注明出处   写在前面的话 我在 github 上用 octopress 搭建了个人博 ...

  2. CSDN博客导出工具 Mac By Swift

    写这篇文章的主要目的是了解Swift语言本身,如何以及Objc和第三方交互框架 必须先用CSDN帐户登录.您可以导出所有的博客文章,加入YAML当首标信息,包括对应标签和分类在头制品信息,和底座式(原 ...

  3. BlogPublishTool - 博客发布工具

    BlogPublishTool - 博客发布工具 这是一个发布博客的工具.本博客使用本工具发布. 本工具源码已上传至github:https://github.com/ChildishChange/B ...

  4. 多平台博客发布工具OpenWrite的使用

    1 介绍 OpenWrite官网 OpenWrite是一款便捷的多平台博客发布工具,可以在OpenWrite编写markdown文档,然后发布到其他博客平台,目前已经支持CSDN.SegmentFau ...

  5. Mac端博客发布工具推荐

    引子 推荐一款好用的 Mac 端博客发布工具. 下载地址 echo 博客对接 这里以cnblog为例.接入类型为metawebblog,access point可以在cnblog的设置最下边找到,然后 ...

  6. Golang拼接字符串的5种方法及其效率_Chrispink-CSDN博客_golang 字符串拼接效率 https://blog.csdn.net/m0_37422289/article/details/103362740

    Different ways to concatenate two strings in Golang - GeeksforGeeks https://www.geeksforgeeks.org/di ...

  7. MetaWeblog博客客户端工具之Windows Live Writer

    吐槽&注意的坑: 刚听说了有这么一个东西,据说Windows Live Writer开源之后就改名为Open Live Writer,我以为Open Live Writer就要比Windows ...

  8. 【转】如何使用离线博客发布工具发布CSDN的博客文章

    目前大部分的博客作者在用Word写博客这件事情上都会遇到以下3个痛点: 1.所有博客平台关闭了文档发布接口,用户无法使用Word,Windows Live Writer等工具来发布博客.使用Word写 ...

  9. 将Medium中的博客导出成markdown

    Medium(https://medium.com)(需要翻墙访问)是国外非常知名的一个博客平台.上面经常有很多知名的技术大牛在上面发布博客,现在一般国内的搬运的技术文章大多数都是来自于这个平台. M ...

随机推荐

  1. Appnium移动自动化框架初探

    作者:cryanimal QQ:164166060 本文简要介绍了appnium自动化框架的架构.加载流程.支持语言.相关配置,以及元素定位工具等. 官方网站: http://appium.io Ap ...

  2. Wordpress SEO对策(译)

    原文link http://netaone.com/wp/wordpress-seo-plugin/ 统一管理SEO对策的设定能够统一管理SEO相关设定的插件:All in One SEO Pack. ...

  3. Flex4 DataGrid实现可复制单元格,同时解决自定义GridItemRenderer出现1009错误的方法

    原创内容,如需转载,请注明出处,谢谢 最近在项目中发现Flex的DataGrid不支持内容复制,在涉及到保护敏感数据时倒是很有用处,但大部分情况下,我们还是希望客户能够直接复制DataGrid单元格中 ...

  4. 慕课网-安卓工程师初养成-2-1 Java中的关键字

    来源:http://www.imooc.com/code/1176 Java 中常用关键字: 问:这么多,记不住啊......-_-|| 答:现在不需要你记住所有,混个眼熟即可,在学习的过程中,你会逐 ...

  5. JS判断手机浏览器

    <script type="text/javascript"> /* * 智能机浏览器版本信息: * */ varbrowser={ versions:function ...

  6. 简单几步优化技巧令你的Windows7系统加速

    就算有再高的硬件配置,系统用久了还是会变慢,xp如此,win7同样是如此.其实系统用的如何完全在于个人使用习惯,只要掌握了以下三种方法,就可以让你的win7运行速度大大提升. 1.修改启动项程序 在你 ...

  7. iOS iOS7 20px 处理

    - (void)viewWillAppear:(BOOL)animated { // View defaults to full size. If you want to customize the ...

  8. javascript计算两个时间差

    其实,javascript计算时间差的方式非常简单,如果是默认的Date()类型,直接相减就是相差的毫秒数. var d1 = new Date('2016/03/28 10:17:22'); var ...

  9. LiveView 0.8 RC1 could boot evidence files acquired from Win10 64bit

    The latest Windows 10 will be more and more popular in the very near future. Now let's take a look i ...

  10. 一步一步学习SignalR进行实时通信_1_简单介绍

    一步一步学习SignalR进行实时通信\_1_简单介绍 SignalR 一步一步学习SignalR进行实时通信_1_简单介绍 前言 SignalR介绍 支持的平台 相关说明 OWIN 结束语 参考文献 ...