- 浏览: 77483 次
- 性别:
- 来自: 上海
文章分类
最新评论
备份CSDN博客正文到本地存档
大哥有了新想法,然而没有技术,令人欣慰的是大哥想到了我,于是我便答应免费帮个忙,这是一个基于云的项目,具体细节也就不透露了,然而在实现的过程中,其中一个模块我觉得可以自用,于是我就想把这个模块抽出来,该模块的功能就是将CSDN博客上的文章下载到本地。
假期只完成了一个模板,虽然很垃圾,但是却能满足自用的需求,一直以来,我都很害怕自己喝懵了写的一些感悟放在网上会在某一天再也打不开,事实上,这种事 情确实也发生过很多次。忘记用户,文章被管理员删除,博客被封闭,网站不再维护等都会导致这样的问题,于是我就不得不定期将自己在各个网站注册的博客复制 到一个本地的文档上,包括网易的,百度的,CSDN的,51CTO的,以及老婆的QQ空间的(我总是将内容发布在老婆的QQ上,因为那上面可以畅所欲 言),这么多的网站,如此多的日志,工作量真的不少,久而久之,本地的存档也越来越乱,渐渐的,有很多文章都被遗漏了。特别是CSDN的博客,一直以来, 我都想将其完整的dump到本地,一篇一篇的复制,简直不可能,因为太多了,也找过整站下载器,但是效果不理想。趁此机会,别人委托我做的这个小玩意正好 可以用于此目的,而且比较满意的一点就是dump下来的每一篇文章都裁掉了不相关的内容,比如友情链接,博客访问量以及广告等,唯一被保留的就是正文和正 文的图片资源。
起初我是使用C++手工实现的,然而却需要自行解析HTML文档的各个标签,落实下来就是复杂的字符串解析,其实字符串解析可以堪称是编程的精髓,但是对 于实际做项目,这种工作还是直接使用现有的解析库比较好,后来我发现使用脚本语言更简单,比如使用python,perl,甚至grep/awk/sed 都可以,然而字符编码却始终是一个大问题。通过咨询一个超猛的同事,我认识了htmlparser这个java库,实在是太方便了,它将html文件元素 抽象成了各个类,这样可以很方便的实现过滤,更可贵的是,这种过滤甚至都不用自己实现,htmlparser中自带了过滤功能,你要做的只是重载一些方法 即可,这样就是使用很简单的代码实现这个博客下载功能了,下载完了之后最好将其保存成一个单独的PDF文档,虽然java也可以实现这个功能,然而目前已 经有了很多这样的工具,有现成工具的就不编程实现,这永远是一个真理。
首先看一下效果,然后看一下代码。
保存在本地的存档拥有下面的目录结构,首先是一个顶级目录,以我博客的标题来命名,内部是一个按月份存档的目录集合以及一个index.html索引文件,如下图所示:
如果你以文本编辑器或者xcode打开每一篇文章或者index.html文件,你将看到其中的大部分链接都被改成了本地的相对路径了,并且删除了大量的无关的内容,这种修改很简单,手工改其实很可以做到,使用程序来做当然更简便些,问题是当你写程序所带来的麻烦超过了手工修改的麻烦时,这种编程就很没有意义,幸运的是,htmlparser可以很简单的做到这一点,一点也不复杂,这样的话这种编程就显得很有意义了。
代码很简单,基本就是几大块:
1.几次遍历-按主页遍历月份信息,按月份存档遍历文章,按每一篇文章遍历图片;
2.解析关键信息,比如标题,文章中的图片等,并填充数据结构。这种事可以通过Filter来完成;
3.根据filter的副作用填充的信息生成目录。
那么,如果使用上面的代码备份你自己的CSDN博客呢?很简单,将dog250改成你的ID即可,我在main方法中注释了一大段的内容,你也可以将其展开,然后他就是通用的了,试试看。
假期只完成了一个模板,虽然很垃圾,但是却能满足自用的需求,一直以来,我都很害怕自己喝懵了写的一些感悟放在网上会在某一天再也打不开,事实上,这种事 情确实也发生过很多次。忘记用户,文章被管理员删除,博客被封闭,网站不再维护等都会导致这样的问题,于是我就不得不定期将自己在各个网站注册的博客复制 到一个本地的文档上,包括网易的,百度的,CSDN的,51CTO的,以及老婆的QQ空间的(我总是将内容发布在老婆的QQ上,因为那上面可以畅所欲 言),这么多的网站,如此多的日志,工作量真的不少,久而久之,本地的存档也越来越乱,渐渐的,有很多文章都被遗漏了。特别是CSDN的博客,一直以来, 我都想将其完整的dump到本地,一篇一篇的复制,简直不可能,因为太多了,也找过整站下载器,但是效果不理想。趁此机会,别人委托我做的这个小玩意正好 可以用于此目的,而且比较满意的一点就是dump下来的每一篇文章都裁掉了不相关的内容,比如友情链接,博客访问量以及广告等,唯一被保留的就是正文和正 文的图片资源。
起初我是使用C++手工实现的,然而却需要自行解析HTML文档的各个标签,落实下来就是复杂的字符串解析,其实字符串解析可以堪称是编程的精髓,但是对 于实际做项目,这种工作还是直接使用现有的解析库比较好,后来我发现使用脚本语言更简单,比如使用python,perl,甚至grep/awk/sed 都可以,然而字符编码却始终是一个大问题。通过咨询一个超猛的同事,我认识了htmlparser这个java库,实在是太方便了,它将html文件元素 抽象成了各个类,这样可以很方便的实现过滤,更可贵的是,这种过滤甚至都不用自己实现,htmlparser中自带了过滤功能,你要做的只是重载一些方法 即可,这样就是使用很简单的代码实现这个博客下载功能了,下载完了之后最好将其保存成一个单独的PDF文档,虽然java也可以实现这个功能,然而目前已 经有了很多这样的工具,有现成工具的就不编程实现,这永远是一个真理。
首先看一下效果,然后看一下代码。
保存在本地的存档拥有下面的目录结构,首先是一个顶级目录,以我博客的标题来命名,内部是一个按月份存档的目录集合以及一个index.html索引文件,如下图所示:
展开一个月份存档目录,你将看到本月的文章集合,每一篇文章包含一个目录,如下图所示:
随意打开一篇文章,你将看到该篇文章的标题以及正文,所有的图片也被包含,链接到了该文章的_files目录中的对应图片,如下图:
index.html呈现处以下的样子:
如果你以文本编辑器或者xcode打开每一篇文章或者index.html文件,你将看到其中的大部分链接都被改成了本地的相对路径了,并且删除了大量的无关的内容,这种修改很简单,手工改其实很可以做到,使用程序来做当然更简便些,问题是当你写程序所带来的麻烦超过了手工修改的麻烦时,这种编程就很没有意义,幸运的是,htmlparser可以很简单的做到这一点,一点也不复杂,这样的话这种编程就显得很有意义了。
代码很简单,基本就是几大块:
1.几次遍历-按主页遍历月份信息,按月份存档遍历文章,按每一篇文章遍历图片;
2.解析关键信息,比如标题,文章中的图片等,并填充数据结构。这种事可以通过Filter来完成;
3.根据filter的副作用填充的信息生成目录。
需要说明的是,以下的代码完全是过程化的,没有使用Java语言的OO特性,因此它的数据以及方法完全是static的,没有生成任何对象,我只是想使用htmlparser的API以及java语言IDE的诸多良好的功能,比如方法以及方法参数的自动补全功能,老手或者科班高年级学生可能会较真地说,C/C++的IDE也可以支持这样的功能,如果碰到这样反驳的,我也可以说,其实嘛,汇编语言也是可以自动补全的…另外,代码中有很多的硬编码,其实应该将它们再抽象一下的,或者说定义成变量也可以,只是因为自用,以后也不准备维护,就这么着了。还有,那就是最大的问题,代码有一些bug,比如对于标题中含有奇怪字符的支持,以及错误日志(这很重要)的记录的缺失等等。不管怎么说,代码如下:
- <spanstyle="font-family:KaiTi_GB2312;font-size:18px;">importorg.htmlparser.Node;
- importorg.htmlparser.NodeFilter;
- importorg.htmlparser.Parser;
- importorg.htmlparser.filters.TagNameFilter;
- importorg.htmlparser.util.NodeList;
- importorg.htmlparser.tags.*;
- importjava.io.*;
- importjava.net.*;
- importjava.nio.*;
- importjava.util.List;
- importjavax.management.*;
- /*类名使用test很不规范,然而为了方面胡乱起的名字,可是不管怎么说,它确实是个test*/
- publicclasstest{
- /*月份文章的月份名称/月份存档URL对的列表*/
- finalstaticAttributeListindexList=newAttributeList();
- /*每月文章名称/每月文章的URL对的列表*/
- finalstaticAttributeListarticleList=newAttributeList();
- /*每篇文章图片本地存档地址/每篇文章图片URL对的列表*/
- finalstaticAttributeListresourceList=newAttributeList();
- /*保存月份以及该月文章本地存档的列表,用于生成目录*/
- staticAttributeListmonthList=newAttributeList();
- /*用于生成本地存档目录的writer*/
- staticOutputStreamWriterindex_handle=null;
- staticStringproxy_addr=null;
- staticintproxy_port=3128;
- /*
- *@paramurl网页的URL
- *@paramtype类型:1为文本,0为二进制
- *@return内容的字节数组
- */
- publicstaticbyte[]GetContent(Stringurl,inttype){
- byteret[]=null;
- try{
- HttpURLConnectionconn=null;
- InputStreamurlStream=null;;
- URLsurl=newURL(url);
- intj=-1;
- if(proxy_addr!=null){
- InetSocketAddresssoA=newInetSocketAddress(InetAddress.getByName(proxy_addr),proxy_port);
- Proxyproxy=newProxy(Proxy.Type.HTTP,soA);
- conn=(HttpURLConnection)surl.openConnection(proxy);
- }else{
- conn=(HttpURLConnection)surl.openConnection();
- }
- /*必须加上这一句伪装成Mozilla浏览器,否则CSDN会拒绝连接*/
- conn.setRequestProperty("User-Agent","Mozilla/4.0");
- conn.connect();
- urlStream=conn.getInputStream();
- if(type==1){
- StringsTotalString="";
- BufferedReaderreader=newBufferedReader(newInputStreamReader(urlStream,"UTF-8"));
- CharBuffervv=CharBuffer.allocate(1024);
- while((j=reader.read(vv.array()))!=-1){
- sTotalString+=newString(vv.array(),0,j);
- vv.clear();
- }
- sTotalString=sTotalString.replace('\n','');
- sTotalString=sTotalString.replace('\r','');
- ret=sTotalString.getBytes();
- }else{
- ByteBuffervv=ByteBuffer.allocate(1024);
- /*CSDN允许最大图片有上限*/
- ByteBufferbuffer=ByteBuffer.allocate(5000000);
- while((j=urlStream.read(vv.array()))!=-1){
- buffer.put(vv.array(),0,j);
- vv.clear();
- }
- ret=buffer.array();
- }
- }catch(Exceptione){
- e.printStackTrace();
- //追加出错日志
- }
- returnret;
- }
- /*
- *@parampath文件路径
- *@paramcontent文件内容的字节数组
- *@return成功或者失败
- */
- publicstaticbooleanWriteFile(Stringpath,byte[]content){
- try{
- FileOutputStreamosw=newFileOutputStream(path);
- osw.write(content);
- osw.close();
- }catch(Exceptione){
- e.printStackTrace();
- //追加出错日志
- returnfalse;
- }
- returntrue;
- }
- /*
- *@parampath目录路径
- *@return成功或者失败
- */
- publicstaticbooleanMKDir(Stringpath){
- try{
- Filefp=newFile(path);
- if(!fp.exists()){
- fp.mkdir();
- }
- }catch(Exceptione){
- e.printStackTrace();
- //追加出错日志
- returnfalse;
- }
- returntrue;
- }
- /*
- *@parampath文件路径
- *@paramurl文章在blog上的URL
- *@paramarticles保存本月存档的列表
- *@return无
- */
- publicstaticvoidHandleHtml(Stringpath,Stringurl,AttributeListarticles){
- try{
- StringBuffertext=newStringBuffer();
- NodeListnodes=HandleText(newString(GetContent(url,1)),3);
- Nodenode=nodes.elementAt(0);
- Stringtitle=(String)((List<Attribute>)resourceList.asList()).get(0).getValue();
- Stringfilepath=path+"/"+title;
- List<Attribute>li=resourceList.asList();
- /*加入meta信息*/
- text.append(newString("<metahttp-equiv=\"Content-Type\"content=\"text/html;chaset=utf-8\"/>"));
- text.append("<h1>"+title+"</h1>");
- if(node!=null){
- Divdv=(Div)node;
- text.append(newString(dv.toHtml().getBytes("UTF-8"),"UTF-8"));
- }else{
- text.append("<h3>Downloaderror</h3>");
- }
- test.MKDir(filepath+"_files");
- articles.add(newAttribute(filepath.split("/",2)[1],title));
- for(inti=1;i<li.size();i++){
- byte[]imgString=GetContent((String)li.get(i).getValue(),0);
- test.WriteFile(filepath+"_files/"+li.get(i).getName()+".gif",imgString);
- }
- resourceList.clear();
- test.WriteFile(filepath+".html",text.toString().getBytes());
- }catch(Exceptione){
- //追加出错日志
- e.printStackTrace();
- }
- }
- /*
- *@paramnlistHTML正文的子标签链表
- *@paramindex用于索引图片的个数以及当前的图片数
- *@return当前的图片数
- */
- publicstaticintparseImg(NodeListnlist,intindex){
- Nodeimg=null;
- intcount=nlist.size();
- for(inti=0;i<count;i++){
- img=nlist.elementAt(i);
- if(imginstanceofImageTag){
- ImageTagimgtag=(ImageTag)img;
- if(!imgtag.isEndTag()){
- Stringtitle=(String)((List<Attribute>)resourceList.asList()).get(0).getValue();
- /*将图片的URL映射成本地路径*/
- resourceList.add(newAttribute(""+index,newString(imgtag.extractImageLocn().getBytes())));
- title=title.trim();
- imgtag.setImageURL(title+"_files/"+index+".gif");
- /*递增本地路径序列*/
- index++;
- }
- }else{
- NodeListslist=img.getChildren();
- if(slist!=null&&slist.size()>0){
- index=test.parseImg(slist,index);
- }
- }
- }
- returnindex;
- }
- /*
- *@paramnlistHTML月份存档的子标签链表
- *@paramindex无用
- *@return无用
- */
- publicstaticintparseMonthArticle(NodeListnlist,intindex){
- Nodeatls=null;
- intcount=nlist.size();
- for(inti=0;i<count;i++){
- atls=nlist.elementAt(i);
- if(atlsinstanceofLinkTag){
- LinkTaglink=(LinkTag)atls;
- indexList.add(newAttribute(link.getLinkText(),link.extractLink()));
- }else{
- NodeListslist=atls.getChildren();
- if(slist!=null&&slist.size()>0){
- index=test.parseMonthArticle(slist,index);
- }
- }
- }
- returnindex;
- }
- /*
- *@paramnlistHTML标题的子标签链表
- *@paramindex无用
- *@return无用
- */
- publicstaticintparseTitle(NodeListnlist,intindex){
- Nodetit=null;
- intcount=nlist.size();
- for(inti=0;i<count;i++){
- tit=nlist.elementAt(i);
- if(titinstanceofSpan){
- Spanspan=(Span)tit;
- if(span.getAttribute("class")!=null&&span.getAttribute("class").equalsIgnoreCase("link_title")){
- LinkTaglink=(LinkTag)span.childAt(0);
- Stringtitle=link.getLinkText();
- /*将文件名中不允许的字符替换成允许的字符*/
- title=title.replace('/','-');
- title=title.trim();
- title=title.replace('','-');
- resourceList.add(newAttribute("title",title));
- }
- }else{
- NodeListslist=tit.getChildren();
- if(slist!=null&&slist.size()>0){
- index=test.parseTitle(slist,index);
- }
- }
- }
- returnindex;
- }
- /*
- *@paramnlistHTML每月份存档的子标签链表
- *@paramindex无用
- *@return无用
- */
- publicstaticintparsePerArticle(NodeListnlist,intindex){
- Nodeatl=null;
- intcount=nlist.size();
- for(inti=0;i<count;i++){
- atl=nlist.elementAt(i);
- if(atlinstanceofSpan){
- Spanspan=(Span)atl;
- if(span.getAttribute("class")!=null&&span.getAttribute("class").equalsIgnoreCase("link_title")){
- LinkTaglink=(LinkTag)span.childAt(0);
- articleList.add(newAttribute(link.getLinkText(),"http://blog.csdn.net"+link.extractLink()));
- }
- }else{
- NodeListslist=atl.getChildren();
- if(slist!=null&&slist.size()>0){
- index=test.parsePerArticle(slist,index);
- }
- }
- }
- returnindex;
- }
- /*
- *@paramnlistHTML分页显示标签的子标签链表
- *@paramindex无用
- *@return无用
- */
- publicstaticintparsePage(NodeListnlist,intindex){
- Nodepg=null;
- intcount=nlist.size();
- for(inti=0;i<count;i++){
- pg=nlist.elementAt(i);
- if(pginstanceofLinkTag){
- LinkTaglt=(LinkTag)pg;
- if(lt.getLinkText().equalsIgnoreCase("下一页")){
- try{
- test.HandleText(newString(test.GetContent("http://blog.csdn.net"+lt.extractLink(),1)),2);
- }catch(Exceptione){
- //追加出错日志
- }
- }
- }
- }
- returnindex;
- }
- /*
- *@paramnlistHTML作者信息标签的子标签链表
- *@paramindex无用
- *@return无用
- */
- publicstaticintparseAuthor(NodeListnlist,intindex){
- Nodeaut=null;
- intcount=nlist.size();
- for(inti=0;i<count;i++){
- aut=nlist.elementAt(i);
- if(autinstanceofLinkTag){
- LinkTaglink=(LinkTag)aut;
- resourceList.add(newAttribute("author",link.getLinkText()));
- }else{
- NodeListslist=aut.getChildren();
- if(slist!=null&&slist.size()>0){
- index=test.parseAuthor(slist,index);
- }
- }
- }
- returnindex;
- }
- /*
- *@paraminput输入的html文档字符串
- *@paramskip是否执行的类别
- *@return匹配的链表,很多类别通过副作用而起作用
- */
- publicstaticNodeListHandleText(Stringinput,finalintskip)throwsException{
- Parserparser=Parser.createParser(input,"UTF-8");
- NodeListnodes=parser.extractAllNodesThatMatch(newNodeFilter(){
- publicbooleanaccept(Nodenode){
- if(nodeinstanceofDiv){
- Divdv=(Div)node;
- NodeListnlist=dv.getChildren();
- if(dv.getAttribute("id")!=null&&nlist!=null){
- if(dv.getAttribute("id").equalsIgnoreCase("article_content")&&skip==3){
- parseImg(nlist,0);
- returntrue;
- }elseif(dv.getAttribute("id").equalsIgnoreCase("article_details")&&skip==3){
- parseTitle(nlist,0);
- }elseif(dv.getAttribute("id").equalsIgnoreCase("archive_list")&&(skip==1||skip==4)){
- parseMonthArticle(nlist,0);
- }elseif(dv.getAttribute("id").equalsIgnoreCase("papelist")&&skip==2){
- parsePage(nlist,0);
- }elseif(dv.getAttribute("id").equalsIgnoreCase("blog_title")&&skip==4){
- parseAuthor(nlist,0);
- }
- }
- if(dv.getAttribute("class")!=null&&nlist!=null){
- if(dv.getAttribute("class").equalsIgnoreCase("article_title")&&skip==2){
- parsePerArticle(nlist,0);
- }
- }
- }
- returnfalse;
- }
- });
- returnnodes;
- }
- /*
- *@paramfilepath本地存档的路径
- *@paramurl保存本月存档的网页的URL
- *@paramarticles保存本月存档的链表
- *@return无
- */
- publicstaticvoidparseMonth(Stringfilepath,Stringurl,AttributeListarticles){
- List<Attribute>li=articleList.asList();
- try{
- HandleText(newString(GetContent(url,1)),2);
- }catch(Exceptione){
- //追加出错日志
- }
- test.MKDir(filepath);
- for(inti=0;i<li.size();i++){
- HandleHtml(filepath,(String)li.get(i).getValue(),articles);
- try{
- /*慢一点,否则会被认为是恶意行为*/
- Thread.sleep(500);
- }catch(Exceptione){}
- }
- articleList.clear();
- }
- /*
- *@paramurlblog入口文章的URL
- *@return无
- */
- publicstaticvoidparseAll(Stringurl){
- try{
- Stringauthor=null;
- HandleText(newString(GetContent(url,1)),4);
- author=(String)((List<Attribute>)resourceList.asList()).get(0).getValue();
- resourceList.clear();
- test.MKDir(author);
- List<Attribute>li=indexList.asList();
- for(inti=0;i<li.size();i++){
- AttributeListarticles=newAttributeList();
- monthList.add(newAttribute(li.get(i).getName(),articles));
- parseMonth(author+"/"+li.get(i).getName(),(String)li.get(i).getValue(),articles);
- }
- HandleIndex(author);
- }catch(Exceptione){
- e.printStackTrace();
- }
- indexList.clear();
- }
- /*
- *@paramdir本地存档根路径名称
- *@return无
- */
- staticvoidHandleIndex(Stringdir){
- try{
- index_handle=newOutputStreamWriter(newFileOutputStream(dir+"/index.html"),"GB18030");
- Stringheader="<html><head><metahttp-equiv=\"Content-Type\"content=\"text/html;charset=utf-8\"><title>CSDN文章归档</title></head><bodybgcolor=\"white\"text=\"black\"link=\"#0000FF\"vlink=\"#840084\"alink=\"#0000FF\"><hr></div><div><h1class=\"title\"><aname=\"id2747881\"></a>"+dir+"CSDN文章归档</h1></div></div><hr></div><divclass=\"toc\"><p><b>目录</b></p><dl><dt><spanclass=\"preface\"><ahref=\"preface.html\">摘要</a></span></dt>";
- Stringtailer="</div></div><hr></body></html>";
- index_handle.write(header);
- List<Attribute>li=monthList.asList();
- for(inti=0;i<li.size();i++){
- Stringmindex="<dt><spanclass=\"part\"><h4>"+li.get(i).getName()+"</span></dt><dd><dl>";
- AttributeListarticles=(AttributeList)li.get(i).getValue();
- List<Attribute>al=articles.asList();
- index_handle.write(mindex);
- for(intj=0;j<al.size();j++){
- Stringper="<dt><spanclass=\"part\"><ahref=\""+al.get(j).getName()+".html\">"+al.get(j).getValue()+"</a></span></dt>";
- index_handle.write(per);
- }
- index_handle.write("</dl></dd>");
- }
- index_handle.write(tailer);
- index_handle.close();
- }catch(Exceptione){}
- }
- /*
- *@paramargsargs[0]:blog入口文章的URLargs[1]:代理地址args[2]:代理端口【用法:javaDownBloghttp://blog.csdn.net/dog250192.168.40.199808】
- *@return无
- */
- publicstaticvoidmain(String[]args)throwsException{
- parseAll("http://blog.csdn.net/dog250");
- /*booleanvalid=false;
- if(args.length==1){
- valid=true;
- }elseif(args.length==2){
- proxy_addr=args[1];
- valid=true;
- }elseif(args.length==3){
- proxy_addr=args[1];
- proxy_port=Integer.parseInt(args[2]);
- valid=true;
- }
- if(valid){
- parseAll(args[0]);
- }else{
- }*/
- }
- }</span>
那么,如果使用上面的代码备份你自己的CSDN博客呢?很简单,将dog250改成你的ID即可,我在main方法中注释了一大段的内容,你也可以将其展开,然后他就是通用的了,试试看。
相关推荐
标题中的“备份CSDN到本地”指的是将CSDN(China Software Developer Network,中国软件开发者网络)上的个人博客或文章数据保存到自己的计算机上,以防数据丢失或方便离线查看。CSDN是一个广大的开发者社区,用户...
【Csdn博客备份工具】是一款专为CSDN(China Software Developer Network)博主设计的实用工具,旨在帮助用户方便地备份自己的博客文章。这款工具能够将你在CSDn上发表的所有文章、评论以及相关资源下载到本地,以...
自己用Java开发的一款CSDN文章备份工具,已转换为exe格式(但仍需要电脑有JRE),可用于备份CSDN文章。 备份完成后的文章是HTML格式,会按照专栏分类,建议每篇文章只设置一个专栏。 使用非常简单,压缩包里有使用...
为了方便管理和备份自己的博客,CSDN提供了一款由C#编写的博客导出工具,该工具能将博客内容导出为MarkDown格式的文档,极大地简化了内容迁移和本地存储的过程。 Markdown是一种轻量级的标记语言,以其简洁易读的...
CSDN 专用 博客备份 工具2.0.0 备份文件为GB2312 编码
CSDN博客导出工具是一款专门针对CSDN平台的实用软件,它的主要功能是帮助用户将个人在CSDN上发表的博客文章批量导出为Markdown或PDF格式。这样的工具对于博主而言非常有价值,因为它提供了备份和整理博客内容的便捷...
CSDN博客备份工具2.0.1 CSDN博客备份工具2.0.1 CSDN博客备份工具2.0.1 CSDN博客备份工具2.0.1 CSDN博客备份工具2.0.1
博客备份是指将博客中的文章、评论、图片等数据复制并保存到另一个安全的位置,以防原平台出现数据丢失或无法访问的情况。对于CSDN用户而言,他们的博客内容可能包含大量的技术文章、项目经验,甚至是职业生涯的记录...
CSDN博客下载器通过解析网页源代码,提取出这些信息,并将它们以合适的格式存储到本地,以便用户在无网络连接的情况下也能访问。 **核心功能** 1. **输入用户名获取博客列表**:用户只需提供CSDN的用户名,下载器...
csdn博客阶段总结存档 各类资源的储备
python版CSDN博客备份工具-更新 解决置顶报错问题
当然如果您发现CSDN博客的一些文章值得收藏,你也可以使用本软件轻松的下载到您的电脑。 该版本新增功能: 1.更新了blogspider的LOGO。 2.添加了很多菜单的图标。 3.增加设置选项窗口,设置背景音乐,PDF页面大小与...
这篇文章主要介绍了一个使用Java和SpringBoot框架开发的程序,该程序能够帮助用户批量将CSDN上的个人文章保存到本地。下面将详细讲解这个程序的工作原理、涉及的技术点以及使用方法。 1. **SpringBoot框架**:...
在CSDN、百度等写博客文章的应该很多,很多时候担心服务器有一天突然挂了,或者担心自己的号被封了,所写的那么多文章就那样子没了。或者出于保持别人博客文章的目的等等,想要把博客文章备份下来,甚至是导出电子书...
CSDN博客导出工具2.0是一款专为CSDN博主精心设计的实用软件,它旨在帮助用户方便快捷地将自己在CSDN平台上发表的博客文章导出到本地计算机上,以实现内容备份、离线阅读或进一步编辑等目的。这款工具的特点在于其...
在CSDN博客导出工具中选择CHM格式,可以将博客内容整合成一本电子书,便于离线查看,同时也可以通过内置的搜索功能快速定位到所需内容,非常适合于个人知识库的构建和整理。 其次,PDF(Portable Document Format)...
CSDN博客导出
对于经常在CSDN上发布博客的开发者来说,这是一款非常实用的工具,能够帮助他们备份、整理或迁移自己的博客内容。 C#(读作“C Sharp”)是微软公司推出的一种面向对象的、运行于.NET Framework之上的高级程序设计...
【CSDN Blog 备份工具】是一款专为CSDN博客用户设计的实用工具,旨在帮助用户将他们的在线博客内容安全地备份到本地计算机上。这个工具的主要目的是确保用户的数据安全,防止因网络问题、平台故障或其他不可预见的...
【标题】:“抓取CSDN博客文章的简单爬虫python源码” 在这个主题中,我们将探讨如何使用Python编写一个简单的爬虫程序来抓取CSDN博客的文章内容。CSDN(Chinese Software Developer Network)是中国的一个大型...