测试积点老人 发表于 2018-12-3 16:23:07

Pyspider快速上手

本帖最后由 测试积点老人 于 2018-12-3 16:25 编辑

pyspider简介: PySpider:一个国人编写的强大的网络爬虫系统并带有强大的WebUI。采用Python语言编写,分布式架构,支持多种数据库后端,强大的WebUI支持脚本编辑器,任务监视器,项目管理器以及结果查看器。

pyspider是作者之前做的一个爬虫架构的开源化实现。主要的功能需求是:
      1.抓取、更新调度多站点的特定的页面
      2.需要对页面进行结构化信息提取
      3.灵活可扩展,稳定可监控

而这也是绝大多数python爬虫的需求 —— 定向抓取,结构化化解析。但是面对结构迥异的各种网站,单一的抓取模式并不一定能满足,灵活的抓取控制是必须的。为了达到这个目的,单纯的配置文件往往不够灵活,于是,通过脚本去控制抓取是我最后的选择。

而去重调度,队列,抓取,异常处理,监控等功能作为框架,提供给抓取脚本,并保证灵活性。最后加上web的编辑调试环境,以及web任务监控,即成为了这套框架。

pyspider的设计基础是:以python脚本驱动的抓取环模型爬虫

通过python脚本进行结构化信息的提取,follow链接调度抓取控制,实现最大的灵活性

开发快速上手:
通过web化的脚本编写、调试环境。web展现调度状态

抓取环模型成熟稳定,模块间相互独立,通过消息队列连接,从单进程到多机分布式灵活拓展

主要函数解释:

[*]def on_start(self) 方法是入口代码。当在web控制台点击run按钮时会执行此方法。
[*]self.crawl(url, callback=self.index_page)这个方法是调用API生成一个新的爬取任务,这个任务被添加到待抓取队列。
[*]def index_page(self, response) 这个方法获取一个Response对象。 response.doc是pyquery对象的一个扩展方法。pyquery是一个类似于jQuery的对象选择器。
[*]def detail_page(self, response)返回一个结果集对象。这个结果默认会被添加到resultdb数据库(如果启动时没有指定数据库默认调用sqlite数据库)。你也可以重写on_result(self,result)方法来指定保存位置。
[*]更多知识:
[*]@every(minutes=24*60, seconds=0) 这个设置是告诉scheduler(调度器)on_start方法每天执行一次。
[*]@config(age=10 * 24 * 60 * 60) 这个设置告诉scheduler(调度器)这个request(请求)过期时间是10天,10天内再遇到这个请求直接忽略。这个参数也可以在self.crawl(url, age=10*24*60*60) 和 crawl_config中设置。
[*]@config(priority=2) 这个是优先级设置。数字越小越先执行。


以爬取财经网财经热评为例:启动函数on_start:
@every(minutes=24 * 60)
    def on_start(self):
      self.crawl('http://comments.caijing.com.cn/hottopics/', callback=self.index_page)调用内置函数self.crawl,生成response对象,传给回调函数index_page
@config(age=10 * 24 * 60 * 60)
    def index_page(self, response):
      # 选择所有href属性以http开头的a标签
      for each in response.doc('a').items():
            # 判断该标签是否是《新闻评论》详情的url
            if re.match('http://comments.caijing.com.cn/\d+', each.attr.href, re.U):
                # 再次发送请求,回调函数为最终的解析函数
                self.crawl(each.attr.href, callback=self.detail_page)进入解析方法,解析页面。response.etree是内置方法,它生成一个html的etree对象
@config(priority=2)
    def detail_page(self, response):
      data = {
            "url": response.url,
            # 调用xpath提取title
            "title": response.etree.xpath('//*[@id="cont_title"]/text()')
      }
      return data全部代码:
import re
import json

class Handler(BaseHandler):
    crawl_config = {
    }

    @every(minutes=24 * 60)
    def on_start(self):
      self.crawl('http://comments.caijing.com.cn/hottopics/', callback=self.index_page, force_update=True)

    @config(age=10 * 24 * 60 * 60)
    def index_page(self, response):
      for each in response.doc('a').items():
            if re.match('http://comments.caijing.com.cn/\d+', each.attr.href, re.U):
                self.crawl(each.attr.href, callback=self.detail_page)
            elif re.match('http://comments.caijing.com.cn/hottopics/\d+.shtml', each.attr.href, re.U):
                self.crawl(each.attr.href, callback=self.index_page, force_update=True)

    @config(priority=2)
    def detail_page(self, response):
      etree = response.etree
      print type(etree.xpath('//*[@id="cont_title"]/text()').encode('utf-8'))
      data = {
            "url": response.url,
            "title": etree.xpath('//*[@id="cont_title"]/text()').encode('utf-8'),
            "content":'\n'.join(etree.xpath('//*[@id="the_content"]/p/text()')).encode('utf-8'),
            "post_time":etree.xpath('//*[@id="pubtime_baidu"]/text()').encode('utf-8'),
            "source":etree.xpath('//span[@id="source_baidu"]//text()').encode('utf-8'),
      }
      return data

    def on_result(self, result):
      if not result:
            return
      sql = SQL()
      sql.replace('article', result)
页: [1]
查看完整版本: Pyspider快速上手