操作系统: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. EndNote文献管理

    一直想写个博客,但是一直没有好好坐下来对自己工作进行一个梳理.从今天开始吧,争取多写一点. 今天,先介绍一下科技论文写作中经常使用的一款软件EndNote,这个软件,掌握它的使用方法后会觉得很方便:但 ...

  2. [Golang]Go Packages

    ---------------------------------------------------------------------------------------------------- ...

  3. sendmessage和postmessage的区别

    BOOL   PostMessage(          HWND   hWnd,             //   handle   of   destination   window        ...

  4. 【考试】简单的sql语句

    )显示正好为5个字符的员工的姓名 HR@ORA11GR2>select last_name,first_name from employees ; )显示不带有"R"的员工的 ...

  5. FindResource函数错误代码:1813-找不到映像文件中指定的资源类型 与LoadResource函数错误代码:1812-指定的映像文件不包含资源区域

    HRSRC WINAPI FindResource( _In_opt_  HMODULE hModule, _In_      LPCTSTR lpName, _In_      LPCTSTR lp ...

  6. 关键字 new 的作用

    ①做运算符 用于创建对象和调用构造函数,小栗子a如下: Class1 obj = new Class1(); 创建匿名类型的实例,小栗子b如下: var query = from cust in cu ...

  7. Leetcode028. Implement strStr()

    class Solution { public: int strStr(string haystack, string needle) { ; //needle empty ; //haystack ...

  8. iOS常用插件

    iOS常用插件总结:http://blog.csdn.net/oik_ios/article/details/50251191http://www.jianshu.com/p/d24eea8b405a ...

  9. WP8_ListBox的用法

    在Windows Phone 7 Tips (5) 中曾经提到,在Windows Phone 7 中页面的布局一般分为:Panoramic.Pivot.List和Full Screen.而通常List ...

  10. RAW格式

    一.什么是RAW文件?RAW文件主要是一种记录了数码相机传感器的原始信息,同时伴随着一些由相机所产生的一些元数据(metadata,诸如IS0的设置.快门速度.光圈值.白平衡等)的文件.不同的相机制造 ...