<?php

    /**
     * 将字符串中编码的emoji字符还原
     * @param $text
     * @return string
     */
    function decodeEmoji($text)
    {
        $content = $text;
        if (preg_match_all("/(\[\:[^\]]+\])/", $content, $match)) {
            foreach ($match[1] as $k=>$str) {
                $str2 = '"' . str_replace(['[', ']', ':'], ['', '', '\\'], $str) . '"';
                $content = str_replace($str, json_decode($str2), $content);
            }
            return $content;
        }
        return $text;
    }

    /**
     * 将字符串中的emoji字符编码
     * @param $text
     * @return string
     */
    function encodeEmoji($text)
    {
        $content = '';
        foreach (preg_split("//u", $text, null, PREG_SPLIT_NO_EMPTY) as $v) {
            $content .= strlen($v)==4 ? '['.str_replace(['\\','"'], [':',''], json_encode($v)).']' : $v;
        }
        return $content;
    }

windows中是自带的,不用安装,直接在cmd窗口直接使用
ctrl+r,运行cmd,直接使用

nslookup 命令是 bind-utils 包的一部分
要想安装 nslookup, 直接安装 bind-utils 即可
centos7:

yum install -y bind-utils

如何使用:
nslookup baidu.com

查询指定某个类型的解析
nslookup的语法为(注意qt必须小写)
nslookup –qt=类型 目标域名

类型主要有:
A 地址记录(Ipv4)
AAAA 地址记录(Ipv6)
CNAME 别名记录
HINFO 硬件配置记录,包括CPU、操作系统信息
ISDN 域名对应的ISDN号码
MB 存放指定邮箱的服务器
MG 邮件组记录
MINFO 邮件组和邮箱的信息记录
MR 改名的邮箱记录
MX 邮件服务器记录
NS 名字服务器记录
PTR 反向记录
RP 负责人记录
SRV TCP服务器信息记录
TXT 域名对应的文本信息
如何使用指定DNS服务器查询?

语法为 nslookup -qt=类型 目标域名 指定的DNS服务器IP或域名
如果你要查询www.jsons.cn的A记录,那在命令符提示窗口输入:nslookup -qt=a www.jsons.cn的 则可以查到相应的记录

例子:nslookup -qt=A www.jsons.cn 8.8.8.8

.btn.loading{
    white-space: nowrap;
}
.btn.loading:before {
    content: "";
    background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABAUlEQVQ4T6WTMUoDURRFz9mEYGcdK8E+7sBKwdImvbiAKFgJgq3prASzCe0VLFSw0kJwBYLdlR/+SAwZxsTfDPx57865d96Tfx7n9ScZAmvqfpJT4FM9nlf7SyDJFvACnAF7qklegTvgEjgERupVIzYrEOBo+mtJCslbkgtgAByo520Cq+pHWyyVsA+sACeldkKQ5Lo81d2uTJM8AuvAhvowN8Q/iGwD9+p7QzBQR12NlbYHPFXiScrloljYVL+6REqoQPkzxbINQU997mpunYNKURQXFvkhqEjLCTRoSfrq7SJWZidx2Dbz1ebO7Pu2ZSo7UTK5qYs1bstnqUGatvgN8r9sEdrr9W0AAAAASUVORK5CYII=);
    background-position: left center;
    background-repeat: no-repeat;
    width: 1em;
    height: 1em;
    display: inline-block;
    margin-right: 3px;
    vertical-align: text-bottom;
    animation: spin 1s infinite linear;
}
@keyframes spin {
    from { transform: rotate(0deg); }
    to { transform: rotate(360deg); }
}

原文:https://juejin.cn/post/6977636149300822046

Splash是Scrapy官方推荐的JavaScript渲染引擎,它是使用Webkit开发的轻量级无界面浏览器,提供基于HTTP接口的JavaScript渲染服务,支持以下功能:

为用户返回经过渲染的HTML页面或页面截图。
并发渲染多个页面。
关闭图片加载,加速渲染。
在页面中执行用户自定义的JavaScript代码。
执行用户自定义的渲染脚本(lua),功能类似于PhantomJS。

安装并开启splash服务

docker中安装Splash

sudo docker pull scrapinghub/splash

在本机的8050和8051端口开启Splash服务:

sudo docker run -p 8050:8050 -p 8051:8051 scrapinghub/splash

查看容器是否启动:

docker ps -a

Splash功能丰富,包含多个服务端点,这里只介绍其中两个最常用的端点:

render.html提供JavaScript页面渲染服务。
execute执行用户自定义的渲染脚本(lua),利用该端点可在页面中执行JavaScript代码。

Splash文档地址。
splash脚本
Splash服务开启成功后,浏览器打开http://localhost:8050/,如图:

可以直接在这个页面lua_script是否可用,例如:
demo:渲染的url通过参数传进去

function main(splash, args)
  assert(splash:go(args.url))
  assert(splash:wait(0.5))
  return {
    html = splash:html(),
    png = splash:png(),
    har = splash:har(),
  }
end

runjs定义一个函数,并且使用evaljs运行这个函数

function main(splash, args)
    splash:go(args.url)
    splash:runjs("foo = function() { return 'bar' }")
    local result = splash:evaljs("foo()")
    return result
end

在浏览器模拟打开拉钩网站,取搜索框的值赋值给result1,模拟搜索框输入关键系”python“,再取搜索框的值赋值result2,模拟点击搜索按钮,跳转页面。

function main(splash, args)
    splash:go("http://www.lagou.com")
    splash:wait(2)
    splash:runjs("document.querySelector('a.tab.focus').click()")
    splash:wait(2)
    splash:runjs("getValue = function() { return document.querySelector('#search_input').value }")
    local result1 = splash:evaljs("getValue()")
    splash:runjs("keyboardInput = function (dom, st) {let evt = document.createEvent('HTMLEvents');evt.initEvent('input', true, true); dom.value = st; dom.dispatchEvent(evt);}")
    splash:evaljs("keyboardInput(document.querySelector('#search_input'), 'python')")
    local result2 = splash:evaljs("getValue()")
    splash:evaljs("document.querySelector('#search_button').click()")
    splash:wait(5)
    return {
        result1 = result1,
        result2 = result2,
        png = splash:png(),
        html = splash:html(),
    }
end

拉勾模拟用户登陆,打开用户登陆的弹窗,分别在用户名和密码的输入框输入真实的用户名密码。再模拟点击登陆按钮

args.url = "www.lagou.com/jobs/list_p…"
function main(splash, args)
    splash:go(args.url)
    splash:wait(3)
      splash:evaljs("document.querySelector('.login-pop').style.display = 'block'")
    splash:runjs("getValue = function() { return document.querySelector('input.input.login_enter_password').value }")
    splash:runjs("keyboardInput = function (dom, st) {let evt = document.createEvent('HTMLEvents');evt.initEvent('input', true, true); dom.value = st; dom.dispatchEvent(evt);}")
    splash:evaljs("keyboardInput(document.querySelector('input.input.login_enter_password'), '136****4534')")
      splash:evaljs("keyboardInput(document.querySelector('input[type=password].input.login_enter_password'), '12345678')")
    splash:evaljs("document.querySelector('div.login-btn.login-password').click()")
    splash:wait(2)
    return {
        text = text,
        result1 = result1,
        png = splash:png(),
    }
end

shell中使用splash脚本
建议在shell脚本中复制粘贴示例代码,因为在vscode中直接运行没有返回值
实例1 :render.html端点
使用requests库调用render.html端点服务对页面 quotes.toscrape.com/js/ 进行渲染的示例代码 。
在终端中进入python的编译环境,输入以下代码

import requests
from scrapy.selector import Selector

splash_url = 'http://localhost:8050/render.html'
args = {'url': 'http://quotes.toscrape.com/js', 'timeout': 60, 'image': 0}

response = requests.get(splash_url, params=args)

sel = Selector(response)
sel.css('div.quote span.text::text').extract()

运行成功后即取到了页面上的名人名言,运行结果如图

实例2:execute端点
在爬取某些页面时,我们想在页面中执行一些用户自定义的JavaScript代码,例如,用JavaScript模拟点击页面中的按钮,或调用页面中的JavaScript函数与服务器交互,利用Splash的execute端点提供的服务可以实现这样的功能。

splash_execute脚本:利用Splash的execute端点提供的服务可以实现在页面中执行一些用户自定义JavaScript代码自定义的功能

下面是使用requests库调用execute端点服务的示例代码。

import requests
import json

# 这段脚本需要在命令行运行
lua_script = '''
function main(splash)
    splash:go("http://quotes.toscrape.com") --打开页面
    splash:wait(0.5) --等待时间
    local title = splash:evaljs("document.title") --执行js代码获取结果
    return {title = title} --返回json形式的结果
    end
'''

splash_url = 'http://localhost:8050/execute'
headers={'content-type':'application/json', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36'}
data = json.dumps({'lua_source':lua_script})
# args = {'url': 'http://quotes.toscrape.com/js', 'timeout': 60, 'image': 0}

response = requests.post(splash_url, headers=headers, data=data)
response.content

response.json()

运行结果如图:

在Scrapy中使用Splash
在Scrapy中调用Splash服务需要用到Python库的scrapy-splash

pip install scrapy-splash
创建一个Scrapy项目,取名为splash_examples:
scrapy startproject quotes
首先在项目配置文件settings.py中对scrapy-splash进行配置,添加内容如下:
# Splash服务器地址
SPLASH_URL = 'http://localhost:8050'

# 开启Splash的两个下载中间件并调整HttpCompressionMiddleware的次序
DOWNLOADER_MIDDLEWARES = {
   'scrapy_splash.SplashCookiesMiddleware': 723,
   'scrapy_splash.SplashMiddleware': 725,
   'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810,
}

# 设置去重过滤器
DUPEFILTER_CLASS = 'scrapy_splash.SplashAwareDupeFilter'

# 用来支持cache_args(可选)
SPIDER_MIDDLEWARES = {
    'scrapy_splash.SplashDeduplicateArgsMiddleware': 100
}

编写Spider代码过程中,使用scrapy_splash调用Splash服务非常简单,scrapy_splash中定义了一个SplashRequest类,用户只需使用scrapy_splash.SplashRequest(替代scrapy.Request)提交请求即可。
实战一:爬取toscrape中的名人名言
创建一个quote的爬虫
scrapy genspider quote quotes.toscrape.com
在这个案例中,我们只需使用Splash的render.html端点渲染页面,再进行爬取即可实现QuoteSpider,具体代码见
spiders/quote.py。

import scrapy
from scrapy_splash import SplashRequest

class QuoteSpider(scrapy.Spider):
    name = 'quote'
    allowed_domains = ['quotes.toscrape.com']
    start_urls = ['http://quotes.toscrape.com/js/']

    def start_requests(self):
        for url in self.start_urls:
            yield SplashRequest(url, args={'images':0, 'timeout': 30})

    def parse(self, response):
        for sel in response.css('div.quote'):
            quote = sel.css('span.text::text').extract_first()
            author= sel.css('small.author::text').extract_first(),
            # tags= sel.css('.tag::text').extract()
            yield {'quote':quote,'author':author}
            href = response.css('li.next > a::attr(href)').extract_first()
            if href:
                url = response.urljoin(href)
                yield SplashRequest(url, args = {'images': 0, 'timeout': 30})

运行这个爬虫并保存文件

scrapy crawl quote -o quote.csv
​```
可以看到成功获取了网站下的名人名言。
实战二:爬取京东商城中的书籍信息
在京东商城中的书籍列表使用了动态渲染方式,即页面中的60本书不是同时加载的,开始只有30本书,当我们使用鼠标滚轮滚动到页面下方某位置时,后30本书才由JavaScript脚本加载。
既然如此,爬取这个页面时,可以先执行一段JavaScript代码,将滚动条拖到页面下方某位置,触发加载后30本书的事件
创建一个jdbook的爬虫:

scrapy genspider jdbook search.jd.com

经上述分析,在爬取每一个书籍列表页面时都需要执行一段JavaScript代码,以让全部书籍加载,因此选用execute端点完成该任务,实现JDBookSpider代码见spiders/jdbook.py。
​```
import scrapy
from scrapy import Request
from scrapy_splash import SplashRequest

lua_script = '''
function main(splash)
    splash:go(splash.args.url)
    splash:wait(2)
    splash:runjs("document.getElementsByClassName('page')[0].scrollIntoView(true)")
    splash:wait(2)
    return splash:html()
end
'''

class JdbookSpider(scrapy.Spider):
    name = 'jdbook'
    # allowed_domains = ['search.jd.book']
    base_url = 'https://search.jd.com/Search?keyword=python&enc=utf-8&wq=python'

    def start_requests(self):
        yield Request(self.base_url, callback=self.parse_urls, dont_filter=True)

    def parse_urls(self, response):
        # 获取商品总数,计算出总页数
        # total = int(response.css('span#J_resCount::text').extract_first())
        # pageNum = total // 60 + (1 if total % 60 else 0)
        # pageNum = response.css('.fp-text i::text').extract_first() || 100
        pageNum = 10

        # 构造每页的url,向Splash的execute端点发送请求
        for i in range(pageNum):
            url = '%s&page=%s' % (self.base_url, 2*i+1)
            yield SplashRequest(url, 
                endpoint='execute', 
                args={'lua_source': lua_script},
                cache_args=['lua_source'])

    def parse(self, response):
        # 获取一个页面中每本书的名字和价格
        for sel in response.css('ul.gl-warp.clearfix > li.gl-item'):
            yield {
                'name': sel.css('div.p-name').xpath('string(.//em)').extract_first(),
                'price': sel.css('div.p-price i::text').extract_first(),
            }

运行这个爬虫并保存文件

scrapy crawl jdbook -o books.csv
​```

背景
安装了node后,执行npm run xxx的命令的时候,报错,提示如下:

/usr/bin/env: node: No such file or directory

解决步骤

ln -s /usr/bin/nodejs /usr/bin/node

推测因为npm执行的时候默认是使用/usr/bin/node去执行的,但我本地是没有/usr/bin/node的,所以需要创建一个
所以需要创建一个软连接将自己的node的执行文件指到/usr/bin/node上,于是修改如下:

ln -s /usr/local/NODEJS_HOME/bin/node /usr/bin/node

再执行,果然成功了