网页截图服务的实现

创建:xiaozi · 最后修改:xiaozi 2019-07-27 16:25 ·

背景目标

这个需求来源于码农文库,码农文库是一个可以在线分享好文章的地方,但是部分文章的网址在分享之后一段时间之后就失效了, 那这个时候再想看到文章的内容就会比较困难,所以得想个办法对网页做个快照。

功能分析

功能 描述

截图工具选择

选择支持好,更新活跃的截图工具

中文乱码问题

解决Linux下缺少中文字体,造成的网页中文无法正常显示的问题

加载超时处理

对于网页加载时间比较长的网页,可以放弃截图

Socks5代理

由于特殊的国情,有些网页需要翻墙才能访问,要截图首先得能访问这个网页

被墙域名白名单

只有被墙的域名才需要走代理,正常的url正常访问就可以了

危险网址域名黑名单

如果这个截图服务是对外提供的,难免会有一些黑客想要通过我们的程序去访问一些有问题的网页,以便发现一些漏洞,进而侵入我们的网站

禁止文件下载

如果这个截图服务是对外提供的,如果有人恶意的输入一些大文件的url地址,而这些文件的下载可以打满服务的网卡,造成服务的不可用

详细设计

流程图

截图服务流程图

linux下安装中文字体

通常情况下,服务器版的linux默认都没有安装中文字体,对网页进行截图的话,会发现中文都是一个个的方块

cd /usr/share/fonts/default/
# 把STHeiTi放到stheiti目录下
# mkfontscale
# mkfontdir
fc-cache -fv

# 查看所有字体
fc-list
# 查看匹配字体
fc-match "sans-serif"

截图工具的选择

特性 PhantomJS Chrome headless

webkit内核更新

x

更新活跃度

x

由于 Chrome headless 出来的比较晚,之前我选择了 Phantomjs;不过下面两个都会讲一下

安装 Phantomjs

# 安装Phantomjs相对比较简单,只要下载已经编译好的文件,解压就可以了
wget https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-2.1.1-linux-x86_64.tar.bz2
tar jxf phantomjs-2.1.1-linux-x86_64.tar.bz2
mv phantomjs-2.1.1-linux-x86_64 /usr/local/phantomjs

使用 Phantomjs 截图

这里我们借助 casperjs 来调用

var fs = require('fs');

var casper = require('casper').create({
	verbose: true,
	logLevel: "debug",
	stepTimeout: 1 * 60 * 1000,
	pageSettings: {
		userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.94 Safari/537.36" // 1280x800
	}
});

var url = casper.cli.get('url');
url = url || 'http://tool.lu/';
var device = casper.cli.get('device');
var target = casper.cli.get('target');
var viewport = {width: 1280, height: 800};

switch (device) {
	case 'weibo':
		viewport = {width: 440, height: 10};
	break;
	case 'iphone':
		viewport = {width: 640, height: 960};
	break;
}

casper.start().viewport(viewport.width, viewport.height).thenOpen(url, function () {
	this.capture(target);
	this.echo(JSON.stringify({url: this.getCurrentUrl(), target : target}));
});

casper.run();

安装 Chrome headless

npm i puppeteer --save

# 如果不出意外的话,是安装不成功的;root用户也会提示权限不足; 执行下面的命令就可以了,然后再安装
npm i puppeteer --unsafe-perm --save

使用 Chrome headless 截图

这里我们使用官方提供的puppeteer来调用

const puppeteer = require('puppeteer');

async function run() {
  // {args:['--proxy-server=socks5://127.0.0.1:9050','--no-sandbox','--disable-setuid-sandbox']}
  const browser = await puppeteer.launch({args: ['--no-sandbox']});
  const page = await browser.newPage();

  // await page.setViewport({width: 1280,height: 800});
  await page.setViewport({width: 1440,height: 900});
  await page.goto('https://tool.lu/', {waitUntil: 'load'});
  await page.screenshot({path: 'screenshot.png', fullPage: true});

  browser.close();
}

run();

搭建代理

PhantomJS 和 Chrome headless 都支持Socks5代理, 所以这里就直接搭建 ShadowSocks 来实现部分需要翻墙网址的截图

165622vm9iCt0wZwOMS78l 521x121

pip install shadowsocks

国外服务器上执行

server.json
{
	"server" : "0.0.0.0",
	"server_port" : 11712,
	"password" : "你的密码",
	"timeout" : 60,
	"method" : "aes-256-cfb"
}
sserver -c server.json

截图服务器上执行

jp.json
{
	"server":"你的国外服务器地址",
	"server_port":11712,
	"local_address":"127.0.0.1",
	"local_port":8016,
	"password":"你的密码",
	"timeout":60,
	"method":"aes-256-cfb"
}
sslocal -c jp.json

Phantomjs 使用代理

LC_CTYPE=en_US.UTF-8 PATH=/usr/local/phantomjs/bin:/usr/bin /usr/local/node/lib/node_modules/casperjs/bin/casperjs --proxy=127.0.0.1:8016 --proxy-type=socks5 --ssl-protocol=any --ignore-ssl-errors=true /data/jobs/webshot/webshot.js

Chrome headless 使用代理

const browser = await puppeteer.launch({
    args: ['--proxy-server=socks5://127.0.0.1:8016']
});

翻墙域名白名单

代理搭建好了,也能用了;但是不是所有的url都需要通过代理来访问,这个时候就需要一个域名白名单来决定哪些域名走代理

危险域名网址黑名单

可以直接使用这个开源项目,netxfly/xsec-ip-database

其他

网页截图是个相对比较耗时的操作,如果有大量的恶意请求过来,机器的CPU占用会很高;可以采用放入MQ的方式,让机器自己的消费能力来决定机器的负载

2019-12-14 更新

新的截图服务


浏览 24710 次

首页 - Wiki
Copyright © 2011-2024 iteam. Current version is 2.139.0. UTC+08:00, 2024-12-27 04:26
浙ICP备14020137号-1 $访客地图$