# iwriter **Repository Path**: dreamidea/iwriter ## Basic Information - **Project Name**: iwriter - **Description**: 聚合写作 - **Primary Language**: Unknown - **License**: BSD-2-Clause - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-10-06 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Intelligent-writer ## 一、概述 聚合写作就是从一些网站、程序接口获取数据,再根据一些规则对数据进行加工,最后得出可用的数据(一段话或者是格式化存储的若干值)。聚合写作与爬虫的区别是抓取处理存储同步完成,即完成的ETL过程。聚合写作包括很多个数据项目,由于每种项目数据加工过程差异较大,无法使用一种简单的描述语言(如DSL或者JSON)来完成规则配置,因此采用动态脚本的方式,每个数据项都有一个独立的动态脚本,一些通用的功能将被写到系统函数中,动态脚本直接调用,每个动态脚本运行时会启动单独的一个VM空间,两个脚本之间互不影响, 动态脚本负责数据的抓取和转换,在动态脚本的末尾通过return语句返回结果,最终的结果由主系统负责统一存储。 以下是该系统的一些术语: * 调度周期 每个数据项都可以设置定时运行的周期,用秒表示。从调度起始时间开始,每一个调度周期轮回时会运行动态脚本。 * 数据版本 每一轮调度周期运行产生的数据为一个版本,在下一个周期之前反复运行产生的结果为同一个版本,在数据库中会覆盖同一版本前一次的结果。可以为版本号设定一个规则(可以使用魔法变量),如果不设定版本规则,默认的版本号是调度的周期号(第一期是1,第二期为2,以此类推),也可以在动态脚本的返回值中用"$version"的字段返回自定义版本号。 * 代码版本 动态脚本可以在web界面编写和调试,每个数据项有两种版本,测试代码和正式代码,在web ide界面对测试代码进行调试,正常后发布成正式代码,数据项每次调度运行使用的是正式代码。 * Web IDE 在线代码编辑器,在线编辑js代码,语法高亮,自动格式化,在线运行,自动保存。 * Wiki 在线编辑和查看markdown格式的文档,主要是对核心函数的描述文档,后台编写说明,在web ide界面可以查看wiki * 数据分区、类别 数据分区是一级大分类,类别是二级分类。分类的目的是数据项变多以后通过分类筛选查看会比较有效,分布式运行时每个进程可以选择一个分区来运行。分区和类别可以通过web后台的编辑动态配置文件进行修改。 *项目GIT仓库地址:https://github.com/ahkimkoo/iwriter.git* ## 二、运行 先启动web项目,然后通过web界面启动聚合爬虫。聚合条目较多的情况下,单个爬虫进程负载过重,因此聚合规则有数据分区的概念,录入规则时需要选择所属的分区,启动爬虫时也选择相应的分区,一个分区不能同时启动两个爬虫进程,否则会出现调度错乱。 * 启动web
node run.js -e dev -p 8811
其中-e dev是环境参数,dev,test,pro分别对应配置文件settings-dev.json, settings-test.json, settings-pro.json。-p 8811是启动的web端口。
* 启动爬虫
在web界面“服务器”菜单中启动爬虫进程
首次运行参考[第一次部署说明](First-Deploy.md)
## 三、动态脚本说明
### 动态脚本说明
每个动态脚本都负责一个数据抽取项目的数据下载和转化过程。每个动态脚本都运行在独立的沙箱内,相互不影响,动态脚本返回最终的抽取数据,由主程序完成存储环节。
### 运行环境
nodejs v8.11.1, 可使用async/await语句
### 返回结果
动态脚本最后一句必须是return 语句,返回抓取结果,抓取结果有以下几种类型:
#### json对象
必须包含message(文本)或者show(html格式),如果有$version字段,将会覆盖根据规则定义自动产生的数据版本;
#### 字符串
自动格式化为JSON对象,字符串作为message字段的值
#### function函数类型
表示该类数据可以被外部接口调用,调用产生的结果不存数据库
### 魔法变量
魔法变量在字符串中用$ { 名字 } 的方式引用,在动态脚本中可以直接使用
* RULE 当前规则ID
* CALLER 程序调用者,viewer数据查阅者,scheduler调度器,coder编码人
* YEAR 年
* MONTH 月
* DATE 日
* DAY 星期
* HOUR 时
* MINUTE 分
* SECOND 秒
* TIMESTAMP 时间戳YYMMDDhhmms
* NOW 时间值毫秒
* YYMMDD 月日年(今天)
* BYYMMDD 月日年(昨天)
* AYYMMDD 月日年(明天)
### 常用函数
Nodejs内置函数可以直接使用
以下是一些非常好用的函数,可以直接使用
#### 网络请求函数
* getJson(url, option)
请求地址获得json数据,返回的是一个Promise对象,使用await获取最终的json对象
option的参数和[request](https://github.com/request/request) 参数一致,有几个特殊参数作如下说明:
(1)encoding : 在request模块可使用的为utf-8,ascii等,如果返回的页面有乱码,此参数值设置为gbk, gb2312就能解决问题
(2)jsonp : 默认为空,如果是jsonp地址,这里写出jsonp callback的函数名以保证正确返回json数据。
* getDocument(url, option)
请求地址获得html文档,返回的对象是经过html解析的,可以通过使用类似于jquery的方式来查询dom节点,具体用法请查阅[cheerio](https://github.com/cheeriojs/cheerio) 。
option的参数和[request](https://github.com/request/request) 参数一致,有几个特殊参数作如下说明:
(1)encoding : 在request模块可使用的为utf-8,ascii等,如果返回的页面有乱码,此参数值设置为gbk, gb2312就能解决问题
(2)parse : 是否要解析成cheerio对象,默认为true,如果设置为false,将返回网页源代码
* getBrowserDocument(url, test, option)
请求地址获得phtomjs模拟浏览器渲染后的文档,test是一个正则表达式,表示满足该条件后才返回文档。返回的对象是经过html解析的,可以通过使用类似于jquery的方式来查询dom节点,具体用法请查阅[cheerio](https://github.com/cheeriojs/cheerio) 。
option的参数说明:
(1)parse : 是否要解析成cheerio对象,默认为true,如果设置为false,将返回网页源代码;
(2)loadimages : 是否载入图片,默认为false。
* getChromeDocument((url, test, option) 请求地址获得chrome浏览器渲染后的文档, test用来测试页面是否加载完成,可以为css选择符,xpath表达式,函数(相当于在浏览器执行可使用浏览器对象document,window等),test需要返回一个truely的值表示加载完成。函数最终的返回对象是页面内evaluated结果或者文档的dom节点cheerio 。
option参数说明:
(1)parse : 是否要解析成cheerio对象,默认为true,如果设置为false,将返回网页源代码 ;
(2)loadimages : 是否载入图片,默认为false;
(3)timeout: 页面超时时间,默认为60000;
(4)evaluate:这是一个在页面内执行的js表达式或者函数,通常用来抽取一些信息,如果有evaluate,函数最终的返回值就是evaluate在页面内执行后的返回结果。
(5)waitUntil:等待页面加载完成的判别方式,取值为load或domcontentloaded,默认为load。
(6)body: 需要post方式发送请求时指定发送的数据,字符串型。
(7)viewport: 屏幕分辨率设置,例如{'width' : 1920,'height' : 1080},详细参数参照[page.setViewport(viewport)](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pagesetviewportviewport)
* snapshotByPosition(url, test = 'body', rect, encoding='base64', options = {})
指定页面位置,返回截图。参数rect是指定的举行位置[左,上,右,下],encoding取值为base64, binary, uri, url,其中uri返回datauri格式,url返回七牛图片地址,options与getChromeDocument一致,默认载入图片。
* snapshotByElement(url, test = 'body', selector, offset=[0, 0, 0, 0], encoding='base64', options = {})
指定页面上的元素,返回截图,参数selector是css选择符指定要截图的元素,offset是给指定元素位置加偏移量之后截图,其余参数与snapshotByPosition相同。
* retryCheck(checkFun, interval, max_times, delay, startTime)
反复检查直到满足条件再继续执行下一步,checkFun是一个返回Promise的函数,检测是否满足条件返回相应的resolve(true|false), interval是检测周期(毫秒), max_times最多检测多少遍,delay是返回前延迟(毫秒),整个函数最终返回Promise对象,resolve的参数值true|false代表最终检测是否满足条件。
#### 文本处理函数
* pnSyntax (value, positive_sytax, negative_sytax)
根据正负值返回相应的词语,例如pnSytax(-1.1, '涨幅', '跌幅')
* percentSyntax(value, keep_point)
将数字转换成百分表达语句,例如percentSytax(0.25)返回“25%”, keep_point为true表示保留所有小数点位数,如果是数字,表示保留相应的小数点位数。
* quoteChange(base_value, changed_value)
两个数字的变化比例,常用于涨跌计算,返回小数,正数是涨,负数是跌
* quoteChangeSyntax(base_value, changed_value, positive_syntax='涨', negative_syntax='跌', keep_point=2)
生成涨跌描述,返回结果如“涨10%”, keep_point是小数保留几位,如果不保留设为false
* dateFormat(date, format)
日期格式化函数,date是一个Date类型, format是日期格式,'yyyy-MM-dd hh:mm:sss.S', 返回字符串
* lookForPreviousNDay(dayn, skipweeks=0)
获取以前的某个星期几(dayn), skipweeks是跳过几周,返回一个Date对象
* lookForNextNDay = function(dayn, skipweeks=0)
获取以后的某个星期几(dayn), skipweeks是跳过几周,返回一个Date对象
* getTextFromHtml(html)
去掉html标签,返回文本
* table2array(cheerio_dom, query, keep_html)
将表格解析为Array, cheerio_dom是一个cheerio对象,query是表格的查询语句(jquey),keep_html,表示返回html,函数返回二维数组
* array2table(arr, include_header = false, class_name = 'iw_data_table')
将数组转换成html table, include_header表示第一行是否为表头,class_name是table的样式名,函数返回字符串
#### 数据访问函数
* getLastValues(RULE, exclude_version)
返回当前规则的上一次(即上一版本)数据,参数RULE是固定用法,表示当前规则,exclude_version是当前版本号,如果没有填写表示返回最后一个版本,如果填写为'DEFAULT'系统按照调度周期或者规则里面指定的version规则生成当前规则。
返回的数据包括,上一版本抓取的自定义字段,以及message, version, updated, created字段。这是一个async函数,返回Promise对象,建议使用await语句。
* getValuesByVersion(RULE, version)
获取某个规则指定版本的数据,如果是当前规则,可以用RULE,否则填写具体的规则ID,version是特定的版本号。返回的数据包括,指定版本抓取的自定义字段,以及message, version, updated, created字段。这是一个async函数,返回Promise对象,建议使用await语句。
* getPreviousNValues(RULE, n)
获取某个规则N个版本之前的数据,如果是当前规则,可以用RULE,否则填写具体的规则ID,n表示几个版本之前,本函数指定的数据不等同于取n个自然日之前数据,加入版本号按照自然日取名,取5个版本之前的数据,一旦其中有一个自然日没有数据,就会编程取6个自然日之前的数据,以此类推。返回的数据包括,指定版本抓取的自定义字段,以及message, version, updated, created字段。这是一个async函数,返回Promise对象,建议使用await语句。
#### 其他函数
* sendMail(address, subject, text, html, config={}, sender)
发送邮件,address为收件人地址,列表格式,例如:['"Hero"