Linux 环境Django框架安装及项目创建

pip 命令安装方法

如果你还未安装 pip 工具,可查看 http://www.goonls.com/?p=1824

pip install Django -i https://pypi.tuna.tsinghua.edu.cn/simple --trusted-host pypi.tuna.tsinghua.edu.cn
[root@198e6d7f2d48 home]# django-admin startproject web
bash: django-admin: command not found

cp /usr/local/python3.8.3/bin/django-admin /usr/bin/django-admin
django-admin startproject web
python manage.py runserver

[root@198e6d7f2d48 web]# python manage.py runserver
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).

You have 17 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.

July 15, 2020 - 03:44:52
Django version 3.0.8, using settings 'web.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

python manage.py migrate

如何使用Docker 快速创建一个mysql服务

#拉取mysql docker 镜像 这里选择mysql5.6版本
#https://hub.docker.com/_/mysql

docker pull mysql:5.6
docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d -p 3310:3306 mysql:5.6
IP:自己服务器IP
PORT:3310
USER:root
PASS:my-secret-pw

这里some-mysql是要分配给容器的名称,my-secret-pw是要为MySQL根用户设置的密码,并且tag是指定所需MySQL版本的标记。请参阅上面的列表以获取相关标签。

我这里使用的是3310端口指向docker容器3306端口,原因:因为我的服务已经安装mysql且占用3306端口,所以新创建的数据库使用3310端口去连接

可能遇到的问题:如果你无法连接数据库,请检查服务器安全策略是否开放对应端口或服务器防火墙限制

php 测试题

<?php 
   static $num = 3;
   echo $num;exit;
   static $num=5;
?> 
<?php 
   $num = 3;
   echo $num;exit;
   static $num=5;
?> 
<?php 
function myTest(){
   static $num = 3;
   echo $num;exit;
   static $num=5;

  }
myTest();
?> 
<?php 
function myTest(){
    $num = 3;
   echo $num;exit;
   static $num=5;

  }
myTest();
?> 

deepin切换root身份运行

默认禁用root帐户,需要加密码才能用。sudo passwd root可以设置root密码或者打开终端(即Terminal) 输入sudo -s -H 也行。注意H 一定要是大写。这样可以直接进入root

Google Translate 谷歌翻译API 使用教程之PHP

Google Translate

Translation
利用 Google 机器学习技术在多种语言之间动态互译
根据您的内容需求提供快速、动态的翻译
Translation 服务让组织能够利用 Google 预先训练或自定义的机器学习模型,在多种语言之间动态互译。

官方地址: https://cloud.google.com/translate/#section-1

准备工作

设置 Cloud Console 项目。
设置项目 https://cloud.google.com/translate/docs/basic/setup-basic

点击即可执行以下操作:

创建或选择项目。
为该项目启用 Cloud Translation API。
创建服务帐号。
下载 JSON 格式的私钥。
您可以随时在 Cloud Console 中查看和管理这些资源。https://console.cloud.google.com

1.创建项目

2.您需要为此项目提供一个计费帐户,然后才能激活该服务。 访问API控制台以配置结算帐户,然后返回此处继续操作。

3.下载秘钥

4.为项目开启API功能

5.搜索需要开启的API类型

6.创建API Key

安装与使用

安装 Cloud Translation 基本版客户端库

客户端库支持多种主流语言,建议您使用这些客户端库。如需安装客户端库,请执行以下操作:

composer install google/cloud-translate

php 使用方法

use Google\Cloud\Translate\V2\TranslateClient;

调用示例

#实例化翻译类
$translate = new TranslateClient([
      'key' => 'AIzaSyCkSxy7UtjwXaBg5-hLWk0FnSWXXXXXXXXXX'
]);
// Translate text from english to french.
$result = $translate->translate('Get the languages supported for translation specifically for your target language.', 
[
        'source' => 'en',//默认EN,不设置自动检测原始语言
        'target' => 'zh-CN'
]);

echo $result['text'] . "\n";
// Detect the language of a string.
$result = $translate->detectLanguage('Greetings from Michigan!');

echo $result['languageCode'] . "\n";
// Get the languages supported for translation specifically for your target language.
$languages = $translate->localizedLanguages([
    'target' => 'en'
]);

foreach ($languages as $language) {
    echo $language['name'] . "\n";
    echo $language['code'] . "\n";
}
// Get all languages supported for translation.
$languages = $translate->languages();

foreach ($languages as $language) {
    echo $language . "\n";
}


输出: af am ar az be bg bn bs ca ceb co cs cy da de el en eo es et eu fa fi fr fy ga gd gl gu ha haw he hi hmn hr ht hu hy id ig is it iw ja jw ka kk km kn ko ku ky la lb lo lt lv mg mi mk ml mn mr ms mt my ne nl no ny or pa pl ps pt ro ru rw sd si sk sl sm sn so sq sr st su sv sw ta te tg th tk tl tr tt ug uk ur uz vi xh yi yo zh zh-CN zh-TW zu

使用TCP/IP协议栈指纹进行远程操作系统辨识 主动识别、被动识别

在做亚马逊爬虫的时候,亚马逊的屏蔽规则让人费解,传统的模拟浏览器请求header、cookie,换IP对亚马逊反爬虫策略并不能完全解释清楚,还存在其他的反爬虫策略,因为亚马逊并不会完全封禁IP,隔断时间会被解封,这样将牺牲一部分用户群体。

困惑产生原因:

1.相同IP、同样的抓取方式,在linux操作系统下面抓取数据已经被封闭,换成windows操作系统时却可以正常抓取数据

2.linux操作系统,通过docker 安装centos ubuntu 蝶变 等操作系统及不同版本,采用相同抓取方式,别封禁的情况截然不同,有些正常抓取,有些被封了,他们的出网ip相同,为什么会存在这种情况?

猜想:难道亚马逊可以识别到服务器与docker容器里面的网卡MAC地址?亦或者能识别我们的操作系统类型及版本号?

最开始错误思虑:http请求时,伪造 User-Agent:windows操作系统,他应该识别到的只能是windows操作系统呀!

User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36 

当然这个问题被放了,没有再做过多的思考,毕竟对当时TCP/IP传输协议了解甚少

。。。。。。。。

几个月后

心血来潮

查阅很多资料

发现

协议栈指纹

协议栈指纹识别是一项强大的技术,能够以很高的概率迅速确定操作系统的版本。虽然TCP/IP协议栈的定义已经成为一项标准,但是各个厂家,如微软和RedHat等在编写自己的TCP/IP协议栈时,却做出了不同的解释。这些解释因具有独一无二的特性,故被称为“指纹”。通过这些细微的差别,可以准确定位操作系统的版本。

TCP/IP堆栈指纹识别作为一种识别准确率很高的技术,被广泛1653运用于nmaP,p0f等著名安全检测工具中。TCP/IP堆栈指纹识别分为两种,即主动识别和被动识别。

p0f 被动识别工具

#安装
yum install p0f
[root@izwz9bb1rjtnk ~]# p0f -h
--- p0f 3.09b by Michal Zalewski <lcamtuf@coredump.cx> ---

p0f: invalid option -- 'h'
Usage: p0f [ ...options... ] [ 'filter rule' ]

Network interface options:

  -i iface  - listen on the specified network interface
  -r file   - read offline pcap data from a given file
  -p        - put the listening interface in promiscuous mode
  -L        - list all available interfaces

Operating mode and output settings:

  -f file   - read fingerprint database from 'file' (/etc/p0f/p0f.fp)
  -o file   - write information to the specified log file
  -s name   - answer to API queries at a named unix socket
  -u user   - switch to the specified unprivileged account and chroot
  -d        - fork into background (requires -o or -s)

Performance-related options:

  -S limit  - limit number of parallel API connections (20)
  -t c,h    - set connection / host cache age limits (30s,120m)
  -m c,h    - cap the number of active connections / hosts (1000,10000)

Optional filter expressions (man tcpdump) can be specified in the command
line to prevent p0f from looking at incidental network traffic.

Problems? You can reach the author at <lcamtuf@coredump.cx>.
监听 eth0 网卡 443端口 将日志写入p0f3.log
p0f -f /etc/p0f/p0f.fp -o ./p0f3.log -i eth0  'port 443'
#输出
.-[ 172.18.37.42/53464 -> 163.177.83.164/443 (syn) ]-
|
| client   = 172.18.37.42/53464
| os       = Linux 3.11 and newer
| dist     = 0
| params   = none
| raw_sig  = 4:64+0:0:1460:mss*20,7:mss,sok,ts,nop,ws:df,id+:0
|
`----

.-[ 172.18.37.42/53464 -> 163.177.83.164/443 (mtu) ]-
|
| client   = 172.18.37.42/53464
| link     = Ethernet or modem
| raw_mtu  = 1500
|
`----

.-[ 172.18.37.42/53464 -> 163.177.83.164/443 (syn+ack) ]-
|
| server   = 163.177.83.164/443
| os       = Linux 3.x
| dist     = 12
| params   = tos:0x05
| raw_sig  = 4:52+12:0:1440:mss*10,7:mss,nop,nop,sok,nop,ws:df:0
|
`----

.-[ 172.18.37.42/53464 -> 163.177.83.164/443 (mtu) ]-
|
| server   = 163.177.83.164/443
| link     = IPIP or SIT
| raw_mtu  = 1480
|
`----

.-[ 222.131.36.189/50664 -> 172.18.37.42/443 (syn) ]-
|
| client   = 222.131.36.189/50664
| os       = Mac OS X
| dist     = 12
| params   = generic fuzzy tos:0x05
| raw_sig  = 4:52+12:0:1420:65535,7:mss,nop,ws,nop,nop,ts,sok,eol+1:df,ecn:0
|
`----

发送http请求到测试服务器,虽然User-Agent伪装windows操作系统,但是通过栈指纹还是可以识别到请求操作系统类型,感觉像是掩耳盗铃,所以通过栈指纹来反爬虫却成为一件很容易的事情。这是亚马逊反爬虫的策略之一。

主动栈指纹识别

#安装
yum install nmap
#帮助文档
[root@root ~]# nmap -h
Nmap 6.40 ( http://nmap.org )
Usage: nmap [Scan Type(s)] [Options] {target specification}
TARGET SPECIFICATION:
  Can pass hostnames, IP addresses, networks, etc.
  Ex: scanme.nmap.org, microsoft.com/24, 192.168.0.1; 10.0.0-255.1-254
  -iL <inputfilename>: Input from list of hosts/networks
  -iR <num hosts>: Choose random targets
  --exclude <host1[,host2][,host3],...>: Exclude hosts/networks
  --excludefile <exclude_file>: Exclude list from file
HOST DISCOVERY:
  -sL: List Scan - simply list targets to scan
  -sn: Ping Scan - disable port scan
  -Pn: Treat all hosts as online -- skip host discovery
  -PS/PA/PU/PY[portlist]: TCP SYN/ACK, UDP or SCTP discovery to given ports
  -PE/PP/PM: ICMP echo, timestamp, and netmask request discovery probes
  -PO[protocol list]: IP Protocol Ping
  -n/-R: Never do DNS resolution/Always resolve [default: sometimes]
  --dns-servers <serv1[,serv2],...>: Specify custom DNS servers
  --system-dns: Use OS's DNS resolver
  --traceroute: Trace hop path to each host
SCAN TECHNIQUES:
  -sS/sT/sA/sW/sM: TCP SYN/Connect()/ACK/Window/Maimon scans
  -sU: UDP Scan
  -sN/sF/sX: TCP Null, FIN, and Xmas scans
  --scanflags <flags>: Customize TCP scan flags
  -sI <zombie host[:probeport]>: Idle scan
  -sY/sZ: SCTP INIT/COOKIE-ECHO scans
  -sO: IP protocol scan
  -b <FTP relay host>: FTP bounce scan
PORT SPECIFICATION AND SCAN ORDER:
  -p <port ranges>: Only scan specified ports
    Ex: -p22; -p1-65535; -p U:53,111,137,T:21-25,80,139,8080,S:9
  -F: Fast mode - Scan fewer ports than the default scan
  -r: Scan ports consecutively - don't randomize
  --top-ports <number>: Scan <number> most common ports
  --port-ratio <ratio>: Scan ports more common than <ratio>
SERVICE/VERSION DETECTION:
  -sV: Probe open ports to determine service/version info
  --version-intensity <level>: Set from 0 (light) to 9 (try all probes)
  --version-light: Limit to most likely probes (intensity 2)
  --version-all: Try every single probe (intensity 9)
  --version-trace: Show detailed version scan activity (for debugging)
SCRIPT SCAN:
  -sC: equivalent to --script=default
  --script=<Lua scripts>: <Lua scripts> is a comma separated list of 
           directories, script-files or script-categories
  --script-args=<n1=v1,[n2=v2,...]>: provide arguments to scripts
  --script-args-file=filename: provide NSE script args in a file
  --script-trace: Show all data sent and received
  --script-updatedb: Update the script database.
  --script-help=<Lua scripts>: Show help about scripts.
           <Lua scripts> is a comma separted list of script-files or
           script-categories.
OS DETECTION:
  -O: Enable OS detection
  --osscan-limit: Limit OS detection to promising targets
  --osscan-guess: Guess OS more aggressively
TIMING AND PERFORMANCE:
  Options which take <time> are in seconds, or append 'ms' (milliseconds),
  's' (seconds), 'm' (minutes), or 'h' (hours) to the value (e.g. 30m).
  -T<0-5>: Set timing template (higher is faster)
  --min-hostgroup/max-hostgroup <size>: Parallel host scan group sizes
  --min-parallelism/max-parallelism <numprobes>: Probe parallelization
  --min-rtt-timeout/max-rtt-timeout/initial-rtt-timeout <time>: Specifies
      probe round trip time.
  --max-retries <tries>: Caps number of port scan probe retransmissions.
  --host-timeout <time>: Give up on target after this long
  --scan-delay/--max-scan-delay <time>: Adjust delay between probes
  --min-rate <number>: Send packets no slower than <number> per second
  --max-rate <number>: Send packets no faster than <number> per second
FIREWALL/IDS EVASION AND SPOOFING:
  -f; --mtu <val>: fragment packets (optionally w/given MTU)
  -D <decoy1,decoy2[,ME],...>: Cloak a scan with decoys
  -S <IP_Address>: Spoof source address
  -e <iface>: Use specified interface
  -g/--source-port <portnum>: Use given port number
  --data-length <num>: Append random data to sent packets
  --ip-options <options>: Send packets with specified ip options
  --ttl <val>: Set IP time-to-live field
  --spoof-mac <mac address/prefix/vendor name>: Spoof your MAC address
  --badsum: Send packets with a bogus TCP/UDP/SCTP checksum
OUTPUT:
  -oN/-oX/-oS/-oG <file>: Output scan in normal, XML, s|<rIpt kIddi3,
     and Grepable format, respectively, to the given filename.
  -oA <basename>: Output in the three major formats at once
  -v: Increase verbosity level (use -vv or more for greater effect)
  -d: Increase debugging level (use -dd or more for greater effect)
  --reason: Display the reason a port is in a particular state
  --open: Only show open (or possibly open) ports
  --packet-trace: Show all packets sent and received
  --iflist: Print host interfaces and routes (for debugging)
  --log-errors: Log errors/warnings to the normal-format output file
  --append-output: Append to rather than clobber specified output files
  --resume <filename>: Resume an aborted scan
  --stylesheet <path/URL>: XSL stylesheet to transform XML output to HTML
  --webxml: Reference stylesheet from Nmap.Org for more portable XML
  --no-stylesheet: Prevent associating of XSL stylesheet w/XML output
MISC:
  -6: Enable IPv6 scanning
  -A: Enable OS detection, version detection, script scanning, and traceroute
  --datadir <dirname>: Specify custom Nmap data file location
  --send-eth/--send-ip: Send using raw ethernet frames or IP packets
  --privileged: Assume that the user is fully privileged
  --unprivileged: Assume the user lacks raw socket privileges
  -V: Print version number
  -h: Print this help summary page.
EXAMPLES:
  nmap -v -A scanme.nmap.org
  nmap -v -sn 192.168.0.0/16 10.0.0.0/8
  nmap -v -iR 10000 -Pn -p 80
SEE THE MAN PAGE (http://nmap.org/book/man.html) FOR MORE OPTIONS AND EXAMPLES
root@MHAnode04:~# nmap -O 50.2.83.130

Starting Nmap 7.01 ( https://nmap.org ) at 2020-06-04 04:11 EDT
Nmap scan report for 50.2.83.130
Host is up (0.15s latency).
Not shown: 999 closed ports
PORT   STATE SERVICE
22/tcp open  ssh
Aggressive OS guesses: Linux 2.6.32 - 3.13 (96%), Linux 3.2 - 4.0 (94%), Linux 2.6.32 - 3.10 (93%), HP P2000 G3 NAS device (93%), Ubiquiti AirMax NanoStation WAP (Linux 2.6.32) (92%), Linux 2.6.32 (92%), Linux 3.7 (92%), Infomir MAG-250 set-top box (92%), Linux 2.6.23 - 2.6.38 (91%), Linux 2.6.32 - 3.1 (91%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 18 hops

OS detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 9.81 seconds

产考资料:

https://blog.csdn.net/he_and/article/details/88350861
https://blog.csdn.net/freeking101/article/details/72962349
https://www.ixueshu.com/document/977e456638c1f9cf.html
https://www.doc88.com/p-8846033523821.html
https://wenku.baidu.com/view/6bdb6c2bff4733687e21af45b307e87100f6f878.html
https://blog.csdn.net/whatday/article/details/105517801
https://wenku.baidu.com/view/c6711182e53a580216fcfe75.html
http://shouce.jb51.net/kali-linux-tutorial/21.html
https://baike.baidu.com/item/%E5%8D%8F%E8%AE%AE%E6%A0%88%E6%8C%87%E7%BA%B9/7113052?fr=aladdin
https://blog.csdn.net/freeking101/article/details/72962349

常见爬虫/BOT 对抗技术简介(二)

何谓VPN?

2.2 VPN

VPN是一个大家耳熟能详的技术。VPN最常用于连接办公网,以及规避流量审计。在WIKI中, VPN的定义如下:

虚拟私人网络(英语:Virtual Private Network,缩写为VPN)是一种常用于连接中、大型企业或团体与团体间的私人网络的通讯方法。它利用隧道协议(Tunneling Protocol)来达到保密、发送端认证、消息准确性等私人消息安全效果,这种技术可以用不安全的网络(例如:互联网)来发送可靠、安全的消息。需要注意的是,加密消息与否是可以控制的,如果是没有加密的虚拟专用网消息依然有被窃取的危险。

我们都知道,我们的网络模型用OSI来描述是7层,分别是应用层、表达层、会话层、传输层、网络层、链路层、物理层。

正常的网络连接, 是完整的7层网络,VPN的原理是通过其中某一层,重新从链路层开始传输。

举个例子,PPTP协议就是把第二层的PPP帧,用GRE协议包装,在IP层上传输。所以PPTP是 PPP over IP . L2TP是把PPP帧封装为UDP包,所以是 PPP over UDP。

用这种方式,也可以理解代理的工作方式,例如,Socks5代理就是 TCP over TCP, HTTP代理是 TCP over HTTP。

只要涉及到改变IP,必然涉及到网络通信协议的重新组装,并在一个层面上重新实现了这个层面或者比这个层面更底层的功能。

由于连接了VPN的用户可以将本地的数据通过VPN路由,所以VPN也是一种“改变IP”的方式。

2.2.1 简单 VPN

简单的VPN组网非常直观,即客户计算机连接至远程服务器,在本地产生一个虚拟网卡,并将本地的所有流量路由至该网卡。
远程的服务器将用户流量从其中一个网卡(可能是物理的、也有可能是PPP的)发出。

2.2.2 混合网络VPN

有意思的是目前国内存在一种混合网络VPN的产品, 本质上是各地的服务器加入到同一个VPN中,用户的VPNClient连接至中心服务器后,

中心服务器在路由表中为此用户随机指定一个VPN网关,实现用户连接同一个VPN服务器,但出口IP是全国随机的。

何谓VPS?

2.3 VPS

VPS 是目前非常常见的一种IT服务, 向用户提供一个远程的服务器,本质上是KVM虚拟机。

通常,在提供VPS服务时,还会向用户提供一个外网IP地址,所以很多爬虫就利用VPS提供的IP地址来解决IP问题。

目前国内有许多优秀的VPS提供商,比如我们已经很熟悉的阿里云、腾讯云,还有不太常见的青云、华为云等等。

2.3.1 混拨VPS

国内还有一个很有意思的VPS服务,叫做混拨VPS。 它的效果是, 你在它提供的VPS服务器上发起PPP连接(拨号), 每次可以通过这个PPP连接为你提供不同地区的IP地址。 它的实现方式是EtherIP。

何谓PPPOE?

2.4 PPPoE (家庭宽带)

PPP协议也叫点对点协议(英语:Point-to-Point Protocol,PPP),是一个历史悠久的协议,定义于1992年,备忘录编号RFC 1331。

它的另外一个名字更为我们所熟知——宽带拨号。 当前我们所用的宽带连接技术,无论ADSL还是光纤接入,在数据链路层上,都使用PPP技术。我们在运营商办理宽带时,如果采用ADSL接入, 运营商会为我们提供一个ADSL Modem,如果使用光纤接入, 运营商为我们提供一个光猫,也叫ONU。 ONU 与 ADSL Modem 为我们建立了与ISP通信的物理层,我们会发现,直接将光猫或ADSL Modem上面的以太网口接入电脑是不行的, 这是因为由于运营商需要AAA,也就是 验证、授权和记账(Authentication、Authorization、Accounting )。 在我们看来,我们需要“拨号” 才能上网。 “拨号”,就是建立了一个PPP连接。 PPP协议提供了认证的能力, 这也就是为什么我们在“拨号”的时候,可以输入 用户名、密码。 而运营商可以通过用户名和密码来对我们进行认证的原因。

在建立了PPP连接之后, 在操作系统看来, PPP连接表现为一个网卡,当然这个网卡并不是物理上的网卡,而是一个虚拟的逻辑网卡, 与这个逻辑的网卡进行通信,PPP协议的驱动程序会自动为我们完成PPP协议的封包和拆包工作, 在我们看来,除了由于PPP协议的8个字节开销,导致MTU比正常的要小一些之外, 这个网卡和一般的物理网卡工作起来并没有什么区别。

一般来说,在PPP连接建立之后, 远端的ISP设备, 称为BAS(接入服务器),会为PPP链接的客户端赋予一个IP地址. 这个IP地址在几年前一般都是公网IP地址, 现在有很多是NAT过的IP地址. 它们来源于BAS服务器上配置的地址池,通常IP地址池的划分是于区县级的,也有部分城市经过改造,可能是市级,甚至是省级的。

PPP拨号在爬虫对抗中是很可靠的IP来源,因为它与用户的IP段重合,如果服务提供商贸然封杀IP,会导致严重的误杀, 当然局限性也很大,如果想获取一个地区IP地址,就需要在这个地区架设机房。所需要的时间精力比较大。

2.5 4G

4G网是近几年已经迅速成熟的移动通信技术。按照ITU的定义,静态传输速率达到1Gbps,用户在高速移动状态下可以达到100Mbps,就可以作为4G的技术之一。据2018年上半年的统计数据,4G用户总数达到11.1亿户。 比传统的宽带接入方式用户数要大得多, 4G接入方式的IP段与家庭宽带的IP段互不重合,是独立的IP段。与家庭宽带来源相比,4GIP段NAT的情况要更加严重, 与用户的重合度更好。 在爬虫对抗的过程中,误杀率会更高。 是更有效的代理IP来源。

接下来我会介绍其他的的IP层反-反爬虫方案

目录如下

三、并发PPP连接技术简介
3.1 PPP协议栈简单介绍
3.2 PPP连接和ADSL的关系
3.3 城域网技术简介
3.4 并发PPP连接方案的适用范围
3.5 国内并发PPP连接服务提供商

四、Linux路由
4.1 Linux基础路由简介
4.2 Linux高级路由简介

常见爬虫/BOT对抗技术介绍(一)

爬虫,是大家获取互联网公开数据的有效手段。爬虫、反爬虫技术、反-反爬虫技术随着互联网的不断发展,也在不断发展更新, 本文简要介绍现代的爬虫/BOT对抗技术,如有疏漏,多谢指正!

一、反爬虫/BOT技术

1.1 Robots.txt

Robots.txt是一个古老的爬虫协议文件,他的位置位于域名根目录下。譬如http://example.com/robots.txt 。 严格来讲Robots.txt并不算一个反爬虫技术,而是一个由爬虫遵守的协议。它通过几个简单的命令告知遵守Robots.txt的爬虫哪些可以被爬取,哪些不能。一般的搜索引擎爬虫会遵守这个协议,而对于上升到爬虫技术对抗的层次来说,这个文件毫无意义。

1.2 IP层/网络层

网络层是反爬虫技术涉及到的最下层,再下的链路层信息在IP报文的传输过程中会被三层交换机丢弃,没有任何意义。IP报文带有的最重要的信息就是IP请求的来源地址, 来源地址极难(近乎不可能)伪造的特性, 使得这个字段成为反爬虫策略中最重要的字段。 封杀IP/IP段是网站可以执行的最严厉的惩罚。由于国内的ISP大量的使用了NAT技术,导致大量用户共用IP的情况越来越多, 内容提供方在做IP封杀时会越来越谨慎, 因为这样做会导致极高的误杀率,以至影响正常用户的网站访问。 但是即使如此, 源IP也是反爬虫策略中最为核心的数据,反爬策略的执行动作一般都要围绕源IP进行。

1.3 HTTP层

HTTP协议层有几个有趣的HTTP头,它们是制定反爬虫策略的常用数据。

1.3.1 X-Forwarded-For

X-Forwarded-For(XFF)是用来识别通过HTTP代理或负载均衡方式连接到Web服务器的客户端最原始的IP地址的HTTP请求头字段。 Squid 缓存代理服务器的开发人员最早引入了这一HTTP头字段,并由IETF在HTTP头字段标准化草案中正式提出。
XFF头由普通HTTP代理服务器添加, 在用户通过普通HTTP代理访问网站时, 用户的IP地址会被添加到这个头中。 一些新手程序员在写代码时,往往会把这个的IP地址当做用户的真实IP地址使用,从而被爬虫利用。

1.3.2 Referer

Referer是浏览器在页面跳转时带入的HTTP头,指示用户上一个页面的URL, 一般来说,网站90%以上的流量应该带有Referer头, 在一些常见的反爬策略中, 大量的不带Referer头的源IP请求会触发”要求输入验证码”策略。

1.3.3 User-Agent

User-Agent 是一个古老的HTTP头,指示用户浏览器的版本、操作系统等基本信息, UserAgent伪装已经在其他的文章里有过充分的讨论,故本文不再赘述。

1.4 应用层/浏览器层

在HTTP层之上是应用层,HTTP层上的数据最终会交由浏览器或者APP去渲染、执行。 本文重点讨论基于现代浏览器的应用层反爬、及反反爬技术。

1.4.1 应用层反爬虫/BOT技术简介

1.4.1.1 验证码

验证码(CAPTCHA)是一种古老而有效的方式,用来判别请求方是否是人类。从最初的简单数字验证码、到后来的中文验证码,到现代的图片验证码, 验证码是应用层最普遍,也最核心的爬虫对抗技术。 对于一些简单的数字、字母验证码, 随着近几年机器学习、神经网络的快速发展,已经近乎于无效。有人训练出基于LSTM的模型可以达到80~90%的识别正确率。 对于图片验证码, 也有灰产专门用人工打码平台来处理,所以单凭验证码很难有效处理爬虫问题, 过多的验证码也会导致正常用户的体验受到影响。

1.4.1.2 JS渲染(Ajax / SPA)

众所周知, Ajax技术在2004年左右开始迅速发展,成为重要的浏览器端技术, 也让爬虫从静态爬虫转化为动态爬虫。 从此,爬取网站的数据不再是简单的一个HTTP请求, 然后解析HTML页面就可以了。大量的网站使用ajax来构建网站前端,也使得解析数据变得越来越困难。 在网站完全不设防的状态,爬虫也不止需要解析HTML页面, 亦需要解析Ajax接口返回的数据。

1.4.1.3 接口加密与JS混淆

一般Ajax接口返回的是一个JSON/XML数据格式,除了给爬虫工程师制造一点点的麻烦以外,并没有任何的反爬虫作用, 只需一点点的前端逆向能力(利用Chrome Debug工具, 找到网络请求),就可以找到ajax接口,并通过对应的库解析出数据。但是如果前端通过JS混淆、并把ajax接口通过token进行加密的话,事情就变得比较麻烦了。 这种做法的思路是, ajax接口除了正常的HTTP请求参数外,额外还要接受一个Token参数,这个token参数是前端的js脚本通过其他的参数加密出来的, 它可能是xor、md5、或者是sha256等等。参数可以是用户名、ip、cookies的sessionid、甚至是用户的操作流程(支付宝的做法)再加上前端把js的函数调用层层嵌套、隐藏、 再加上js脚本混淆,令破解者无法方便的逆向出token计算的流程, 就可以达到一定的反爬目的。

1.4.1.4 数据混淆

爬虫的目的是获取到有效的数据。对于许多应用来说,获取到错误的数据往往比获取不到数据更加致命。(想象一下比价网站拿到的都是错误数据的场景)。这个思路的核心就是,当爬虫命中反爬规则之后,使用错误的数据代替正确的数据返回给爬虫, 这种方式非常隐蔽,又可以对对手造成足够的麻烦, 可以说非常的猥琐、也相当的有效。

1.4.1.5 行为分析

用户的操作轨迹与爬虫的操作轨迹是不同的。举个例子, 在电商网站上,用户可能会浏览100个或者更多相似的商品,最终选择一个进行下单。而爬虫的行为可能是浏览100000个商品,且它们之间彼此关联度很低, 最终也不会有任何购买动作。从这个维度来说,就可以判断出这个请求来源是客户还是爬虫。 结合其他的反爬手段,就可以对爬虫造成有效干扰。低级的行为分析基于规则,高级的行为分析基于机器学习。 对于用户操作比较多的网站来讲,是一种很可靠的反爬手段。

1.4.1.6 存储跟踪与flash Storage

Cookies是众所周知的浏览器保持状态的一种机制。 除了Cookies,现代的浏览器还支持localStorage。以目前国内用户的使用习惯,绝大多数用户不会设置拒绝Cookies保持。所以,拒绝Cookies跟踪的客户端可以认为就是爬虫。通过Cookies,就可以跟踪用户的行为轨迹。 除此之外,如果用户使用浏览器模拟技术,一定在每次请求时会清空Cookies。 Cookies被清空之后,我们仍然有机会使用flash来继续跟踪用户。今天的(2017年)Flash确实是一个夕阳技术,但仍然保持极高的市场占用率,在PC端,90%以上的国内视频网站依然采用flash作为播放器的客户端。所以,一个以PC端流量为主的网站,可以使用flash来进行用户跟踪。值得高兴的是,在flash插件中,通过Capabilities.serverString可以获取到非常多的系统信息,包括操作系统、语言、系统分辨率、DPI等等等等。这些系统信息与JS上下文、UserAgent、用户访问日志进行一起分析,就可以判断是否是伪装为爬虫的浏览器。举个例子,如果是正常的用户, 从flash、js上下文、useragent拿到的参数应该是一致的,而如果伪造过UA(不那么高明的伪造),则肯定会有纰漏。正所谓一个谎言需要用十个谎言去掩盖。

1.4.1.7 navigator对象

浏览器中的window.navigator对象保持了很多的操作系统、浏览器信息。navigator对象的信息配合Useragent、flash,可以用来判断是否是伪装浏览器。

1.4.1.8 假链陷阱

假链陷阱作为反爬手段,多见于半静态网站。 它的思路主要是构建一个不可见的a标签, 如果爬虫跟踪所有的页面链接,势必会掉到构造好的陷阱,导致爬虫命中反爬策略。

1.4.1.9 浏览器指纹

浏览器指纹技术常用于客户端跟踪及反机器人的场景。核心思路是, 不同浏览器、操作系统、以及操作系统环境,会使得canvas的同一绘图操作流程产生不同的结果。如果是相同的运行环境,同一套Canvas操作流程会产生相同的结果。 浏览器指纹的优势是不需要浏览器保持本地状态,即可跟踪浏览器。 由于国内特色的Ghost系统安装,这种方式的误杀率并不低,

1.4.1.10 JS引擎指纹

这种思路是,不同的JS引擎在执行相同的JS语句时,会有不同的结果。 举个例子来说,eval.toString().length,在Safari浏览器中的结果是 37 , 在IE中是39 , 在Chrome 中的结果是33. 通过判断JS引擎的动作和UserAgent中声称的浏览器类型,可以判断是否是伪造浏览器。

1.4.2 应用层反反爬虫/BOT方案简介

1.4.2.1 前端逆向

前端逆向,就是利用前端所有代码、数据都是暴露给客户端的特点, 通过分析HTML、JS等源码来获取数据的技术。 常用的前端逆向工具就是Chrome Debug 工具。前端逆向分析通常用来分析那些动态渲染的网站。 如果分析透彻,可以避免使用浏览器模拟的方式来进行爬取。

1.4.2.2 浏览器模拟

浏览器模拟指利用真实的浏览器去请求、执行页面和脚本。应用场景是爬取带有复杂JS和接口加密的网站、也被BOT用于复杂网站。常见的浏览器模拟框架有Selenium WebDriver、 PhatomJS。 Selenium 是通过浏览器的debug接口进行浏览器的远程操控API。PhantomJS是一个嵌入了浏览器内核的js渲染服务,这种技术可以用来对抗动态渲染和接口加密。所有的渲染和加密过程都由浏览器内核完成。 高级的做法是用CEF(Chrome Embedded Framework)进行二次开发。通过二次开发CEF,可以获得很强的灵活性, 比如在页面加载之前劫持JS对象、用C++代码hook native js api等等。这种技术的主要劣势是低下的性能。 与纯粹的HTTP请求代码来说, 这种方案要多吃50~500倍的CPU。 也就是说, 它的效率要下降数十倍到数百倍左右。

1.4.2.2 字符识别

光学字符识别(OCR)用于对抗简单的数字、字母验证码。初级的OCR基于模板。高级的字符识别基于神经网络,比如[这个项目],它基于LSTM模型,可以提供更好的识别率。

1.4.2.4 行为模拟

行为模拟是指在爬虫和BOT的过程中,有意的留下Cookie,并请求一些与需要爬取数据无关的接口或者做一些动作,用来模拟一般用户的动作, 用于对抗行为分析。 在BOT场景下,这种方式也用来模拟用户的活跃度和留存率。 一般来说,行为模拟的主要依据来源于前端逆向的工作, 破解者需要确定究竟有哪些HTML元素和用户行为事件被网站所关注,并针对性的做出想要模拟的行为。 大多数情况下,爬虫的行为模拟是请求某个日志上报接口, 而一些比较特殊的网站(比如支付宝), 用户行为数据附着在请求普通接口的参数中,并经过高度混淆。

1.4.2.6 打码平台

打码平台用来对抗强度比较高的验证码和人机验证方案。正常的验证码流程是,由网站生成一张图片传递给用户,用户输入这张图片的信息传回网站,完成人机验证。 破解者通过对接打码平台,将用户识别信息的环节放到打码平台去做,打码平台组织一群专职人员,进行验证码的识别工作,并传回爬虫,完成验证码的识别工作。高级的打码平台还会利用这些海量的打码数据进行模型训练。

1.4.2.7 JS Hook

这种方式主要用来对抗js上下文的跟踪和分析。做法是,在页面加载前,通过替换JS上下文的对象,将JS上下文中的对象和方法替换掉。 例如,将window.screen对象替换, 使网站的js代码获取到替换后的屏幕分辨率。 JS Hook一般在CEF二次开发中实现,也可以通过劫持普通浏览器的流量完成js hook。

二、IP层反反爬虫技术

2.1 代理服务器

对于爬虫的客户端编程来说,利用代理服务器进行源IP更改,是最简单易行的方式。 代理服务器分为HTTP代理和Socks代理两类。HTTP又分为HTTP和HTTPS代理, Socks又分为Socks4和Socks5两类。

2.2.1 HTTP代理

HTTP代理是一种常见的代理服务类型。常用80、8080端口, 它的协议在RFC 7230 中定义。 对于连接到它的客户端来说,它是服务端;对于要连接的服务端来说,它是客户端。它就负责在两端之间来回传送 HTTP 报文。 根据XFF头部的添加与否, 分为普通代理和高匿代理两类。 普通代理会把请求方的源IP添加在HTTP请求头, 而高匿代理不会。对于服务端程序员来说,通过XFF头判断用户的源IP来源是一种十分 Too Young , sometimes naive 的行为,因为服务端完全没有能力判断这个XFF头是由请求方伪造的,还是由代理服务器添加的。 网上流传的一些Java代码,会首先判断XFF头,如果有则将XFF头作为源IP处理,这种方式基本没有任何反爬虫作用。

2.2.2 Socks代理

SOCKS是另外一种常见的代理服务。SOCKS是”SOCKetS”的缩写[1]。这个协议最初由David Koblas开发,而后由NEC的Ying-Da Lee将其扩展到版本4。最新协议是版本5,与前一版本相比,增加支持UDP、验证,以及IPv6。根据OSI模型,SOCKS是会话层的协议,位于表示层传输层之间。 也就是说,Socks通过TCP连接作为隧道进行代理。 Socks代理中,Socks5代理最为常见。

接下来我会介绍其他的的IP层反-反爬虫方案。

目录如下

2.2 VPN
2.3.1 简单 VPN
2.3.2 混合网络VPN

2.3 VPS
2.4 单机PPP拨号
2.5 并发PPP拨号

三、并发PPP连接技术简介
3.1 PPP协议栈简单介绍
3.2 PPP连接和ADSL的关系
3.3 城域网技术简介
3.4 并发PPP连接方案的适用范围
3.5 国内并发PPP连接服务提供商

四、Linux路由
4.1 Linux基础路由简介
4.2 Linux高级路由简介

MyISAM加锁分析

为什么加锁

你正在读着你喜欢的女孩递给你的信,看到一半的时候,她的好闺蜜过来瞄了一眼(假设她会隐身术,你看不到她),她想把“我很喜欢你”改成“我不喜欢你”,刚把“很”字擦掉,“不”字还没写完,只写了一横一撇,这时候你正读到这个字,她怕你察觉到也就没继续往下写了,这时候你读到的这句话就是“我丆喜欢你”,这是什么鬼?!这位闺蜜乐了:没错,确实是鬼在整蛊你呢,嘿嘿!

数据库也会闹鬼吗?很有可能!假设会话1正在读取表里的一条记录(还没读取完),另一个会话2突然插队过来更新表里的同一条记录(还没更新完),那么会话1拿到的数据就可能是错误的(还没更新完的内容和原内容混在一起,造成乱码,就像上面的“我丆喜欢你”)。

怎么避免这种情况呢?加锁,当有一个人在读的时候,别人能读不能写,当有一个人在写的时候,别人不能读和写。

所以,加锁是为了在并发操作的时候,能够确保数据的完整性和一致性。

加锁的规则

MyISAM锁的粒度是表级锁,在执行查询(SELECT)之前,尝试在表上面加读锁,在执行更新(UPDATE,DELETE,INSERT)之前,尝试在表上面加写锁。

加写锁:

如果在表上没有锁(读锁和写锁),在它上面放一个写锁。
否则,把锁定请求放在写锁定队列中。

加读锁:

如果在表上没有写锁定,把一个读锁定放在它上面。
否则,把锁定请求放在读锁定队列中。

优先级:

当一个锁定被释放时,锁定优先被写锁定队列中的线程得到,然后是读锁定队列中的线程。这意味着如果有大量的写操作,读操作将会一直等待,直到写完成。可以通过以下命令看到加锁的情况:

SHOW STATUS LIKE 'table%';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| Table_locks_immediate | 42    |
| Table_locks_waited    | 3     |
+-----------------------+-------+

Table_locks_immediate是加锁立刻执行成功的次数,Table_locks_waited是造成等待的加锁次数。另外,可以通过LOW_PRIORITY来改变优先级

实例分析

开一个会话窗口1,输入下面的语句执行:

CREATE TABLE `users`(
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(15) NOT NULL,
PRIMARY KEY (`id`)
)ENGINE=MYISAM DEFAULT CHARSET=utf8 COMMENT='用户';

INSERT INTO `users` VALUES (null, 'pigfly'),(null,'zhupp');

为了模拟,我们手动执行LOCK TABLES语句把表锁住:

LOCK TABLES `users` READ LOCAL;
SELECT * FROM `users`;
UPDATE `users` SET name='aa' where id=1;

SELECT正常返回,UPDATE报错了,原因是当前表加了读锁,则当前会话只能执行读操作,不能执行更新操作。

新开一个会话窗口2:

INSERT INTO `users` VALUES (null, 'zhupp');
UPDATE `users` SET name='xxx' where id=1;

可以看到插入执行成功,但是UPDATE操作被窗口1加的读锁阻塞了,我们回到窗口1执行:

UNLOCK TABLES;

这时候窗口2的更新语句马上返回更新成功了。

为什么插入不会被读锁阻塞呢?原因是当表加了读锁并且表不存在空闲块的时候(删除或者更新表中间的记录会导致空闲块,OPTIMIZE TABLE可以清除空闲块),MYISAM默认允许其他线程从表尾插入。可以通过改变系统变量concurrent_insert(并发插入)的值来控制并发插入的行为。

SHOW VARIABLES LIKE 'concurrent%';
+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| concurrent_insert | AUTO  |
+-------------------+-------+

Value的值:

  • NEVER(0): 不允许并发插入
  • AUTO(1): 表里没有空行时允许从表尾插入(默认)
  • ALWAYS(2): 任何时候都允许并发插入

注意:锁表的时候加了LOCAL关键字表示允许走并发插入的逻辑,具体是否可以并发插入还需要看是否满足concurrent_insert指定的条件,只有手动锁表的时候才需要指定LOCAL关键字。

测试一下当表里有空闲块的情况,窗口1执行:

DELETE FROM `users` WHERE id=1;
LOCK TABLES `users` READ LOCAL;

然后在窗口2执行:

INSERT INTO `users` VALUES (null, 't1');

果然被阻塞了。我们把并发插入的值改成2试试,在窗口1执行:

UNLOCK TABLES;
SET GLOBAL concurrent_insert=2;
DELETE FROM `users` WHERE id=2;
LOCK TABLES `users` READ LOCAL;

然后在窗口2执行:

INSERT INTO `users` VALUES (null, 't2');
SELECT * FROM `users`;

这一次没有被阻塞,插入成功了。

表级锁的特点

开销小、加锁快、不会产生死锁,锁定力度大,发生锁冲突的概率最高,不适合高并发场景。

性能优化

  1. 对于并发插入,一般默认配置AUTO就可以了,如果有大量插入操作,可以把concurrent_insert设置为2,然后定期在流量低峰期执行OPTIMIZE TABLE来清除空闲块。
  2. 调整优先级。
  3. 在大量更新操作前手动锁表,这样锁表只执行了一次,不然每执行一次更新就锁一次表。
  4. 存在大量更新操作造成等待,又要兼顾查询的时候,给max_write_lock_count设置一个低值,在写锁达到一定数量时允许执行挂起的读请求。

Amazon Comprehend 自然语言处理,PHP使用教程,调用示例

Amazon Comprehend 是一项自然语言处理 (NLP) 服务,使用机器学习来发现文本中的洞察信息。Amazon Comprehend 提供关键词提取、情绪分析、实体识别、主题建模和语言检测 API,因此您可以轻松地将自然语言处理集成到您的应用程序中。您只需在应用程序中调用相应 Amazon Comprehend API 并提供源文档或文本的位置即可。这些 API 将以 JSON 格式输出实体、关键词、情绪和语言,以供您在应用程序中使用。

一、通过Composer安装SDK(需要安装aws/aws-sdk-php软件包)

composer require aws/aws-sdk-php

https://packagist.org/packages/aws/aws-sdk-php

或下载独立的AWS来开始使用。 zip 或aws.phar文件。
https://docs.aws.amazon.com/aws-sdk-php/v3/download/aws.zip
二、非框架安装需要引用/vendor/autoload.php
use Aws\Comprehend\ComprehendClient;
use Aws\Exception\AwsException;

完整demo

<?php
namespace app\controller;

use app\BaseController;
use Aws\Comprehend\ComprehendClient;
use Aws\Textract\TextractClient;
use Aws\Exception\AwsException;
class Index extends BaseController
{
	/**
	 * doc:https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-comprehend-2017-11-27.html#detectsentiment
	 */
    public function aws(){
	    $client=new ComprehendClient([
		    'version' => 'latest',
            //'version' => '2018-06-27',
		    'region' => 'us-west-2',
		    'credentials' => [
			    'key' => 'AKIAQHKSE4HRGDDDDDDD', //IAM user key
			    'secret' => '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', //IAM user secret
		    ]]);

	    /**
	     * 情绪分析
	     * 情绪分析 API 会返回文本的整体情绪(正面、负面、中性或混合)。
	     */

	    $result = $client->detectSentiment([
//	    'LanguageCode'=>'en | es | fr | de | it | pt | ar | hi | ja | ko | zh | zh-TW',//必填
	    'LanguageCode'=>'en',//必填
        'Text'=>'Your service attitude is really poor',//必填
		]);
	    print_r($result->toArray());
	    /*
		Array
		(
		    [Sentiment] => NEGATIVE
		    [SentimentScore] => Array
		        (
		            [Positive] => 6.2582264945377E-5
		            [Negative] => 0.99910479784012
		            [Neutral] => 0.00083179638022557
		            [Mixed] => 8.1932506645899E-7
		        )

		    [@metadata] => Array
		        (
		            [statusCode] => 200
		            [effectiveUri] => https://comprehend.us-west-2.amazonaws.com
		            [headers] => Array
		                (
		                    [x-amzn-requestid] => 7436bbaf-73c1-4462-a814-d29efe81522f
		                    [content-type] => application/x-amz-json-1.1
		                    [content-length] => 164
		                    [date] => Thu, 21 May 2020 08:46:28 GMT
		                )

		            [transferStats] => Array
		                (
		                    [http] => Array
		                        (
		                            [0] => Array
		                                (
		                                )

		                        )

		                )

		        )

		)
	    */
	    /**
	     * 语言检测
	     * 语言检测 API 可自动识别出 100 多种语言编写的文本,并返回主导语言以及证明其占据主导地位的置信度得分。
	     */

	    $result =$client->detectDominantLanguage([
		    'Text'=>'Your service attitude is really poor',//必填
	    ]);
	    print_r($result->toArray());
	    /*
	    Array
	    (
		    [Languages] => Array
		    (
			    [0] => Array
			    (
				    [LanguageCode] => en
				    [Score] => 0.98973816633224
                )

            )

		    [@metadata] => Array
			    (
				    [statusCode] => 200
		            [effectiveUri] => https://comprehend.us-west-2.amazonaws.com
		            [headers] => Array
			    (
				    [x-amzn-requestid] => e4a6f3cd-5678-46b7-abd3-51d81e28b69f
			    [content-type] => application/x-amz-json-1.1
		                    [content-length] => 64
		                    [date] => Thu, 21 May 2020 08:42:48 GMT
		                )

		            [transferStats] => Array
			    (
				    [http] => Array
				    (
					    [0] => Array
					    (
					    )

				    )

			    )

		        )

		)
	     */
	    /**
	     * 关键词提取
	     * 关键词提取 API 会返回关键词或谈话要点以及证明此为关键词的置信度。
	     */

	    $result =$client->detectKeyPhrases([
		    'LanguageCode'=>'en',//必填
		    'Text'=>'Your service attitude is really poor',//必填
	    ]);
	    print_r($result->toArray());
        /*
	    Array
	    (
		    [KeyPhrases] => Array
		    (
			    [0] => Array
			    (
				    [Score] => 1
                    [Text] => Your service attitude
	    [BeginOffset] => 0
                    [EndOffset] => 21
                )

        )

		    [@metadata] => Array
			    (
				    [statusCode] => 200
		            [effectiveUri] => https://comprehend.us-west-2.amazonaws.com
		            [headers] => Array
			    (
				    [x-amzn-requestid] => 18657c2a-28d9-432c-9e4b-b403ac597299
			    [content-type] => application/x-amz-json-1.1
		                    [content-length] => 92
		                    [date] => Thu, 21 May 2020 09:01:37 GMT
		                )

		            [transferStats] => Array
			    (
				    [http] => Array
				    (
					    [0] => Array
					    (
					    )

				    )

			    )

		        )

		)
        */


	    /**
	     * 实体识别
	     * 实体识别 API 会返回根据提供的文本自动分类的命名实体(“人物”、“地点”和“位置”等)。
	     */

	    $result =$client->detectEntities([
		    'LanguageCode'=>'en',//必填
		    'Text'=>'Your service attitude is really poor',//必填
	    ]);
	    print_r($result->toArray());
	    /*
	    Array
	    (
		    [Entities] => Array
		    (
		    )

		    [@metadata] => Array
			    (
				    [statusCode] => 200
		            [effectiveUri] => https://comprehend.us-west-2.amazonaws.com
		            [headers] => Array
			    (
				    [x-amzn-requestid] => 78db83bb-7bca-4381-82f8-06deb3e18546
			    [content-type] => application/x-amz-json-1.1
		                    [content-length] => 15
		                    [date] => Thu, 21 May 2020 09:04:33 GMT
		                )

		            [transferStats] => Array
			    (
				    [http] => Array
				    (
					    [0] => Array
					    (
					    )

				    )

			    )

		        )

		)
	     */

	    /**
	     * 语法分析
	     * 借助 Amazon Comprehend Syntax API,客户能够使用分词断句和词性 (PoS) 分析文本,识别文本中的名词和形容词等单词边界和标签。
	     */
	    $result =$client->detectSyntax([
		    'LanguageCode'=>'en',//必填
		    'Text'=>'Your service attitude is really poor',//必填
	    ]);
	    print_r($result->toArray());

	    /*
	    Array
	    (
		    [SyntaxTokens] => Array
		    (
			    [0] => Array
			    (
				    [TokenId] => 1
                    [Text] => Your
	    [BeginOffset] => 0
                    [EndOffset] => 4
                    [PartOfSpeech] => Array
				    (
					    [Tag] => PRON
					    [Score] => 0.99996387958527
			                        )

			                )

			            [1] => Array
				    (
					    [TokenId] => 2
			                    [Text] => service
				    [BeginOffset] => 5
			                    [EndOffset] => 12
			                    [PartOfSpeech] => Array
				    (
					    [Tag] => NOUN
					    [Score] => 0.9985853433609
			                        )

			                )

			            [2] => Array
				    (
					    [TokenId] => 3
			                    [Text] => attitude
				    [BeginOffset] => 13
			                    [EndOffset] => 21
			                    [PartOfSpeech] => Array
				    (
					    [Tag] => NOUN
					    [Score] => 0.99978679418564
			                        )

			                )

			            [3] => Array
				    (
					    [TokenId] => 4
			                    [Text] => is
				    [BeginOffset] => 22
			                    [EndOffset] => 24
			                    [PartOfSpeech] => Array
				    (
					    [Tag] => VERB
					    [Score] => 0.99935394525528
			                        )

			                )

			            [4] => Array
				    (
					    [TokenId] => 5
			                    [Text] => really
				    [BeginOffset] => 25
			                    [EndOffset] => 31
			                    [PartOfSpeech] => Array
				    (
					    [Tag] => ADV
					    [Score] => 0.9999988079071
			                        )

			                )

			            [5] => Array
				    (
					    [TokenId] => 6
			                    [Text] => poor
				    [BeginOffset] => 32
			                    [EndOffset] => 36
			                    [PartOfSpeech] => Array
				    (
					    [Tag] => ADJ
					    [Score] => 0.9997541308403
			                        )

			                )

			        )

			    [@metadata] => Array
				    (
					    [statusCode] => 200
			            [effectiveUri] => https://comprehend.us-west-2.amazonaws.com
			            [headers] => Array
				    (
					    [x-amzn-requestid] => 0eb35b66-d36a-43e8-94ee-b5b0c3e786eb
				    [content-type] => application/x-amz-json-1.1
			                    [content-length] => 722
			                    [date] => Thu, 21 May 2020 09:08:51 GMT
			                )

			            [transferStats] => Array
				    (
					    [http] => Array
					    (
						    [0] => Array
						    (
						    )

					    )

				    )

			        )

			)
	    */

    }
}

https://docs.aws.amazon.com/comprehend/latest/dg/comprehend-general.html

https://aws.amazon.com/cn/comprehend/features/

https://docs.aws.amazon.com/general/latest/gr/rande.html

https://docs.aws.amazon.com/comprehend/latest/dg/supported-languages.html