jarviscrawlercore
Version:
jarvis crawler core
824 lines (556 loc) • 29.2 kB
Markdown
# JarvisCrawlerCore Development Log
### 2020-02-08
这几天重写douban,代码结构又有点小调整,感觉越来越好了。
但是,
这套代码其实有3种写法了,好乱,没时间整理老代码,先这样吧。
### 2019-12-26
折腾过2次windows下的项目安装,前面一次是自己的虚拟机上,因为以前装过vs,所以除了网络问题外,没遇到别的什么问题,这次是在一台服务器上,node-gyp稍折腾了下,一定要参考node-gyp的文档,先把prebuild环境装好,其实也就是一个命令行的事情。
然后麻烦在于国内网络对aws限制很死,而github很多资源都放aws上,aws好像会临时给你生成一下下载通道,超过时间就下载不到了。
hosts这些也都不行,我是找台机器下载好,然后把文件复制到npm的cache里面把问题解决掉的。
这次主要是sharp有一个libvips的依赖,在 C:\Users\Administrator\AppData\Roaming\npm-cache\_libvips 下有个文件,下载地址在这里 https://github.com/lovell/sharp-libvips/releases/download/v8.8.1/libvips-8.8.1-win32-x64.tar.gz 下载完覆盖进去就好了。
期待 github 入华。
### 2019-12-07
http request返回一般是 buffer,在 nodejs里,如果是utf8编码的,可以直接 toString 得到string。但如果是unicode编码的,则需要转码,可以通过 String.fromCharCode 转码。
### 2019-11-14
taobao的页面,一般是 https://item.taobao.com/item.htm?id=592826167303 ,重点在 itemid 。
taobao 和 tmall 页面布局差别很大,很多数据没有像 tmall 那样处理,sib.html 里,有具体 sku 的价格和库存数据。
然后 Hub.config.sku 里是另外一部分 sku 数据,2个合起来应该就够了。
### 2019-11-05
今天遇到一个browser的bug,就是可能frames取不全,网上查了一下,有一个很详细的issue,就前不久刚发的,但那个在chrome下无效,因为一些别的原因,必须要用chrome。
后来找到了一个``OOPIF``的issue,里面提到是浏览器bug,加个参数启动就可以解决。
```
-disable-features=site-per-process
```
果然就好了。
然后是关于``Captcha``的,其实复杂的校验机制解决起来会很折腾,技术是一方面,剩下的更多还是动脑筋,得有技巧才行,不到万不得已,不要硬解。
关键还是不要过分挖掘别人的数据吧,一定的自动化,提升效率为主,恶意盗取数据还是不可取的。
### 2019-10-24
``node.js`` 版本更新非常频繁,大部分时候大版本升级都是向下兼容的,但``node-gyp``相关的没那么快,所以``package-lock.json``最好还是同步一下,然后 ``Dockerfile`` 里的node版本号,至少也要给到大版本,今天``dockerhub``发布就遇到问题了,一查才发现``node.js``升级到13了,按照``node.js``的规划,奇数版本属于开发版,还是用现在的LTS版比较好。
### 2019-10-22
JD,如果 ``.activity-banner`` 的 id 是 ``J_atmosphere_banner``,可能是双十一。
如果是 ``banner-shangou``,则是闪购。
``$$('.activity-message')[0].innerText``是闪购的剩余时间,好像可以取到更细的值,但估计用处不大。
``$$('.summary-price-wrap')[0].getElementsByClassName('p-price')`` 这个是闪购价格。
``document.getElementById('page_opprice').innerText``是原始价格。
只要不是``pingou`` 和 ``banner-shangou``,估计都是正常商品。
这时,取``#jd-price``是价格。
这里的价格类似¥279.30,如果要转浮点数,需要特殊处理一下。
``#page_maprice`` 这是原价。
``.quan-item`` 这是优惠券。
``.prom-item`` 可以取到促销信息。
这可能有多个,每个节点下面,前面2个em,一个是类型,一个是内容。
如果不是pingou,这样可以找到服务提供商。
``` js
$$('#summary-service')[0].getElementsByClassName('hl_red')
```
### 2019-10-19
jd的促销活动页面,一般是这样的,https://pro.jd.com/mall/active/3nTQQZ66AGtiwwtRcikGFnT1DVjX/index.html 。
这个页面,其实没有太多结构化数据,简单的找到 ``a`` 即可。
如果是 ``https://item.jd.com/`` 开头的就是商品页。
如果是 ``https://pro.jd.com/mall/active/`` 开头的就是活动页。
mountainsteals 商品页,下面是商品类型。
``` js
$$('.breadcrumb-itm')
```
下面是价格购买区。
``` js
$$('#widget_product_info_viewer')
```
下面是商品名。
商品名里有品牌。
``` js
$$('.product_name')
```
这是品牌。
``` js
$$('.brand')
```
商品评分。
``` js
$$('.RatingAddtlInfo')
```
当前价格。
``` js
$$('.price-set')
```
原价
``` js
$$('.pdp-strike-extra')
```
这个是大小、颜色的选框,可能多个,也可能是大小颜色以外的。
``` js
$$('.po-link.po-size-link')
```
这个是选项内容。
``` js
$$('.selector-itm-box')
```
取到这个节点的class以后,可以根据class是否有 js-size-product-thumb 或 js-color-product-thumb 判断是 size 还是 color。
``` js
$$('.selector-itm-box')[0].getElementsByClassName('po-row')[0].getElementsByClassName('product-thumb')
```
如果是size,这样可以取到size内容。
``` js
$$('.selector-itm-box')[0].getElementsByClassName('po-row')[0].getElementsByClassName('js-size-name')
```
如果是color,这样可以取到color内容。
``` js
$$('.selector-itm-box')[1].getElementsByClassName('po-row')[0].getElementsByClassName('js-color-name')
```
下面是各种评分的人数。
这里面,``data-bv-histogram-rating-value``是星,``data-bv-histogram-rating-count``是人数。
``` js
$$('.bv-inline-histogram-ratings-bar')
```
平均明细评分,一个标题 ``$$('.bv-secondary-rating-summary-id.bv-td')``,一个评分 ``$$('.bv-secondary-rating-summary-rating')``。
其中,如果是 Fit,则没有数字的评分。
Fit 还要找一些例子看。
评论,``$$('.bv-content-item.bv-content-top-review.bv-content-review')`` 这样可以找到。
作者名。
可能会找到多个,取第一个即可。
``` js
$$('.bv-content-item.bv-content-top-review.bv-content-review')[0].getElementsByClassName('bv-author')
```
作者位置,字符串的。
``` js
$$('.bv-content-item.bv-content-top-review.bv-content-review')[0].getElementsByClassName('bv-author-location')
```
下面是这个用户对这件商品的评分。
children[0] 的 attributes 里,应该有 itemprop ,且该值为 ratingValue 。
``` js
$$('.bv-content-item.bv-content-top-review.bv-content-review')[0].getElementsByClassName('bv-content-rating bv-rating-ratio')[0].children[0].content
```
评价的标题。
``` js
$$('.bv-content-item.bv-content-top-review.bv-content-review')[0].getElementsByClassName('bv-content-title')
```
评价的内容。
``` js
$$('.bv-content-item.bv-content-top-review.bv-content-review')[0].getElementsByClassName('bv-content-summary-body-text')
```
是否推荐,找到这个节点。
如果有 ``bv-content-data-recommend-no`` 节点,表示不推荐。
``'bv-content-data-recommend-yes'`` 表示推荐。
``` js
$$('.bv-content-item.bv-content-top-review.bv-content-review')[3].getElementsByClassName('bv-content-data')
```
评论时间,字符串方式的。
几年以前几个月以前这样的。
``` js
$$('.bv-content-item.bv-content-top-review.bv-content-review')[2].getElementsByClassName('bv-content-datetime-stamp')
```
### 2019-10-18
jd的商品页面,在 https://item.jd.com/下面,一般是html页面,譬如https://item.jd.com/100006585530.html。
商品类别,可以找这个 ``#crumb-wrap``,或者直接找这个 ``.crumb.fl.clearfix``。
``` js
$$('.crumb.fl.clearfix')[0].getElementsByClassName('item')
```
这样的结果,里面去掉class包含sep的,也就是``.item.sep``的。
里面品牌那里是个select,但我们只要文本,所以也可以很方便取到。
``` js
$$('.crumb.fl.clearfix')[0].getElementsByClassName('item')[6].innerText
```
取名字。
``` js
$$('.sku-name')[0].innerText
```
这里,如果里面有img,最好把alt取出来,做tag用。
``` js
$$('.sku-name')[0].getElementsByTagName('img')[0].alt
```
下面是产品描述,不知道为啥叫new。
``` js
$$('.news')[0].innerText
```
接下来是banner,这个应该是分类型的。
``` js
$$('.activity-banner')
```
类型,我估计可以通过这个id来判断。
或者,取到下面的innerText也可以的。
``` js
$$('.activity-type')[0].innerText
```
然后,估计不同的类型,会有不同的数据。
``` js
$$('.activity-message')[0].getElementsByClassName('item')
```
这里,如果是预售,第一个是预定量,第二个是剩余时间,时间是中文的剩余时间,要反推出结束时间来。
然后是价格,我估计要根据类型来。
下面这个是尽量回避类型的取值了。
``` js
$$('.summary-price-wrap')[0].getElementsByClassName('summary-price')
```
商品摘要信息。
``` js
$$('.summary.p-choose-wrap')
```
这个是售后提供者。
``` js
$$('.summary-service')[0].getElementsByTagName('span')[0].innerText
```
这个是发货时间。
``` js
$$('#summary-yushou-ship')[0].getElementsByClassName('dd')[0].innerText
```
这个是重量。
``` js
$$('#summary-weight')[0].getElementsByClassName('dd')[0].innerText
```
下面是选择项,估计可能有多个,这个children里面,id会类似``choose-attr-1``这样。
``` js
$$('#choose-attrs')[0].children
```
或者,这样
``` js
$$('#choose-attrs')[0].getElementsByClassName('li p-choose')
```
取选项数据
``` js
$$('#choose-attrs')[0].getElementsByClassName('li p-choose')[0].getElementsByClassName('item')
```
评论数据。
``` js
$$('.comment-info.J-comment-info')
```
好评百分比。
``` js
$$('.percent-con')[0].innerText
```
这里是评论的tag列表。
``` js
$$('.percent-info')[0].getElementsByTagName('span')
```
这里是评论的统计。
``` js
$$('.J-comments-list.comments-list.ETab')[0].getElementsByClassName('tab-main small')[0].getElementsByTagName('li')
```
其中,class为current的是总计,class为J-addComment的是追评,剩下的有class的都可以放弃掉。
``#detail``这个里面,找``li``。
里面找 商品评价 。
``` js
$$('#detail')[0].getElementsByTagName('li')
```
### 2019-10-16
这几天一直发现Charles可能会卡,以为是Charles的问题,今天仔细查了一下,还是crawler的bug,有时候chrome还是会卡住。
最初想法是从grpc这边加超时,后来想到这样crawler这边还是可能会慢慢积累chrome进程,时间长了,内存会受不了的。
实际测了一下,这种情况下,很多是websocket的一个错误,因为现在一个请求,可能要几分钟时间才能返回,有可能是grpc底层网络问题吧,但如果这时重启jarviscrawlerserv,客户端那边能很快得到响应,原因待查。
有个正确的判断element是否可视的接口。
``` js
/**
* isElementVisible
* @param {object} page - page
* @param {object} ele - element
* @return {bool} isvisible - is visible
*/
async function isElementVisible(page, ele) {
const isVisibleHandle = await page.evaluateHandle((e) => {
const style = window.getComputedStyle(e);
return (
style &&
style.display !== 'none' &&
style.visibility !== 'hidden' &&
style.opacity !== '0'
);
}, ele);
const visible = await isVisibleHandle.jsonValue();
const box = await ele.boxModel();
if (visible && box) {
return true;
}
return false;
}
```
### 2019-10-08
关于``puppeteer``,特别需要注意要waitFor,会有大量的element都不是马上构建好的,切记一定要waitFor以后再操作。
然后就是click,最好先hover,这时会移动滚动条,保证该element可见。
这时可能还会有些页面级的bug,譬如分页的表单,页数为1位数甚至2位数都可见,但到3位数时,可能就会看不见,这时hover或者click都会报错,这时就只能自己特殊处理了。
### 2019-09-09
今天部署了一台国内的机器,整个流程都非常的不顺,需要加各种镜像映射才行,后来还是将dockerhub弄好了,这样就不用走build docker的流程,会好很多吧。
dockerhub非常慢,build一次要18分钟。
### 2019-08-25
前几天开始把npm提交放到github的action了,这几天测了一下,没啥问题,每次合并master时,就会自动发布到npm。
然后,基于golang的jccclient差不多也完善了。
接下来,计划会升级到v0.3,主要是彻底的插件化,现在代码越来越多,不容易维护了。
升级到v0.3以后,还有个很重要的,就是会考虑私有插件的问题。
现在的想法比较简单,私有插件的话,自己做个私有bin就好了。
到v0.3,就不支持v0.1的grpc接口了。
### 2019-08-07
今天开始,npm的提交基于github上的release包了。
``` sh
npm publish https://github.com/zhs007/jarviscrawlercore/archive/v0.2.62.tar.gz
```
``puppeteer``的``networkidle2``这一组感觉也不怎么靠谱,可以自己侦听 request 和 response 来处理,这样比较容易控制一些。
``` js
page.on('request', (req) => {
let url = req.url();
if (url.indexOf('data:image') == 0) {
url = 'local:imgdata-' + hashMD5(url);
}
const oldreq = findReq(lstReq, url);
if (oldreq) {
return;
}
console.log('request - ', url);
lstReq.push({
url: url,
st: Date.now(),
et: -1,
status: 0,
buflen: 0,
});
});
page.on('response', async (res) => {
let url = res.url();
if (url.indexOf('data:image') == 0) {
url = 'local:imgdata-' + hashMD5(url);
}
console.log('response - ', url);
const req = findReq(lstReq, url);
if (req) {
const buf = await res.buffer();
req.buflen = buf.byteLength;
req.et = Date.now();
req.status = res.status();
} else {
console.log('no response', url);
}
});
```
还有几个简单的处理函数,在这里。
``` js
/**
* findReq - find a request
* @param {array} reqs - request list
* @param {string} url - url
* @return {object} req - request
*/
function findReq(reqs, url) {
for (let i = 0; i < reqs.length; ++i) {
if (reqs[i].url == url) {
return reqs[i];
}
}
return undefined;
}
/**
* isReqFinished - is request finished?
* @param {array} reqs - request list
* @return {bool} isfinished - is finished
*/
function isReqFinished(reqs) {
for (let i = 0; i < reqs.length; ++i) {
if (reqs[i].status == 0) {
return false;
}
}
return true;
}
```
其实需要特殊考虑的主要就是多次的request请求,特殊处理一下就好。
### 2019-07-23
最近在日本,dtbkbot的测试用``service+dtclient2``。
### 2019-07-09
关于``puppeteer``,最近又有些感想:
1. 自己通过``page``来侦听``domcontentloaded``这些事件会比``page.waitFor``要稳定一些,细节更可控,官方的``waitFor``实现应该是太简单了,所以导致某些复杂逻辑下经常会卡主。
2. ``frame``的处理,我一般是等待该页面的``response``彻底完成,这个只能在``page``来处理。
3. ``frame``内部的``reCAPTCHA``是可以处理对的,基本上可以通过``page``处理对,但切记,要确定彻底加载成功,这个步骤非常重要,我一般通过``response``和``domcontentloaded``来确定彻底加载成功,然后通过clientRect计算出点击位置或hold位置。
4. ``page``的``viewport``在某些时候非常重要,如果element不可见,可能会导致后面的操作报错。
5. ``click``操作其实会移动屏幕,当然只限于有滚动条的情况,如果页面写得不好,对``viewport``有要求,``click``是可能报错的,这时只能通过改变``viewport``避免bug。
6. 安全稳定的操作,一定是逻辑严密的,不能所有事都依赖于sleep时间,而最后从逻辑层避免sleep。
7. 业务逻辑上,一定要处理所有的异常状况,一些未考虑的异常保留足够的输出,并安全退出,为下一次做准备。
```
node ./bin/jarviscrawler.js bt ./cfg/btcfg.yaml -n oabt
```
豆瓣查找
```
node ./bin/jarviscrawler.js douban search -s "蜘蛛 侠" -d true -t movie
```
### 2019-06-23
关于爬虫,其实这次写这个项目,并不是希望把数据全拉下来(不现实也没啥必要)。
只是想能有个更方便的查询方式而已。
目的是自动化,不是拿到数据。
### 2019-06-22
今天新开了``0.2``的分支,主要是下面几个结构调整:
1. 命令行模式切换到具体模块内,这样 ``bin/jarviscrawler.js`` 代码结构会更清晰。
2. ``service``模式下,增加统一的请求协议,统一来处理协议过长需要``stream``的情况。
### 2019-06-21
crunchbase organization 页面的一点记录:
- ``cb-overflow-ellipsis`` 名字。
- 大栏目 ``layout-row section-header ng-star-inserted`` ,该元素的父节点才是card节点。
- 在 overview 和 IPO 分栏里, ``cb-text-color-medium field-label flex-100 flex-gt-sm-25 ng-star-inserted`` 是所有的小栏目,该节点的next是内容。
- 剩下几个表格card里,``tr.ng-star-inserted``取到行。
crunchbase login 页面的一点记录:
- ``tag``为``mat-form-field``的是输入框,search也是一个输入框。
- ``id``为``mat-input-1``是email,``mat-input-2``是密码。
- ``.cb-text-transform-upper.mat-raised-button.mat-primary``这个是登录按钮。
怎么判断``reCAPTCHA``?
crunchbase页面会多产生一次跳转,且如果第二次跳转返回403,就会进入``reCAPTCHA``流程。
譬如我们访问``https://www.crunchbase.com/organization/slack``,当mainframe第二次定位到这个url时,如果response的status是403的话,就是``reCAPTCHA``。
今天实现了这个,但有个小问题,再登录时,有可能点击登录按钮再跳转页面的时候出现``reCAPTCHA``。
处理``captcha``
通过``#px-captcha``得到区域,然后模拟鼠标操作。
鼠标操作有问题,如果页面比较大,不能直接用mouse来操作,而应该自己发送event,因为client坐标需要写对。
在控制台,这个指令可以查看``event``,``monitorEvents(document.body, "click");``。
### 2019-06-20
这个可以通过crunchbase查询公司情况,这个接口是查询公司的,可以根据常规的名字查到公司代码。
```
node ./bin/jarviscrawler.js crunchbase companies -c Facebook
```
这个用来查询公司明细,需要传入companycode才行。
```
node ./bin/jarviscrawler.js crunchbase company -c slack
```
crunchbase前面有个检查,暂时没有处理,有些时候需要主动点一下。
这个可以下载blob的图片。
```
node ./bin/jarviscrawler.js playngo blobimg -g gameofgladiators
```
### 2019-06-03
```
node ./bin/jarviscrawler.js yc company
```
### 2019-05-23
今天增加了zdreview.com
```
node ./bin/jarviscrawler.js getarticle -o 123.pb https://zdreview.com -d true
```
### 2019-04-23
今天发布了一个非docker版本,这样发布,可以直接安装。
```
npm publish https://github.com/zhs007/jarviscrawlercore/archive/v0.1.41.tar.gz
```
后来处理了techinasia, iheima, smzdm。
```
node ./bin/jarviscrawler.js getarticles -o 123.pb https://www.techinasia.com
node ./bin/jarviscrawler.js getarticles -o 123.pb http://www.iheima.com -d true
node ./bin/jarviscrawler.js getarticles -o 123.pb https://post.smzdm.com -d true
node ./bin/jarviscrawler.js getarticles -o 123.pb https://news.smzdm.com -d true
```
### 2019-04-18
```
node ./bin/jarviscrawler.js dtbkbot ./cfg/dttestbot.yaml -h false -d false -m gametodaydata
node ./bin/jarviscrawler.js dtbkbot ./cfg/dttestbot.yaml -h false -d false -m gamedatareport -s 2019-04-17 -e 2019-04-17
```
### 2019-04-17
从昨天开始,我发现其实很多``evaluate``的事情,其实``$eval``和``$$eval``也都能做。
### 2019-04-15
关于``puppeteer``的几个问题:
1. 感觉一直在wait那块有bug,我的感觉是有些时候,调用的时间点,event已经触发过了,所以就只能timeout,其实这种可以用我们zhihu的一些处理方法,就是在浏览器环境里,加标志量,在nodejs里wait那个变量就好,这样不会出问题。
2. 还有就是前几天处理``techinasia``遇到的,那个是页面动态加载的,如果取了动态加载部分,再来设置``setContent``就会卡timeout,后来回避了这个问题,就好了。
3. 就是可能会出现``$ is not defined``的错误,我觉得是``addScriptTag``没有等待加载完成,就返回导致的,现在可以用``attachJQuery``这个接口来加载``jquery``了,这个接口会检查是否需要加载,并等待加载完成。
4. 尽量用``waitForFunction``,这个目前看来是最不容易timeout的了,然后这个里面其实也可以改浏览器环境下的值,只是依靠返回值决定是否放开waitfor而已。
5. 今天尝试过侦听2个``framenavigated``事件,发现很容易卡住,感觉并发处理有些问题,这个对调用先后有要求,所以尽量顺序调用吧。
### 2019-04-13
今天处理了``medium``、``techcrunch``。
```
node ./bin/jarviscrawler.js exparticle https://medium.com/@sean22492249/%E5%88%A9%E7%94%A8-rasa-n-rasa-core-%E4%BE%86%E5%BB%BA%E7%AB%8B%E4%B8%AD%E6%96%87%E7%9A%84-chatbot-aa65436efa5f -o ./output/abc.pdf -m pdf -h false -i true -q true -d true
node ./bin/jarviscrawler.js exparticle https://techcrunch.com/2019/04/03/ruhnn-ipo/ -o ./output/a.pdf -m pdf -h false -i true -q true -d true
node ./bin/jarviscrawler.js exparticle https://www.techinasia.com/3-vietnamese-platforms-visited-ommerce-sites-sea -o ./output/abc.pdf -m pdf -h false -i true -q true -d true
```
### 2019-04-12
今天articles也支持了service。
### 2019-04-11
```
node ./bin/jarviscrawler.js getarticles -o 123.pb http://www.baijingapp.com
node ./bin/jarviscrawler.js getarticles -o 123.pb -q true https://36kr.com
node ./bin/jarviscrawler.js getarticles -o 123.pb https://www.geekpark.net
node ./bin/jarviscrawler.js getarticles -o 123.pb https://www.huxiu.com
node ./bin/jarviscrawler.js getarticles -o 123.pb https://www.lieyunwang.com
node ./bin/jarviscrawler.js getarticles -o 123.pb https://www.tmtpost.com
node ./bin/jarviscrawler.js getarticles -o 123.pb https://techcrunch.com
```
### 2019-04-08
这几天把翻译的功能接入到``JarvisTeleBot``,现在双向翻译方便很多了。
这几天简单处理了一下电商网站,有几个小技巧,其实就是改本地``DOM``,怎么方便怎么来,没必要太拘泥于一些”好“的实现,浏览器都在手上了,能控制住的就控制住,省得进一步折腾。
今天开始将``exportarticle``移植到``service``里去,支持了长消息(``grpc``不允许大于4mb的消息)。
然后就是,代码量越来越大了,需要有单元测试才好,否则后面代码重构风险越来越大。
目前想到的还是单独写单元测试,一方面可以测代码本身,另外还可以测网站是否升级,尽可能用现成的代码来做单元测试。
### 2019-04-05
切换到``grpc-tools``了,如果要重新buildproto,需要先装``grpc-tools``。
```
npm install -g grpc-tools
```
今天把服务也写好了,你可以通过
```
node ./bin/jarviscrawler.js startservice ./cfg/service.yaml
```
写了个简单的client,可以这样
```
node ./src/service/client.js
```
### 2019-04-04
今天把google翻译支持了。
```
node ./bin/jarviscrawler.js googletranslate "你好 你很好,哈哈" -h true -s zh-CN -d en
node ./bin/jarviscrawler.js googletranslate "@Peter Walker I am sure there is a problem with excel file, I need more time to check it." -h true -s en -d zh-CN
```
### 2019-04-02
今天调整了``exparticle``的参数。
取消了以前可以同时输出``protobuf``、``pdf``、``jpg``的方案,现在一次只能输出一种格式。
```
node ./bin/jarviscrawler.js exparticle https://post.smzdm.com/p/alpzl63o/ -o ./output/abc.pdf -m pdf -h true -i true
node ./bin/jarviscrawler.js exparticle https://post.smzdm.com/p/alpzl63o/ -o ./output/abc.jpg -m jpg -h true -j 80
node ./bin/jarviscrawler.js exparticle https://post.smzdm.com/p/alpzl63o/ -o ./output/abc.pb -m pb -h true -i true
node ./bin/jarviscrawler.js exparticle https://zhuanlan.zhihu.com/p/60881398 -o ./output/abc.pdf -m pdf -h true -i true -q true
node ./bin/jarviscrawler.js exparticle https://www.zhihu.com/question/295675918/answer/600007589 -o ./output/abc.pdf -m pdf -h true -i true -q true
node ./bin/jarviscrawler.js exparticle https://36kr.com/p/5191170 -o ./output/abc.pdf -m pdf -h true -i true -q true
node ./bin/jarviscrawler.js exparticle http://www.baijingapp.com/article/22290 -o ./output/abc.pdf -m pdf -h true -i true
node ./bin/jarviscrawler.js exparticle https://www.huxiu.com/article/292563.html -o ./output/abc.pdf -m pdf -h true -i true
node ./bin/jarviscrawler.js exparticle https://www.tmtpost.com/3859873.html -o ./output/abc.pdf -pdf -h true -i true
node ./bin/jarviscrawler.js exparticle https://www.geekpark.net/news/240120 -o ./output/abc.pdf -pdf -h true -i true
node ./bin/jarviscrawler.js exparticle https://www.lieyunwang.com/archives/453240 -o ./output/abcdf -m pdf -h true -i true
```
### 2019-03-29
今天加了confluence的bot,现在可以获取更新。
```
node ./bin/jarviscrawler.js confluencebot ./cfg/confluence.yaml -h false
```
### 2019-03-28
这几天还在考虑数据存储到底是用``html``还是``markdown``,``html``的格式化现在做得差不多了,但如果最后要自己渲染的话,``markdown``其实还是有些优势的,特别是代码段这些,会方便很多。
今天支持了smzdm,发现几个新的问题,包括当前页面请求图片可能也会出现跨域问题(#15),和images库对图片格式支持不全(#16)。
```
node ./bin/jarviscrawler.js exparticle https://post.smzdm.com/p/alpzl63o/ -o ./output/abc.pb -p ./output/abc.pdf -f A4 -h true
```
今天还支持了知乎,解决了CSP的问题,解决了jquery加载的问题,解决了图片延迟加载的问题。
```
node ./bin/jarviscrawler.js exparticle https://zhuanlan.zhihu.com/p/59909721 -o ./output/abc. -p output/abc.pdf -f A4 -h true
```
### 2019-03-27
今天把``exparticle``重构了一版,这个版本功能基本能达到目前的需求了。
数据没有用``json``的,而是直接用了``protobuf``,支持未压缩的文件和zip压缩文件,把图片打包进去了。
今天把baijingapp的处理完了,可以通过下面命令行使用。
```
node ./bin/jarviscrawler.js exparticle http://www.baijingapp.com/article/22156 -p ./output/abc.pdf -f A4 -h true -o ./output/abc.pb
```
今天晚上把huxiu也处理完了,huxiu的代码质量更好一些,这个可以作为后续的样板。
```
node ./bin/jarviscrawler.js exparticle https://www.huxiu.com/article/291141.html -o ./output/abc.pb -p ./output/abc.pdf -f A4 -h true
```
### 2019-03-26
关于puppeteer,留点记录。
首先,``$()``和``$eval()``是不一样的,``$()``返回一个nodejs对象,``$eval()``其实是做页面操作,而且``$eval()``里面的输出也在浏览器里面。
还有点需要注意的,就是``$eval()``的返回值是你自己控制的,可以用来传递跨域对象。
如果需要加载页面以外的js,可以用
``` js
// url
await page.addScriptTag({url: 'https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/index.js'});
// local file
await page.addScriptTag({path: './browser/base64.js'});
```
运行js代码,用``page.evaluate``,这个里面是页面的js空间,类似chrome控制台操作,这个函数的返回值是你自己控制的,可以用来传递js对象。
页面可以用``fetch``取数据,没有跨域问题。
```
const response = await fetch(curimg[0].src);
```
返回是一个``ReadableStream``,可以转``arrayBuffer``、``json``、``text``等。
关于``chrome``和``nodejs``层变量传递问题,``ArrayBuffer``是传不过来的,可以通过``base64``以后传``string``。
### 2019-03-25
今天发现知乎的图片是延迟加载的,本来想到的是移动屏幕,等加载完就好,后来看别人提了个思路,是直接改img的css,改成直接加载就好,可以试试。
### 2019-03-20
今天把Docker部署完成了,最折腾的其实是字体问题,最后找到了Adobe的SourceHanSans,看起来效果还不错。
### 2019-03-19
这算是第3次写爬虫框架了,现在各种基础库比上次写的时候要完善很多,希望这次能做出点东西来。
现在几乎完全基于puppeteer的,轻量级的后面如果有需要再加。
核心是插件系统。
接下来应该还会做开放的插件管理器,就是不放代码库里的插件。