V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
darksand
V2EX  ›  Python

[Sasila] 一个简单易用的爬虫框架

  •  1
     
  •   darksand · 2017-07-12 14:01:31 +08:00 · 3365 次点击
    这是一个创建于 2723 天前的主题,其中的信息可能已经有所发展或是发生改变。

    现在有很多爬虫框架,比如scrapywebmagicpyspider都可以在爬虫工作中使用,也可以直接通过requests+beautifulsoup来写一些个性化的小型爬虫脚本。但是在实际爬取过程当中,爬虫框架各自有优势和缺陷。比如 scrapy,它的功能强大,但过于强大的功能也许反而让新手无所适从,并且它采用 twisted 异步框架开发,对新手来说源码难以理解,项目难于调试。所以我模仿这些爬虫框架的优势,以尽量简单的原则,搭配 gevent(实际上是 grequests)开发了这套轻量级爬虫框架。

    • downloader 是下载器。
    • processor 是解析器。
    • scheduler 是调度器。
    • pipeline 是数据处理器。
    • 将下载器,解析器,调度器,数据处理器注入核心 core 成为 spider 对象。
    • 通过 manager 管理 spider 对象
    • manager 透过 webapi 提供外部访问 /控制接口

    主要特点

    • 框架代码结构简单易用,易于修改。新手、老鸟皆可把控。
    • 采用 gevent 实现并发操作,与 scrapy 的 twisted 相比,代码更容易理解。
    • 完全模块化的设计,强大的可扩展性。
    • 使用方式和结构参考了scrapywebmagic。对有接触过这两个框架的朋友非常友好。
    • 不采用命令行来启动爬虫,方便调试。
    • 对数据的解析模块并没有集成,可以自由使用beautifulsouplxmlpyqueryhtml5lib等等各种解析器进行数据抽取。
    • 集成代理换 IP 功能。
    • 支持高并发采集数据。
    • 支持分布式。
    • 支持增量爬取。
    • 支持爬取 js 动态渲染的页面(加载 SeleniumDownLoader 即可)。
    • 提供 webapi 对爬虫进行管理、监控。
    • 提供即时爬虫的集成思路和结构。

    安装

    pip install sasila
    

    准备

    • 请准备好您的 redis 服务器进行调度。
    • 并在 settings.py 文件中 写入您的 redis 服务器地址
    REDIS_HOST = 'localhost'
    REDIS_PORT = 6379
    

    构建 processor(解析器)

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    from bs4 import BeautifulSoup as bs
    from sasila.system_normal.processor.base_processor import BaseProcessor
    from sasila.system_normal.downloader.http.spider_request import Request
    from sasila.system_normal.spider.spider_core import SpiderCore
    
    class Mzi_Processor(BaseProcessor):
        spider_id = 'mzi_spider'
        spider_name = 'mzi_spider'
        allowed_domains = ['mzitu.com']
        start_requests = [Request(url='http://www.mzitu.com/', priority=0)]
    
        @checkResponse
        def process(self, response):
            soup = bs(response.m_response.content, 'lxml')
            print soup.title.string
            href_list = soup.select('a')
            for href in href_list:
                yield Request(url=response.nice_join(href['href']))
    

    写法与 scrapy 几乎一样

    • 所有的解析器都继承自 BaseProcessor ,默认入口解析函数为 def process(self, response)。
    • 为该解析器设置 spider_id 和 spider_name,以及限定域名。
    • 初始爬取请求为 start_requests,构建 Request 对象,该对象支持 GET、POST 方法,支持优先级,设置回调函数等等所有构建 request 对象的一切属性。默认回调函数为 process
    • 可以使用 @checkResponse 装饰器对返回的 response 进行校验并记录异常日志。你也可以定义自己的装饰器。
    • 解析函数因为使用 yield 关键字,所以是一个生成器。当 yield 返回 Request 对象,则会将 Request 对象推入调度器等待调度继续进行爬取。若 yield 不是返回 Request 对象则会进入 pipelinepipeline 将对数据进行清洗入库等操作。

    与 scrapy 相似,sasila 同样提供LinkExtractor 的方式来提取链接,以下是用LinkExtractor的方式构造processor下载妹子图的示例

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    from sasila.system_normal.processor.base_processor import BaseProcessor, Rule, LinkExtractor
    from sasila.system_normal.downloader.http.spider_request import Request
    import os
    import uuid
    
    class MezituProcessor(BaseProcessor):
        spider_id = 'mzitu'
        spider_name = 'mzitu'
        allowed_domains = ['mzitu.com', 'meizitu.net']
        start_requests = [Request(url='http://www.mzitu.com/xinggan/')]
    
        rules = (
            Rule(LinkExtractor(regex_str=r"http://i.meizitu.net/\d{4}/\d{2}/[0-9a-z]+.jpg"),callback="save", priority=3),
            Rule(LinkExtractor(regex_str=r"http://www.mzitu.com/\d+"), priority=1),
            Rule(LinkExtractor(regex_str=r"http://www.mzitu.com/\d+/\d+"), priority=2),
            Rule(LinkExtractor(regex_str=r"http://www.mzitu.com/xinggan/page/\d+"), priority=0),
        )
    
        def save(self, response):
            if response.m_response:
                if not os.path.exists("img"):
                    os.mkdir("img")
                with open("img/" + str(uuid.uuid1()) + ".jpg", 'wb') as fs:
                    fs.write(response.m_response.content)
                    print("download success!")
    

    LinkExtractor 的构造方式为

    LinkExtractor(regex_str=None, css_str=None, process_value=None)
    
    • 提供正则表达式提取方式:regex_str
    • 提供 css 选择器提取方式:css_str
    • 也可以自定义process_value来提取链接,其中process_value是一个生成器
    • 若使用此方式构造processor,请不要定义默认入口函数 def process(self, response)

    构建 pipeline

    该 pipeline 获取数据后将数据转为 json 格式,并输出到屏幕

    from sasila.system_normal.pipeline.base_pipeline import ItemPipeline
    import json
    
    class ConsolePipeline(ItemPipeline):
        def process_item(self, item):
            print json.dumps(item).decode("unicode-escape")
    

    构建 spider(爬虫对象)

    • 通过注入 processor 生成 spider 对象
    from sasila.system_normal.spider.spider_core import SpiderCore
    
    spider = SpiderCore(Mzi_Processor())
    
    • SpiderCore 对象包含批下载数量 batch_size,下载间隔 time_sleep,使用代理 use_proxy 等一切必要的属性
    SpiderCore(processor=None, downloader=None, use_proxy=False,scheduler=None,batch_size=None,time_sleep=None)
    
    • 本项目集成使用代理 IP 的功能,只要在构建 SpiderCore 时将 use_proxy 设置为 True,并在脚本同级目录下放置 proxy.txt 文件即可。你也可以在 settings.py 文件中写入代理 IP 文件路径。
    PROXY_PATH_REQUEST = 'proxy/path'
    
    • proxy.txt 文件中请写入代理 IP,格式为:IP,端口号。若该代理 IP 有账号密码,在末尾追加账号密码即可。
    127.0.0.1,8080
    127.0.0.2,8080,user,pwd
    127.0.0.3,8080,user,pwd
    
    • SpiderCore 已经默认设置好了 downloaderscheduler,如果不满意,可以自己进行定制。

    • 可以为 spider 设置 downloaderpipeline 甚至 scheduler

     spider = spider.set_pipeline(ConsolePipeline())
    
    • 可以通过该方式启动爬虫
    spider.start()
    
    • 也可以将 spider 注入manager进行管理
    from sasila.system_normal.manager import manager
    from sasila import system_web
    
    manager.set_spider(spider)
    
    system_web.start()
    

    访问 http://127.0.0.1:5000/slow_spider/start?spider_id=mzi_spider 来启动爬虫。 访问 http://127.0.0.1:5000/slow_spider/stop?spider_id=mzi_spider 来停止爬虫。 访问 http://127.0.0.1:5000/slow_spider/detail?spider_id=mzi_spider 来查看爬虫详细信息。

    针对需要登录才能爬取的处理办法

    • 可以为 downloader 加载登录器(loginer),在使用 downloader 的时候使用 loginer 进行登录获取 cookies,再进行爬取
    • 也可以自己定义一个 cookie 池,批量进行登录并将登录成功的 cookies 放进 cookie 池中随时进行取用。项目中暂时没有这些功能。欢迎 pull request~

    架构

    • 任务由 scheduler 发起调度,downloader 抓取网页内容,processor 执行预先编写的 py 脚本,输出结果或产生新的提链任务(发往 scheduler ),形成闭环。
    • 每个脚本被认为是一个 spider,spiderid 确定一个任务。
    • downloader 1.method, header, cookie, proxy,timeout 等等抓取调度控制。 2.可以通过适配类似 phantomjs 的 webkit 引擎支持渲染。
    • processor 1.灵活运用 pyquery,beautifulsoup 等解析页面。 2.在脚本中完全控制调度抓取的各项参数。 3.可以向后链传递信息。 4.异常捕获。
    • scheduler 1.任务优先级。 2.对任务进行监控。 3.对任务进行去重等操作。 4.支持增量。
    • webApi 1.对爬虫进行增删改查等操作。

    非及时爬虫流程图

    即时爬虫

    即时爬虫是可以通过 api 调用,传入需要爬取的页面或者需求,即时爬取数据并返回结果。现阶段开发并不完善。仅提供思路参考。示例核心代码在 sasila.system_instant 中。

    即时爬虫-获取数据流程图

    即时爬虫-授权流程图

    为啥叫 Sasila ?

    作为一个 wower,你可以猜到吗ヾ( ̄▽ ̄)

    环境

    暂时只支持 python2.7,其它版本还没有测试过。。

    联系方式

    如果对使用有疑问,或者有想法,欢迎加入讨论群:602909155 交流~

    项目地址

    7 条回复    2017-07-13 16:25:37 +08:00
    NaVient
        1
    NaVient  
       2017-07-12 14:24:54 +08:00   ❤️ 1
    支持,已 star
    ikeeper
        2
    ikeeper  
       2017-07-12 17:22:46 +08:00   ❤️ 1
    支持,已 star
    tedchen
        3
    tedchen  
       2017-07-12 19:48:24 +08:00
    支持,已 star
    cxd44
        4
    cxd44  
       2017-07-12 20:39:06 +08:00 via Android
    支持
    darksand
        5
    darksand  
    OP
       2017-07-12 22:57:18 +08:00 via iPhone
    @cxd44 谢谢!
    darksand
        6
    darksand  
    OP
       2017-07-12 22:57:48 +08:00 via iPhone
    @tedchen 谢谢!
    yangyaofei
        7
    yangyaofei  
       2017-07-13 16:25:37 +08:00 via Android
    正在用 pyspider 做项目,不知道这个和 pyspider 比起来优势是啥?
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2743 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 15:12 · PVG 23:12 · LAX 07:12 · JFK 10:12
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.