zoukankan      html  css  js  c++  java
  • python实战--csdn博客专栏下载器

       打算利用业余时间好好研究Python的web框架--web.py,深入剖析其实现原理,体会web.py精巧之美。但在研究源码的基础上至少得会用web.py。思前想后,没有好的Idea,于是打算开发一个csdn博客专栏下载器,界面不是很好看,还过得去吧。

    效果图如下:



    为了简单,下载以html格式保存。

    下载我自己的博客专栏,目录列表


    主界面html文件非常简单,如下:

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>CSDN 博客专栏下载器</title>
    <link rel="stylesheet" type="text/css" href="/static/main.css"/>
    <script type="text/javascript" src="static/main.js"></script>
    </head>
    
    <body>
    <input type="text" class="name" name="csdnname" id="csdnid"/><br/>
    <button type="button" class="btn" onclick="category()">获取专栏</button>
    <div id="categorylist">
    </div>
    <div id="download">
    </div>
    <div id="status">
    </div>
    <div id="footer">
    </div>
    </body>
    </html>
    


    获取后端数据使用Ajax,没有用封装好的库,所以看起来很简洁。

    function ajax(requesturl,handler){
    	var xmlhttp;
    	if (window.XMLHttpRequest){
      		xmlhttp=new XMLHttpRequest();
      	}
    	else{
      		xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
      	}
      	xmlhttp.onreadystatechange=function(){
      		if (xmlhttp.readyState==4 && xmlhttp.status==200){
        		handler(xmlhttp.responseText);
        	}
      	}
    	xmlhttp.open("GET",requesturl,true);
    	xmlhttp.send();
    }
    
    function category(){
    	var name=document.getElementById('csdnid').value;
    	document.getElementById('categorylist').innerHTML=""
    	if (name==""){
    		alert("用户名不可以为空");
    	}
    	else{
    		ajax('category'+'?name='+name,function(content){
    					document.getElementById('categorylist').innerHTML=content;
    				   });
    	}
    }
    
    function down(){
    	var box=document.getElementsByName('check');
    	var atag=new Array();
    	for (var i=0; i<box.length; i++) {
    		if(box[i].checked){
    			atag.push(box[i].value);
    		}
    	}
    	var astring=atag.join('*');
    	ajax('down'+'?urls='+astring,function(content){
    					if(content!=""){
    						document.getElementById('download').innerHTML=content;
    					}
    					else{
    						document.getElementById('download').innerHTML="正在下载";
    					}
    				   });
    }
    
    


     ajax函数,一个参数是请求url,另一个是请求成功回调函数。在函数里创建一个XMLHttpRequest对象,发送请求给url,并调用回调函数。

     category函数,主要是获取csdn用户ID,并发送给ajax请求获取专栏信息,成功后显示。

     down函数,获取选中的复选框,将选中专栏url拼接后发送ajax请求。


    主文件,如下

    #coding=utf-8
    import web
    import os
    import urllib2
    import cookielib
    import re
    import threading
    import thread
    import sys
    
    reload(sys)
    sys.setdefaultencoding('utf8')
    
    urls = (
        '/','index',
        '/category(.*)','category',
        '/down','down'
    
           )
    render = web.template.render('templates/')
    
    #所有用到的正则表达式
    contentMatch={
        'category':re.compile(r"<div id="panel_Category"(.*?)博(.*?)>(.*?)</div>", re.I|re.DOTALL), #专栏显示
        'zlalink':re.compile(r"a(s*)href(s*)=("|')(.*?)(3)(.*?)>(.*?)</a>",re.I|re.DOTALL),   #各个专栏url
        'blogalink': re.compile(r"<a(s*)name(.*?)href(s*)=("|')(.*?)(4)",re.I|re.DOTALL),  #博客链接url
        'lastpagenum': re.compile(r"<a(s*)href=(.*?)?page=(d)">尾页",re.I|re.DOTALL),    #尾页链接
        'title':re.compile(r"<title>(.*?)</title>",re.I|re.DOTALL)
        }
    
    class Http:
        """
           由于CSDN做了特殊处理,如果使用简单的httplib2.Http().request()会抓取不到数据,所以我们需要模拟真实用户行为,
        """
        def __init__(self):
            cookie_support= urllib2.HTTPCookieProcessor(cookielib.CookieJar())
            self.opener = urllib2.build_opener(cookie_support,urllib2.HTTPHandler)
            #urllib2.install_opener(opener)
            self.opener.addheaders = [("User-agent","Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.11"),("Accept","*/*"),("Referer","http://www.google.com")]
    
        def open(self,url):
            return self.opener.open(url)
    
    class index:
        """
        首页
        """
        def GET(self):
            return render.index()
    
    class category:
        """
        获取专栏信息,并显示相应的复选框
        """
        def GET(self,name):
            name=web.input(name=None).name
            url = "http://blog.csdn.net/"+name
            try:
                opener=Http()
                res=opener.open(url)
                content = res.read()
                category_match=contentMatch['category'].search(content)
                if category_match:
                    left=category_match.group()
                    right=""
                    list_match=contentMatch['zlalink'].findall(left)
                    for i in range(len(list_match)):
                        if i%2 == 1:
                            right+="""
                            <input type="checkbox" name="check" value="%s" /> %s<br />
                            """ % (list_match[i][3],list_match[i][6])
                    submit="""<button type="button" class="btn" onclick="down()">下载专栏</button>"""
                    return left+right+submit
                else:
                    return "该用户没有开通专栏"
            except Exception:
                return "请检查网络和用户名"
    
    class createfile(threading.Thread):
        """
        下载专栏中文章的线程类
        """
        def __init__(self,zlurl):
            threading.Thread.__init__(self)
            self.blogurl=[]
            self.opener=Http()
            self.zlname=""
            try:
                res=self.opener.open(zlurl)
                content = res.read()
                zlname_match=contentMatch['title'].search(content)
                if zlname_match:
                    self.zlname="".join(zlname_match.group(1).split('-')[:-2]).decode('utf8')
                    if not os.path.exists(self.zlname):
                        os.mkdir(self.zlname)
                else:
                    thread.exit_thread()
                if content.find("尾页") < 0:
                    self.addblog(content)
                else:
                    page_match=contentMatch['lastpagenum'].search(content)
                    page=int(page_match.group(3))
                    for x in range(1,page+1):
                        url="%s?page=%d" %(zlurl,x)  #分页处理
                        content=self.opener.open(url).read()
                        self.addblog(content)
    
            except Exception,e:
                print 'init:'+str(e)
                thread.exit_thread()
    
        def addblog(self,content): #获取文章url
            try:
                blogs_match=contentMatch['blogalink'].findall(content)
                if blogs_match:
                    for m in blogs_match:
                        if m[4] not in self.blogurl:
                            self.blogurl.append(m[4])
            except Exception,e:
                print "addblog:"+str(e)
    
        def write(self,content): #写入文件
            try:
                if content !="":
                    blogtitle="".join(contentMatch['title'].search(content).group(1).split('-')[:-3])
                    #path="%s%s%s.html" %(self.zlname.encode('utf8'),os.sep,blogtitle)
                    path="%s.html" % blogtitle
                    f = open(path.decode('utf8'),"w")
                    f.write(content.decode('utf8'))
                    f.close()
            except Exception,e:
                print "write:"+str(e)
    
        def run(self):
            try:
                print len(self.blogurl)
                for blog in self.blogurl:
                    self.write(self.opener.open(blog).read())
            except Exception,e:
                print "run:"+str(e)
    
    
    
    class down:
        def GET(self):
            urls=web.input().urls
            urllist=urls.split('*')
            for url in urllist:
                file=createfile(url)
                file.start()
                file.join()
            #等待线程结束,结束后返回下载完成
            return "下载完成"
    
    if __name__=='__main__':
        app = web.application(urls,globals())
        app.run()


       使用了多线程,博主有几个专栏,将启动几个线程,主程序等待线程结束。

        在这里也遇到了一个问题,本身是每个专栏一个文件夹,但处理时有点问题,拼接path后open时总是报没有这个文件或文件夹,应该是编码的问题。

    留个遗憾,等待各位亲的指教。



  • 相关阅读:
    【面积并】 Atlantis
    【动态前k大 贪心】 Gone Fishing
    【复杂枚举】 library
    【双端队列bfs 网格图建图】拯救大兵瑞恩
    【奇偶传递关系 边带权】 奇偶游戏
    【权值并查集】 supermarket
    CF w4d3 A. Pythagorean Theorem II
    CF w4d2 C. Purification
    CF w4d2 B. Road Construction
    CF w4d2 A. Cakeminator
  • 原文地址:https://www.cnblogs.com/xinyuyuanm/p/3212333.html
Copyright © 2011-2022 走看看