Your SlideShare is downloading. ×
浮云脱水小说站的搭建
浮云脱水小说站的搭建
浮云脱水小说站的搭建
浮云脱水小说站的搭建
浮云脱水小说站的搭建
浮云脱水小说站的搭建
浮云脱水小说站的搭建
浮云脱水小说站的搭建
浮云脱水小说站的搭建
浮云脱水小说站的搭建
浮云脱水小说站的搭建
浮云脱水小说站的搭建
浮云脱水小说站的搭建
浮云脱水小说站的搭建
浮云脱水小说站的搭建
浮云脱水小说站的搭建
浮云脱水小说站的搭建
浮云脱水小说站的搭建
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

浮云脱水小说站的搭建

2,644

Published on

Published in: Technology
0 Comments
7 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
2,644
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
45
Comments
0
Likes
7
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. 《浮云脱水小说站》的搭建
    http://www.zhikanlz.com
    Python、BeautifulSoup、web.py、 twisted、nginx
    Author: piglei2007@gmail.com
  • 2. 起因
    一个寂寞的周末,作者手贱点开了这个“直播贴”
    翻了十页以后发现贴吧直播贴完全是个 坑爹 的存在…
    偷懒的程序员,做点什么吧!
  • 3. 想要的结果
    最初的想法:
    我需要一个脚本来替我完成抓取帖子中所有楼主的发言,并把它们存成一个静态页面来供阅读
    我需要:
    一个解析页面的工具(BeautifulSoup )
    http://www.crummy.com/software/BeautifulSoup/
  • 4. Code
    import urllib
    import urlparse
    from BeautifulSoup import BeautifulSoup
    class BaiduZhibo(object):
    """
    可迭代的对象,不停返回下一页含有给定username的内容(默认为楼主)
    返回格式:
    字典:{
    "url": "..." #当前链接地址
    "page": 5 #当前页数
    "content": [...] #列表,里面有当前页每一个指定username的发言内容
    }
    参数:
    url: 帖子地址
  • 5. Code
    obj_name: 需要抓取的用户昵称,默认为楼主
    limit: 限定抓取页面的数量,默认无限制
    html: 设定输出格式,True不做处理,False替换换行符、空格
    """
    def __init__(self, url, obj_name=None, limit=0, html=False):
    … …
    def next(self):
    if (self.limit and self.counter == self.limit) or (self.nowurl is None):
    print "finished."
    raise StopIteration
    … …
    def __iter__(self):
    return self
    … …
    if __name__ == ‘__main__’:
    # 初始化一个BaiduZhibo对象,然后拼装html页面
  • 6. Thinking
    效果页面
    虽然已经初步达到了效果,能不能把这个东西升级成一个站点呢。
    初步想法:
    管理员(我)可以通过后台来添加帖子的原始url、分类、作者等信息。
    另外用一个cron来负责根据后台添加的信息抓取生成html页面
    项目到此分为两个:
    nowater:
    负责被cron调用,从数据库查询出小说资源进行抓取工作
    nowater_web:
    负责前端web的展示,提供添加小说资源的后台
  • 7. 准备工作
    Web框架的选择:
    特点:
    数据库结构简单(最初设计只有寥寥几张表)
    业务逻辑简单(展示)
    web.py (http://webpy.org/)
    足够简洁
    换个新鲜的
    模板引擎(mako)
    数据库(postgresql)
  • 8. 表结构设计
    CREATE TABLE "nowater_novel" (
    "id" serial NOT NULL PRIMARY KEY,
    "title" varchar(100) NOT NULL,
    "author" varchar(20) NOT NULL,
    "content_type" integer NULL, --小说类型
    "type" varchar(10) NOT NULL default 'baidu', --来源类型
    “url” varchar(200) NOT NULL unique, --来源url
    “update_interval” integer default 10, --更新间隔
    "email" varchar(40) NULL, --推荐人email,如果有的话
    “last_update_floor” integer NOT NULL default 0, --最后更新的楼层
    “last_update_url” varchar(500) NOT NULL, --最后更新的url
    “last_update_time” timestamp with time zone, --最后更新时间
    "ip" varchar(20) NOT NULL default '',
    "status" integer NOT NULL default 0,
    "jointime" timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP
    );
    NOVEL_STATUS = {
    0: u"未初始化",
    1: u"更新中...",
    2: u"等待更新",
    3: u"已完结",
    4: u"更新异常",
    100: u"已删除"
    }
  • 9. 项目结构
    [database]
    novels
    view_count
    page_info
    … …
    获得小说url等信息
    添加novel小说源信息
    #hash
    ff/
    #novel id
    373/
    1.html
    2.html
    … …
    [nowater]
    main.py
    basedb.py
    baidu_crawler.py
    writer.py
    novels/
    … …
    [nowater_web]
    web.py
    包含两个app
    Novel:浏览脱水小说的前台
    Admin:一个添加修改小说源的管理后台
    封装一些简单的对数据库的操作
    处理对baidu贴吧帖子的抓取逻辑
    接收格式通用的数据,写入html文件,需要处理分页
    提供抓取完成的html静态文件
    5min – main.py
    Crontab
  • 10. 问题和解决
    多线程抓取
    Threading模块
    Queue模块
    抓取内容的分页
    建立page_info表(字段:page、word_count)
    在writer.py中集中处理写入逻辑(是否应该分页,分页参数的设置)
    支持其他社区
    baidu_crawler.py,封装页面处理逻辑,格式化内容输出
    由于对输出格式的统一,后期可方便添加tianya_crawler.py … …
    图片反盗链的处理
    在**_crawler.py里面对盗链图片url进行预处理
    使用nginx的反向代理
    CREATE TABLE "page_info" (
    "id" integer NOT NULL PRIMARY KEY,
    "page" integer NOT NULL default 1,
    "word_count" integer NOT NULL default 0
    )
    http://hiphotos.baidu.com/%C2%B9%CD%E8%C3%A8/pic/item/e575bcf5acb72b73730eecf4.jpg
    -------------------------转换为-------------------------
    http://www.zhikanlz.com/get_outside_image/hiphotos.baidu.com/%C2%B9%CD%E8%C3%A8/pic/item/e575bcf5acb72b73730eecf4.jpg
    location ~* ^/get_outside_image/(.*?)/(.*) {
    expires 30d;
    set $obj_referrer http://$1/;
    resolver 8.8.8.8;
    proxy_pass http://$1/$2;
    proxy_set_headerreferer $obj_referrer;
    proxy_set_header host $1;
    }
  • 11. 后续问题&改进途径
    小说源由管理员(我)手动添加效率太低
    提供txt下载
    对天涯社区的支持
    改进途径:
    允许用户直接添加原帖地址,并实时的展现抓取的过程
    从抓取的html文件生成txt。
    新建tianya_crawler.py
  • 12. 准备工作
    Comet
    long-polling
    基于ajax的长轮询
    框架选择(Twisted)
  • 13. 项目结构
    [nowater_web]
    web.py
    包含两个app
    Novel: …
    Admin: …
    添加novel小说源信息
    [database]
    … …
    Nginx
    使用twisted.web维持一个长连接
    该长连接起到实时返回抓取进度的作用,同时writer.py也通过这个文件提供的http接口与之交互
    [nowater]
    main.py
    basedb.py
    baidu_crawler.py
    writer.py
    long_looping.py
    tianya_crawler.py
    … …
    提供抓取完成的html静态文件
    调用http接口驱动爬虫
    对于抓取进度方面的长连接请求反向代理到这里来
  • 14. Comet
    实时显示抓取进度
    class Progress(resource.Resource):
    def render_GET(self, request):
    id = request.args.get("id", [""])[0]
    client_id = request.args.get("client_id", [""])[0]
    client = mb.connection_made(id, client_id, request)
    if isinstance(client, str):
    return client
    else:
    request.notifyFinish().addErrback(self.disconnect, client)
    return server.NOT_DONE_YET
    def disconnect(self, ret, client):
    client.request = None
    client.status = False
  • 15. Comet
    实时显示抓取进度
    def render_POST(self, request):
    """
    通知某小说更新到了某一页
    page:
    start 开始
    r_12 表示初始页面的12页
    o_12 表示小说页面的12页
    end 结束
    """
    id = request.args.get("id", [""])[0]
    page = request.args.get("page", [""])[0]
    mb.new_msg(id, page)
    return "ok"
  • 16. 问题和解决
    下载txt文件的实现
    Nginxsendfile
    location /download_txt/ {
    internal;
    alias /;
    }
    PY:
    file = get_txt_file(str(id), web.utf8(novel.title))
    if file:
    web.replace_header("Content-Type", "text/plaintext")
    web.replace_header("Content-Disposition", "attachment; filename=%s.txt" % id)
    web.header("X-Accel-Redirect", "/download_txt/%s" % file)
    return "ok"
  • 17. 生态链
    baidu_crawler.py
    … …
    twisted
    main.py
    writer.py
    新帖,先插入帖子的相关信息,调用twisted的接口,开始抓取
    旧帖,一定更新间隔
    Comet
    Client
    web.py
    提交帖子地址给web.py
    如果是已经存在的帖子,直接返回供阅读
  • 18. Thanks
    希望Python在中国的应用越来越多
    Enjoy coding!
    Author: piglei2007@gmail.com

×