博客导出工具(C++实现,支持sina,csdn,自定义列表)


操作系统: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页面源代码,实现如下:


  1. bool CBlogExportDlg::GetUrlStr(CString strUrl, CString& UrlData)  
  2. {  
  3.     CInternetSession session;  
  4.     CHttpFile *file = NULL;  
  5.     try{  
  6.         file = (CHttpFile*)session.OpenURL(strUrl);  
  7.     }  
  8.     catch (CInternetException *m_pException){  
  9.         file = NULL;  
  10.         m_pException->m_dwError;  
  11.         m_pException->Delete();  
  12.         session.Close();  
  13.         ShowMes("网络连接错误...");  
  14.         return false;  
  15.     }  
  16.   
  17.     if (!file){  
  18.         ShowMes(strUrl + "获取失败...");  
  19.         return false;  
  20.     }  
  21.   
  22.     CString sRecived;  
  23.     while (file->ReadString(sRecived) != NULL) {  
  24.         UrlData += sRecived + "\n";  
  25.     }  
  26.     session.Close();  
  27.     file->Close();  
  28.     delete file;   
  29.     file = NULL;  
  30.     return true;  
  31. }  


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


  1. int CBlogExportDlg::ConvUtf8ToAnsi(CString& strSource, CString& strChAnsi)  
  2. {  
  3.     if (strSource.GetLength() <= 0)  
  4.         return 0;  
  5.   
  6.     CString strWChUnicode;  
  7.   
  8.     strSource.TrimLeft();  
  9.     strSource.TrimRight();  
  10.     strChAnsi.Empty();  
  11.   
  12.     int iLenByWChNeed = MultiByteToWideChar(CP_UTF8, 0,  
  13.         strSource.GetBuffer(0),  
  14.         strSource.GetLength(), //MultiByteToWideChar  
  15.         NULL, 0);  
  16.   
  17.     int iLenByWchDone = MultiByteToWideChar(CP_UTF8, 0,  
  18.         strSource.GetBuffer(0),  
  19.         strSource.GetLength(),  
  20.         (LPWSTR)strWChUnicode.GetBuffer(iLenByWChNeed * 2),  
  21.         iLenByWChNeed); //MultiByteToWideChar  
  22.   
  23.     strWChUnicode.ReleaseBuffer(iLenByWchDone * 2);  
  24.   
  25.     int iLenByChNeed = WideCharToMultiByte(CP_ACP, 0,  
  26.         (LPCWSTR)strWChUnicode.GetBuffer(0),  
  27.         iLenByWchDone,  
  28.         NULL, 0,  
  29.         NULL, NULL);  
  30.   
  31.     int iLenByChDone = WideCharToMultiByte(CP_ACP, 0,  
  32.         (LPCWSTR)strWChUnicode.GetBuffer(0),  
  33.         iLenByWchDone,  
  34.         strChAnsi.GetBuffer(iLenByChNeed),  
  35.         iLenByChNeed,  
  36.         NULL, NULL);  
  37.   
  38.     strChAnsi.ReleaseBuffer(iLenByChDone);  
  39.   
  40.     if (iLenByWChNeed != iLenByWchDone || iLenByChNeed != iLenByChDone)  
  41.         return 1;  
  42.   
  43.     return 0;  
  44. }  


3. 消息文本框显示


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


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


  1. void CBlogExportDlg::OnBnClickedButtonOk()  
  2. {  
  3.     GetDlgItemText(IDC_EDIT_ADDRESS, blogAdr);  
  4.     ShowBlogAdr();  
  5.     //blogAdr = ("http://blog.csdn.net/yxstars/");  
  6.     int pos = blogAdr.Find("http://blog.csdn.net/");  
  7.     if (pos == -1){  
  8.         ShowMes("csdn blog地址不对...");  
  9.     }  
  10.     blogAdrs = blogAdr;  
  11.   
  12.     CString urlData;  
  13.     if (!GetUrlStr(blogAdr, urlData)){  
  14.         return;  
  15.     }  
  16.   
  17.     CFile fs;  
  18.     if (!fs.Open(strDirPath + "temp", CFile::modeCreate | CFile::modeWrite)){  
  19.         return;  
  20.     }  
  21.   
  22.     fs.Write(urlData, urlData.GetLength());  
  23.     fs.Close();  
  24.   
  25.     CString ansiUrlData;  
  26.     ConvUtf8ToAnsi(urlData, ansiUrlData);  
  27.     GetBlogInfo(ansiUrlData);  
  28.   
  29. }  


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


[html]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. <!--显示分页 -->  
  2.   
  3. <div id="papelist" class="pagelist">  
  4. <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>   
  5. </div>  

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

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

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


C++代码实现如下:

  1. void CBlogExportDlg::GetBlogInfo(CString& urlData)  
  2. {  
  3.     int pos = urlData.Find("<div id=\"papelist\" class=\"pagelist\">");  
  4.     if (pos == -1){  
  5.         ShowMes("获取列表数目失败...");  
  6.         return;  
  7.     }  
  8.     urlData = urlData.Mid(pos + 44);  
  9.     pos = urlData.Find("条数据");  
  10.     if (pos == -1){  
  11.         ShowMes("获取列表条数失败...");  
  12.         return;  
  13.     }  
  14.   
  15.     CString blogListNum = urlData.Left(pos);  
  16.       
  17.     pos = urlData.Find("条数据  共");  
  18.     int poss = urlData.Find("页</span>");  
  19.     if ((poss == -1) || (pos == -1)){  
  20.         ShowMes("获取列表页数失败...");  
  21.         return;  
  22.     }  
  23.   
  24.     CString listPage = urlData.Mid(pos + 10, poss - pos - 10);  
  25.     blogListPage = StrToInt(listPage);  
  26.     ShowMes("博文" + blogListNum + "篇");  
  27. }  


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

  1. void CBlogExportDlg::OnBnClickedButtonList()  
  2. {  
  3.     clearMes();  
  4.     CString urlData, ansiUrlData, listPage;  
  5.     //http://blog.csdn.net/yxstars/article/list/1  
  6.     FileListMap.clear();  
  7.     listNum = 1;  
  8.   
  9.     for (int i = 1; i < blogListPage + 1; i++){  
  10.         urlData.Empty();  
  11.         ansiUrlData.Empty();  
  12.         listPage.Format("%d", i);  
  13.         blogAdr = blogAdrs + "/article/list/" + listPage;  
  14.         ShowBlogAdr();  
  15.         if (!GetUrlStr(blogAdr, urlData)){  
  16.             return;  
  17.         }  
  18.   
  19.         ConvUtf8ToAnsi(urlData, ansiUrlData);  
  20.         GetFileList(ansiUrlData);  
  21.     }  
  22.   
  23. }  


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

[html]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. <h1>  
  2.     <span class="link_title"><a href="/yxstars/article/details/38469431">  
  3.     <font color="red">[置顶]</font>  
  4.     金融系列12《双币电子现金方案》  
  5.     </a></span>  
  6. </h1>  

从上面源码可以看出:

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

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

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


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

  1. void CBlogExportDlg::GetFileList(CString& urlData)  
  2. {     
  3.     CString strListNum;  
  4.     int posF = urlData.Find("<span class=\"link_title\">");  
  5.     while (posF != -1){  
  6.         urlData = urlData.Mid(posF + 34);  
  7.         int posE = urlData.Find("\"");  
  8.         if (posE == -1){  
  9.             ShowMes("获取列表失败...");  
  10.             return;  
  11.         }  
  12.   
  13.         CString href = urlData.Left(posE);  
  14.         posF = urlData.Find("</a>");  
  15.         if (posF == -1){  
  16.             ShowMes("获取列表失败...");  
  17.             return;  
  18.         }  
  19.   
  20.         CString title = urlData.Mid(posE+2, posF-posE-2);  
  21.         posF = title.ReverseFind('>');  
  22.         if (posF != -1){  
  23.             title = title.Mid(posF + 1);  
  24.         }  
  25.         title.Trim("\n").Trim();  
  26.         href = "http://blog.csdn.net" + href;  
  27.         FileListMap[title] = href;  
  28.         strListNum.Format("%03d", listNum++);  
  29.         strListNum = (strListNum + ":" + title + "                                            ").Left(45);  
  30.         ShowMes(strListNum + href);  
  31.         posF = urlData.Find("<span class=\"link_title\">");  
  32.     }  
  33. }  


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

  1. void CBlogExportDlg::OnBnClickedButtonExport()  
  2. {  
  3.     clearMes();  
  4.     unsigned tid;  
  5.     unsigned long thd = _beginthreadex(NULL, 0, CBlogExportDlg::WriteCycle, this, 0, &tid);  
  6.     if (thd != NULL)  
  7.     {  
  8.         CloseHandle((HANDLE)thd);  
  9.     }  
  10.   
  11. }  
  12.   
  13. unsigned __stdcall  CBlogExportDlg::WriteCycle(void* p)  
  14. {  
  15.     CBlogExportDlg* dlg = (CBlogExportDlg*)p;  
  16.     CString blogFolderPath = dlg->strDirPath + "Blog\\";  
  17.     if (!PathIsDirectory(blogFolderPath))  
  18.     {  
  19.         if (!CreateDirectory(blogFolderPath, NULL))  
  20.         {  
  21.             dlg->ShowMes(blogFolderPath + "创建失败...");  
  22.             return 1;  
  23.         }  
  24.     }  
  25.       
  26.   
  27.     dlg->stopRun = false;  
  28.     CString urlData, strList;  
  29.     int iList = 1;  
  30.     CFile cf;  
  31.     std::map<CString, CString>::iterator iter;  
  32.     for (iter = dlg->FileListMap.begin(); iter != dlg->FileListMap.end(); iter++){  
  33.         //dlg->blogAdr = iter->second;  
  34.         //dlg->ShowBlogAdr();  
  35.         urlData.Empty();  
  36.         if (!dlg->GetUrlStr(iter->second, urlData)){  
  37.             return 1;  
  38.         }  
  39.         strList.Format("%3d", iList++);  
  40.         dlg->ShowMes("正在导出第" + strList + "篇博文:" + iter->first);  
  41.         CString blogPath(iter->first);  
  42.         blogPath.Replace('\\', '_');  
  43.         blogPath.Replace('/''_');  
  44.         blogPath = blogFolderPath + blogPath + ".html";  
  45.         if (!cf.Open(blogPath, CFile::modeCreate | CFile::modeWrite)){  
  46.             dlg->ShowMes("创建文件失败" + blogPath);  
  47.             return 2;  
  48.         }  
  49.         cf.Write(urlData, urlData.GetLength());  
  50.         cf.Close();  
  51.   
  52.         if (dlg->stopRun){  
  53.             return 1;  
  54.         }  
  55.   
  56.     }  
  57.     return 0;  
  58. }  


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

  1. void CBlogExportDlg::OnBnClickedButtonRead()  
  2. {  
  3.     clearMes();  
  4.     unsigned tid;  
  5.     unsigned long thd = _beginthreadex(NULL, 0, CBlogExportDlg::ReadCycle, this, 0, &tid);  
  6.     if (thd != NULL)  
  7.     {  
  8.         CloseHandle((HANDLE)thd);  
  9.     }  
  10. }  
  11.   
  12.   
  13. unsigned __stdcall  CBlogExportDlg::ReadCycle(void* p)  
  14. {  
  15.     CBlogExportDlg* dlg = (CBlogExportDlg*)p;  
  16.     dlg->stopRun = false;  
  17.     std::map<CString, CString>::iterator iter;  
  18.     for (iter = dlg->FileListMap.begin(); iter != dlg->FileListMap.end(); iter++){  
  19.         dlg->blogAdr = iter->second;  
  20.         dlg->ShowBlogAdr();  
  21.         dlg->ShowMes("正在遍历博文:" + iter->first);  
  22.         Sleep(3000);  
  23.         if (dlg->stopRun){  
  24.             return 1;  
  25.         }  
  26.   
  27.   
  28.     }  
  29.     return 0;  
  30. }  


CSDN免积分下载地址:

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

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


这个显示网页到MFC对话框中要用到 ActiveX 控件了,向对话框里面插入一个 WebBrowser控件,之后使用就可以了!
=============================
利用WebBrowser控件创建自己的浏览器
①新建一个基于对话框的工程,命名为test,然后在对话框上单击右键,选择
Insert ActiveX Control…在弹出的对话框中选择MicroSoft Web浏览器,点击OK。
此时对话框上已经出现了WebBrowser控件,调整它的大小以适合对话框的大小。

②选择WebBrowser控件,点击View/ClassWizard,选择Member Variables,单击
Add Variable按钮,此时会弹出两个对话框,均点击确定即可。然后给该控件加
入一个变量,我们把它命名为m_ctrlWeb。

③在ClassWizard中选择OnInitDialog()函数,在里面加入如下代码:

m_ctrlWeb.Navigate("http://www.baidu.com", NULL, NULL, NULL, NULL);

第一个参数即你要浏览的URL地址,可以是一个文件,也可以是一个地址
(如:http://www.baidu.com)

而如果想要禁止在新窗口打开,则需要添加控件事件处理函数NewWindow3()添加如下函数

[cpp]  view plain copy
  1. void C网页Dlg::NewWindow3Explorer1(LPDISPATCH* ppDisp, BOOL* Cancel, unsigned long dwFlags, LPCTSTR bstrUrlContext, LPCTSTR bstrUrl)  
  2. {  
  3.     // TODO: 在此处添加消息处理程序代码  
  4.     * Cancel = TRUE;  
  5.     VARIANT vInfo;  
  6.     m_webBrowser.Navigate(<span style="color: rgb(51, 102, 153); font-family: Monaco, Consolas, 'Lucida Console', 'Courier New', serif; line-height: 21.600000381469727px; ">bstrUrl</span>, &vInfo, &vInfo, &vInfo, &vInfo);  
  7. }  
如在新窗口中打开链接和在新标签中打开链接是两个不同的事件(NewWindow2,NewWindow3)


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






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值