打算利用业余时间好好研究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时总是报没有这个文件或文件夹,应该是编码的问题。

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

python实战--csdn博客专栏下载器的更多相关文章

  1. Python采集CSDN博客排行榜数据

    文章目录 前言 网络爬虫 搜索引擎 爬虫应用 谨防违法 爬虫实战 网页分析 编写代码 运行效果 反爬技术 前言 很多人学习python,不知道从何学起.很多人学习python,掌握了基本语法过后,不知 ...

  2. Python 实用爬虫-04-使用 BeautifulSoup 去水印下载 CSDN 博客图片

    Python 实用爬虫-04-使用 BeautifulSoup 去水印下载 CSDN 博客图片 其实没太大用,就是方便一些,因为现在各个平台之间的图片都不能共享,比如说在 CSDN 不能用简书的图片, ...

  3. Python爬取CSDN博客文章

    0 url :http://blog.csdn.net/youyou1543724847/article/details/52818339Redis一点基础的东西目录 1.基础底层数据结构 2.win ...

  4. Python 爬取CSDN博客频道

    初次接触python,写的很简单,开发工具PyCharm,python 3.4很方便 python 部分模块安装时需要其他的附属模块之类的,可以先 pip install wheel 然后可以直接下载 ...

  5. python环境变量配置 - CSDN博客

    一.下载: 1.官网下载python3.0系列(https://www.python.org/) 2.下载后图标为: 二.安装: Window下: 1.安装路径: 默认安装路径:C:\python35 ...

  6. Python爬虫小实践:爬取任意CSDN博客所有文章的文字内容(或可改写为保存其他的元素),间接增加博客访问量

    Python并不是我的主业,当初学Python主要是为了学爬虫,以为自己觉得能够从网上爬东西是一件非常神奇又是一件非常有用的事情,因为我们可以获取一些方面的数据或者其他的东西,反正各有用处. 这两天闲 ...

  7. 在CSDN开通博客专栏后如何发布文章(图文)

    今天打开电脑登上CSDN发现自己授予了专栏勋章,有必要了解如何在专栏发布文章. 很感谢已经有前辈给出了图文教程,此文章转载自博客:http://blog.csdn.net/upi2u/article/ ...

  8. mongodb丢失数据的原因剖析 - 迎风飘来的专栏 - CSDN博客 https://blog.csdn.net/yibing548/article/details/50844310

    mongodb丢失数据的原因剖析 - 迎风飘来的专栏 - CSDN博客 https://blog.csdn.net/yibing548/article/details/50844310

  9. Docker安装elasticsearch-head监控ES步骤 - gmijie的专栏 - CSDN博客

    原文:Docker安装elasticsearch-head监控ES步骤 - gmijie的专栏 - CSDN博客 Docker安装elasticsearch-head监控ES步骤 docker拉取镜像 ...

随机推荐

  1. Java 企业级 JavaEE

    授权协议:CDDL 开发语言:Java 操作系统:跨平台 开发厂商:Oracle 原文:https://www.oschina.net/p/j2ee Java EE 详细介绍 这是SUN公司推出的J2 ...

  2. 【gearman】学习笔记

    学习资料:http://gearman.org/manual/ 1.Gearman是跨语言的,client和worker可以用不同的语言来实现 2.client与job server之间的交互称为ta ...

  3. 升级 php composer 版本

    在执行 composer update 时,报错 You made a reference to a non-existent script @php artisan package:discover ...

  4. Splay-Tree总结一:模拟队列

    伸展树是一种强大的数据结构,由于其特性,可以很好地模拟队列的插队等操作,而线段树解决这类问题通常需要转化一下,比较伤脑筋 而用伸展树的解决方法就是先建好一颗节点数等于队列长度的树,每个队列元素在队列中 ...

  5. Fiddler抓包8-打断点(bpu)

    前言 先给大家讲一则小故事,在我们很小的时候是没有手机的,那时候跟女神聊天都靠小纸条.某屌丝A男对隔壁小王的隔壁女神C倾慕已久,于是天天小纸条骚扰,无奈中间隔着一个小王,这样小王就负责传小纸条了.有一 ...

  6. hdu 5256 最少修改多少个数 能使原数列严格递增 (LIS)

    Problem Description我们有一个数列A1,A2...An,你现在要求修改数量最少的元素,使得这个数列严格递增.其中无论是修改前还是修改后,每个元素都必须是整数. 请输出最少需要修改多少 ...

  7. POJ 2010 Moo University - Financial Aid (优先队列)

    题意:从C头奶牛中招收N(奇数)头.它们分别得分score_i,需要资助学费aid_i.希望新生所需资助不超过F,同时得分中位数最高.求此中位数. 思路: 先将奶牛排序,考虑每个奶牛作为中位数时,比它 ...

  8. 【AtCoder】Tenka1 Programmer Contest

    C - 4/N 列出个方程枚举解一下 #include <bits/stdc++.h> #define fi first #define se second #define pii pai ...

  9. 外部函数/external

    定义在moodle/lib/externallib.php 概观 外部函数API允许您创建可由外部程序(如Web服务API)访问的完全参数化的方法. 外部函数位于externallib.php文件中. ...

  10. HDU 1542 矩形面积并【离散化+线段树+扫描线】

    <题目链接> 题目大意: 给你n个矩形,求出它们面积的并. 解题分析: 此题主要用到了扫描线的思想,现将各个矩形的横坐标离散化,然后用它们离散化后的横坐标(相当于将矩形的每条竖线投影在x轴 ...