0%

top

简介

Dashboard 是基于网页的 Kubernetes 用户界面。可以很直观的管理k8s,降低新手学习难度。
github地址为:https://github.com/kubernetes/dashboard

安装

下载yaml文件

1
wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.3/aio/deploy/recommended.yaml

修改配置

找到Service部分

1
2
3
4
5
6
7
8
9
10
11
12
13
kind: Service
apiVersion: v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kubernetes-dashboard
spec:
ports:
- port: 443
targetPort: 8443
selector:
k8s-app: kubernetes-dashboard

改成如下内容,添加NodePort,nodePort为30002

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
kind: Service
apiVersion: v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kubernetes-dashboard
spec:
type: NodePort
ports:
- port: 443
targetPort: 8443
nodePort: 30002
selector:
k8s-app: kubernetes-dashboard

创建dashboard

1
kubectl apply -f recommended.yaml

查看dashboard状态

1
kubectl get svc,pod,deployment -o wide -n kubernetes-dashboard

结果如下:
kubernetes-dashboard

创建account

新建配置文件serviceAccount.yaml,内容如下

1
2
3
4
5
apiVersion: v1
kind: ServiceAccount
metadata:
name: admin-user
namespace: kubernetes-dashboard

通过kubectl apply创建

1
kubectl apply -f serviceAccount.yaml

查询是否创建成功

1
kubectl -n kubernetes-dashboard  get secret | grep "admin-user"

admin-user

设置权限

新建配置文件clusterRoleBinding.yaml,内容如下

1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: admin-user
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: admin-user
namespace: kubernetes-dashboard

通过kubectl apply创建

1
kubectl apply -f clusterRoleBinding.yaml

查询secret

1
kubectl -n kubernetes-dashboard describe secret $(kubectl -n kubernetes-dashboard get secret | grep admin-user | awk '{print $1}')

复制token,并记录下来
secret

访问dashboard

IP地址为master节点IP,端口为30002,完整url为https://192.168.233.129:30002
登陆方式选择token,复制上面记录的token即可
dslogin

效果如下:
ds

小结

我们可以通过命令行管理k8s,也可以通过ui管理,对于新手来说可以用ui,熟练之后建议用命令行。

bottom

top

机器准备

准备4台机器,至少2GB内存, 至少2个CPU。如果资源不够,可以用虚拟机,安装centos 7以上操作系统,本实验所用的版本号为:CentOS Linux release 7.6.1810 (Core),机器规划如下:

name host ip user
master master, master.k8s.io 192.168.233.129 root
slave1 slave1, slave1.k8s.io 192.168.233.131 root
slave2 slave2, slave2.k8s.io 192.168.233.132 root
slave3 slave3, slave3.k8s.io 192.168.233.133 root

其中Pod网络地址分配如下:10.244.0.0/16,Service网络地址分配如下:10.96.0.0/12

机器配置(以master为例,其它的三台slave类似)

配置静态IP

编辑文件/etc/sysconfig/network-scripts/ifcfg-ens33,

1
2
3
4
5
6
7
8
ONBOOT=yes
BOOTPROTO="static"
IPADDR=192.168.233.129
NETMASK=255.255.255.0
GATEWAY=192.168.233.2
PREFIX=24
DNS1=192.168.233.2
PEERDNS=no

配置主机名

1
hostnamectl set-hostname master

配置hosts

/etc/hosts

1
2
3
4
5
6
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.233.129 master master.k8s.io
192.168.233.131 slave1 slave1.k8s.io
192.168.233.132 slave2 slave2.k8s.io
192.168.233.133 slave3 slave3.k8s.io

系统设置

systemctl命令 说明
systemctl start 启动服务
systemctl enable 设置服务开机启动
systemctl status 查看服务状态

开启时钟同步

1
2
3
systemctl start chronyd.service
systemctl enable chronyd.service
systemctl status chronyd.service

关闭防火墙

1
2
3
systemctl stop firewalld.service
systemctl disable firewalld.service
systemctl status firewalld.service

关闭SELinux

1
2
3
4
#Permissive
setenforce 0
getenforce
sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config

SELinux

关闭swap

1
swapoff -a

编辑/etc/fstab,注释掉swap相关的行,行首前面加#
fstab

查询最终状态如下:

1
free -m

swap

最好重启一下机器,然后下一步安装docker

安装docker

docker install centos

移除旧的docker

1
2
3
4
5
6
7
8
yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine

设置docker-ce.repo

1
2
3
4
5
yum install -y yum-utils

yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo

安装docker-ce

1
yum install docker-ce

配置docker

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
mkdir /etc/docker

# Setup daemon.
cat > /etc/docker/daemon.json <<EOF
{
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2",
"storage-opts": [
"overlay2.override_kernel_check=true"
]
}
EOF

sed -i "13i ExecStartPost=/usr/sbin/iptables -P FORWARD ACCEPT" /usr/lib/systemd/system/docker.service

# start Docker
service network restart
systemctl daemon-reload
systemctl enable docker
systemctl start docker
docker info

安装kubernetes

kubernetes install kubeadm

配置kubernetes.repo

google源

1
2
3
4
5
6
7
8
9
10
cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-\$basearch
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
exclude=kubelet kubeadm kubectl
EOF

阿里镜像源

1
2
3
4
5
6
7
8
9
10
touch /etc/yum.repos.d/kubernetes.repo
cat > /etc/yum.repos.d/kubernetes.repo <<EOF
[kubernetes]
name=Kubernetes Repo
enabled=1
gpgcheck=1
repo_gpgcheck=1
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF

安装k8s

1
yum -y install kubelet kubeadm kubectl

配置网络路由相关

Make sure that the br_netfilter module is loaded. This can be done by running

1
lsmod | grep br_netfilter

To load it explicitly call

1
modprobe br_netfilter

配置k8s.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables=1
net.bridge.bridge-nf-call-ip6tables=1
net.ipv4.ip_forward=1
net.ipv4.tcp_tw_recycle=0
vm.swappiness=0
vm.overcommit_memory=1
vm.panic_on_oom=0
fs.inotify.max_user_watches=89100
fs.file-max=52706963
fs.nr_open=52706963
net.ipv6.conf.all.disable_ipv6=1
net.netfilter.nf_conntrack_max=2310720
EOF
sysctl --system

enable ip_forward

1
echo 1 > /proc/sys/net/ipv4/ip_forward

配置kubelet.service

1
systemctl enable kubelet.service

以上配置,master和slave是一样的过程。

下载k8s镜像

由于k8s镜像默认下载不了,需要通过docker hub mirror进行下载

获取所需镜像版本

1
kubeadm config images list

images

master节点下载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
docker pull mirrorgcrio/kube-apiserver:v1.18.6
docker pull mirrorgcrio/kube-controller-manager:v1.18.6
docker pull mirrorgcrio/kube-scheduler:v1.18.6
docker pull mirrorgcrio/kube-proxy:v1.18.6
docker pull mirrorgcrio/pause:3.2
docker pull mirrorgcrio/etcd:3.4.3-0
docker pull mirrorgcrio/coredns:1.6.7

docker tag mirrorgcrio/kube-apiserver:v1.18.6 k8s.gcr.io/kube-apiserver:v1.18.6
docker tag mirrorgcrio/kube-controller-manager:v1.18.6 k8s.gcr.io/kube-controller-manager:v1.18.6
docker tag mirrorgcrio/kube-scheduler:v1.18.6 k8s.gcr.io/kube-scheduler:v1.18.6
docker tag mirrorgcrio/kube-proxy:v1.18.6 k8s.gcr.io/kube-proxy:v1.18.6
docker tag mirrorgcrio/pause:3.2 k8s.gcr.io/pause:3.2
docker tag mirrorgcrio/etcd:3.4.3-0 k8s.gcr.io/etcd:3.4.3-0
docker tag mirrorgcrio/coredns:1.6.7 k8s.gcr.io/coredns:1.6.7

docker rmi mirrorgcrio/kube-apiserver:v1.18.6
docker rmi mirrorgcrio/kube-controller-manager:v1.18.6
docker rmi mirrorgcrio/kube-scheduler:v1.18.6
docker rmi mirrorgcrio/kube-proxy:v1.18.6
docker rmi mirrorgcrio/pause:3.2
docker rmi mirrorgcrio/etcd:3.4.3-0
docker rmi mirrorgcrio/coredns:1.6.7

master节点最终镜像列表

1
docker images | grep "k8s.gcr.io"

k8s.gcr.io

slave节点只需要下载kube-proxy:v1.18.6y和pause:3.2

1
2
3
4
5
6
7
8
docker pull mirrorgcrio/kube-proxy:v1.18.6
docker pull mirrorgcrio/pause:3.2

docker tag mirrorgcrio/kube-proxy:v1.18.6 k8s.gcr.io/kube-proxy:v1.18.6
docker tag mirrorgcrio/pause:3.2 k8s.gcr.io/pause:3.2

docker rmi mirrorgcrio/kube-proxy:v1.18.6
docker rmi mirrorgcrio/pause:3.2

请确保所有的机器镜像都提前下载好,否则后面k8s启动会失败。

启动k8s

master

运行kubeadm init

1
2
3
4
5
6
7
8
9
10
11
kubeadm init \
--kubernetes-version=v1.18.6 \
--pod-network-cidr=10.244.0.0/16 \
--service-cidr=10.96.0.0/12 \
--apiserver-advertise-address=0.0.0.0

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

slave

复制master节点/run/flannel/subnet.env到各个slave节点

运行kubeadm join命令,xxx和yyy分别是master打印出来的日志里面的内容

1
2
kubeadm join 192.168.233.129:6443 --token xxx \
--discovery-token-ca-cert-hash yyy

检查状态

master节点执行

集群组件状态

命令

1
kubectl get cs

kubectlgetcs

故障排查

kubernetes:v1.18.6 get cs127.0.0.1 connection refused

编辑文件/etc/kubernetes/manifests/kube-controller-manager.yaml和/etc/kubernetes/manifests/kube-scheduler.yaml
注释或删除掉 –port=0所在的行

重启kubelet.service

1
systemctl restart kubelet.service

集群节点状态

命令

1
kubectl get nodes

kubectlgetnodes

Hello World

master节点执行

创建service

创建文件 hello-service.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
apiVersion: v1
kind: Service
metadata:
name: hello-service
spec:
selector:
app: hello-k8s-demo
ports:
- protocol: TCP
port: 81
targetPort: 80
nodePort: 30001
type: NodePort

执行命令kubectl create,其中80是nginx端口,81是pod端口,30001是映射到外部的端口

1
kubectl create -f hello-service.xml

创建deployment和pod

创建文件hello-deployment.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: hello-k8s-demo
name: hello-deployment
spec:
replicas: 2
selector:
matchLabels:
app: hello-k8s-demo
template:
metadata:
labels:
app: hello-k8s-demo
spec:
containers:
- image: docker.io/nginx:latest
name: hello-k8s
ports:
- containerPort: 80

执行命令kubectl create, pod数量为2,会随机选择2个slave节点运行nginx docker

1
kubectl create -f hello-deployment.xml

查询状态

1
kubectl get svc,pod,deployment -o wide

svcpoddeployment

验证nginx

如上图hello-service的IP为10.101.171.221, 内部端口为81,外部IP为:192.168.233.129(master IP),端口为30001

在master,slave,节点内部访问http://10.101.171.221:81进行验证

1
curl http://10.101.171.221:81

看到如下内容,说明成功

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

在k8s外部访问http://192.168.233.129:30001进行验证

1
curl http://192.168.233.129:30001

结果相同

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

小结

我们通过虚拟机可以配置k8s集群,其中一台master,3台slave,k8s启动之后就可以运行nginx hello world例子。

bottom

简介

上一篇文章介绍了docker安装,并演示了HelloWorld。今天主要介绍一下镜像管理相关知识,分为三大部分:镜像、容器、仓库,首先看一下关系图:

1

仓库(Repository)

仓库是存放镜像的地方,每个仓库集中存放某一类镜像,比如存放Ubuntu镜像的仓库叫做Ubuntu仓库,可能包括14.04、16.04、latest等版本,通过tag区分。这些仓库可以存放在公开服务器Registry上面,可以搭建私有服务器。官方的服务器为Docker Hub, 网址为:https://hub.docker.com。 如果网络访问不方便,可以采用国内镜像网站。
自己可以注册账号,上传自定义镜像到服务器,共享给他人下载。

镜像(Image)

Docker镜像类似于虚拟机镜像, 可以理解成包含了文件系统的只读模板。可以从压缩文件导入或从仓库下载,我们可以在本地已有镜像的基础上自定义镜像。
以下载Ubuntu镜像为例:

1
docker pull ubuntu

2

通过docker images命令查询已经下载的镜像,我们发现之前的Hello-world和ubuntu都查询成功了。
默认如果不指定tag,下载的就是最新的latest, 相当于docker pull ubuntu:latest, 如果下载指定版本,比如14.04,命令为docker pull ubuntu:14.04
3

再次查询一下,发现有两个ubuntu镜像,但是TAG不一样,并且他们的IMAGE ID也不一样,是两个不同的镜像。
如果我们不需要ubuntu:14.04镜像了,可以通过docker rmi f216cfb59484命令进行删除:
4

删除后,查询一下,发现ubuntu:14.04镜像不见了,说明删除成功。
现在运行一下镜像ubuntu:latest,命令为:

1
docker run -ti ubuntu /bin/bash

5

运行成功后,自动创建了一个容器并运行,可以输入简单的Linux命令,比如ls。可以添加一个新文件,然后创建一个新的镜像。
6

首先创建一个文件:然后退出:

1
2
touch test.txt
exit

记录容器ID为4040e711b2a3之后,执行命令

1
docker commit -m "Add test.txt" -a "beyondspider" 4040e711b2a3 ubuntu:test

在ubuntu:latest镜像基础上创建了一个新的镜像ubuntu:test。
可以把刚才创建的镜像导出到本地压缩文件,或者上传到Docker Hub,这里就不做演示了。

容器(Container)

Docker容器类似于一个轻量级的沙箱,可以看作简易版的Linux系统环境,容器是从镜像创建的实例,会在镜像的最上层创建一个可写层,镜像是只读的,不会改变。
一个镜像可以创建多个容器,不同容器是相互隔离互不可见的。可以对容器进行启动、停止、删除等操作。
刚才的命令

1
docker run -ti ubuntu /bin/bash

其实包括两个动作,首先执行了命令创建容器:

1
docker create -ti ubuntu /bin/bash

然后执行了命令运行容器:

1
docker start

首先docker ps -a查询一下刚才创建的容器。
7

继续运行一下:

1
docker start -i 4040e711b2a3

8

我们发现和刚才的效果一样的,并且test.txt文件还在,说明容器是可写的。继续创建并运行一个新的容器:
9

我们发现新的容器8f4c252c6b0c没有test.txt文件,说明不同的容器直接是隔离的。
如果我们不需要8f4c252c6b0c容器了,可以通过docker rm 8f4c252c6b0c命令进行删除:
10

删除后,查询一下,发现8f4c252c6b0c容器不见了,说明删除成功。

小结

通常我们可以从Docker Hub下载一个镜像,然后根据镜像创建容器并运行,在容器中自定义功能后,创建新的镜像,然后上传新的镜像到服务器。下次继续分享制作镜像的详情内容,欢迎交流。

客户需求

酒店后台管理系统记录了合作酒店信息,一共300多页,每页10条数据,主要包括合作酒店的地区、价格、风险指数等信息,现在需要把这些信息整理成EXCEL,如果手工复制工作量大,而且容易出错,所以客户提出用爬虫采集数据并导出到EXCEL。

爬虫模拟

登陆

http://checkhrs.zzzdex.com/piston/login

login

列表页面

http://checkhrs.zzzdex.com/piston/hotel?page=1
list

详情页面

http://checkhrs.zzzdex.com/piston/hotel/xxxx/edit
detail

详细设计

流程

首先通过用户名密码登陆,然后打开第一页,接着打开每条记录的详情页,然后采集数据。接下来遍历第二页直到最后一页。

Scrapy

采用Python的Scrapy框架

1
pip install scrapy

核心源码

登陆成功后,自动处理cookie,这样就可以正常访问页面了。返回的数据格式为html,通过xpath进行解析。为了避免对服务器产生压力,在夜间爬取数据,并且在settings.py里面并且设置延时5S。

1
DOWNLOAD_DELAY = 5

hotel.py源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
import scrapy
from scrapy.selector import Selector
from scrapy.http import FormRequest

class HotelSpider(scrapy.Spider):
name = 'hotel'
allowed_domains = ['checkhrs.zzzdex.com']

login_url = 'http://checkhrs.zzzdex.com/piston/login'

url = 'http://checkhrs.zzzdex.com/piston/hotel'

start_urls = ['http://checkhrs.zzzdex.com/piston/hotel']

def login(self, response):
fd = {'username':'usernamexxx', 'password':'passwordxxx'}
yield FormRequest.from_response(response,
formdata = fd,
callback = self.parse_login)

def parse_login(self, response):
if 'usernamexxx' in response.text:
print("login success!")
yield from self.start_hotel_list()
else:
print("login fail!")

def start_requests(self):
yield scrapy.Request(self.login_url,
meta = {

},
encoding = 'utf8',
headers = {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36'
},
dont_filter = True,
callback = self.login)

def start_hotel_list(self):
yield scrapy.Request(self.url,
meta = {

},
encoding = 'utf8',
headers = {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36'
},
dont_filter = True)

def parse(self, response):
print("parse")
selector = Selector(response)

select_list = selector.xpath('//table//tbody//tr')

for sel in select_list:
address = sel.xpath('.//td[3]/text()').extract_first()

next_url = sel.xpath('.//td//a[text()="编辑"]/@href').extract_first()

next_url = response.urljoin(next_url)

print(next_url)

yield scrapy.Request(next_url,
meta = {
'address': address
},
encoding = 'utf8',
headers = {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36'
},
dont_filter = True,
callback = self.parseDetail)

totalStr = selector.xpath('//ul[@class="pagination"]//li[last()-1]//text()').extract_first();
print(totalStr)

pageStr = selector.xpath('//ul[@class="pagination"]//li[@class="active"]//text()').extract_first();
print(pageStr)

total = int(totalStr)
print(total)

page = int(pageStr)
print(page)

if page >= total:
print("last page")
else:
next_page = self.url + "?page=" + str(page + 1)
print("continue next page: " + next_page)
yield scrapy.Request(next_page,
meta = {
},
encoding = 'utf8',
headers = {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36'
},
dont_filter = True)

def parseDetail(self, response):
address = response.meta['address']
print("parseDetail address is " + address)

addresses = address.split('/')
print(addresses)

country = ""
province = ""
city = ""

address_len = len(addresses)

if address_len > 0:
country = addresses[0].strip()

if address_len > 1:
province = addresses[1].strip()

if address_len > 2:
city = addresses[2].strip()

selector = Selector(response)

hotelId = selector.xpath('//input[@id="id"]/@value').extract_first()

group_list = selector.xpath('//form//div[@class="form-group js_group"]')

hotelName = group_list[1].xpath('.//input[@id="hotel_name"]/@value').extract_first()

select_list = selector.xpath('//form//div[contains(@class,"company_container")]')
for sel in select_list:
company_list = sel.xpath('.//div[@class="panel-body"]//div[@class="form-group"]')

#公司
companyName = company_list[0].xpath('.//input[@id="company"]/@value').extract_first()

#单早
singlePrice = company_list[1].xpath('.//input/@value')[0].extract()

#双早
doublePrice = company_list[1].xpath('.//input/@value')[1].extract()

#风险指数
risk = company_list[2].xpath('.//input/@value').extract_first()

#备注
remark = company_list[3].xpath('.//input/@value').extract_first()

yield {
'ID': hotelId,
'国家': country,
'省份': province,
'城市': city,
'酒店名': hotelName,
'公司': companyName,
'单早': singlePrice,
'双早': doublePrice,
'风险指数': risk,
'备注': remark
}

运行

1
scrapy crawl hotel -o ./outputs/hotel.csv

从晚上10点开始爬,大概第二天中午数据全部采集完成,没有错误,最终输出成CSV,按照ID排序后转成EXCEL即可。
excel

小结

在日常工作中利用爬虫技术,可以提高工作效率,避免手重复劳动。

安装虚拟机

首先在windows机器上安装VirtualBox虚拟机,然后在虚拟机中安装CentOS操作系统,最后在CentOS中安装Docker。CentOS开启ssh服务后,通过mac远程连接CentOS,后续操作全部在mac机器上进行(非mac机器连接方式类似),本文结尾将演示Docker的HelloWorld例子。

安装VirtualBox

常见虚拟机软件包括VirtualBox和vmware,建议使用免费开源的VirtualBox,下载地址:https://www.virtualbox.org, 没有特别要求,下载最新版本即可,安装过程请参考网上教程。

安装CentOS

采用Linux系统学习Docker,建议使用CentOS操作系统
下载地址:https://www.centos.org/download/, 选择Everything ISO,从镜像链接中下载CentOS-7-x86_64-Everything-1708.iso。
由于网络受限,无法通过桥接的方式访问外网,所以网络链接方式选择“网络地址转换(NAT)”,虚拟机和windows主机共享一个IP地址。有条件的情况下,选择“桥接网卡”方式后续会更加方便一些。
8260ea86228f21cd9d058a9ef0b57432.jpg

修改hostname

执行命令:

hostnamectl set-hostname beyondspider
其中beyondspider为新的机器名称,根据实际情况修改。一旦修改了hostname,/etc/hostname将被自动更新。但是/etc/hosts不会更新,所以需要手动更新/etc/hosts,最终改完效果如下:
b2b9fe104617b54b5daa27a9c8a684ea.jpg

配置ssh

CentOS安装完之后默认已经启动了ssh服务, 可以通过如下步骤检查ssh服务是否启动。

查看端口22是否开放:
netstat -tnl
c099cfebad5e6c4b55784c7159f86414.jpg

查看ssh服务是否启动:

systemctl status sshd.service
d76c78aa5d20a2438cb3e5aa4b980faf.jpg

设置虚拟机网卡端口转发

由于NAT网络,外部无法访问虚拟机,所以设置端口转发来使用ssh服务
e9c2d0e0f53ddb798d1ca0e2981e204f.jpg

密码访问

ssh root@xx.xx.xx.xx
注意:需要根据提示输入密码。

证书访问

首先通过ssh-keygen命令生成公钥和私钥,然后用ssh-copy-id命令,自动保存公钥在对方主机的/root/.ssh/authorized_keys 文件中去
ssh-copy-id -i ~/.ssh/id_rsa.pub root@xx.xx.xx.xx
注意:需要根据提示输入密码, 下次就可以免密访问了。

ssh登录成功画面如下:
d7edb00bc85d5bdcaf1050d419fa835c.jpg

配置阿里云yum镜像

mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
yum clean all
rm -rf /var/cache/yum
yum makecache

安装Docker并启动

yum -y install docker
service docker start
检查docker版本
docker –version
a4314795ef391638e025e5bb55cc4123.jpg

修改docker加速镜像

访问阿里docker网页,登录后台获取专属加速地址, https://dev.aliyun.com

df39dbaf09550852962adad79495b200.jpg

修改后/etc/docker/daemon.json内容如下

2ecfedb19aa767b3b8c77c4a98083386.jpg

修改完记得重启docker

sudo systemctl daemon-reload
sudo systemctl restart docker

修改docker代理(可选)

如果网络不好,需要设置代理
创建文件/etc/systemd/system/docker.service.d/http-proxy.conf,参考如下内容修改:

[Service]
Environment=”HTTP_PROXY=http://proxy.xx.xx.xx:8080"

修改后效果如下:
3da4ceae821a9e259ce10bfa018e626d.jpg

修改完记得重启docker
sudo systemctl daemon-reload
sudo systemctl restart docker

运行hello-world

docker run hello-world

成功

看人如下页面表示成功,
786da34298447f7bb1d94046e8d4b59e.jpg

小结

到此,docker 在 CentOS 系统的安装完成。下回将讲解Docker镜像相关知识,欢迎交流。

简介

Charles is an HTTP proxy / HTTP monitor / Reverse Proxy that enables a developer to view all of the HTTP and SSL / HTTPS traffic between their machine and the Internet. This includes requests, responses and the HTTP headers (which contain the cookies and caching information).

支持平台

支持Mac、Windows、Linux三大操作系统。
支持http抓包,通过安装证书还可以支持https协议,支持手机抓包,包括Android和iOS。
下载地址:https://www.charlesproxy.com

charles使用

charles

小结

Charles和Fiddler可以同时使用,充分利用各种优势,具体的使用方式可以参考官网文档。

简介

Fiddler是一个http协议调试代理工具,它能够记录并检查所有你的电脑和互联网之间的http通讯,设置断点,查看所有的“进出”Fiddler的数据(指cookie,html,js,css等文件)。Fiddler要比其他的网络调试器要更加简单,因为它不仅仅暴露http通讯,还提供了一个用户友好的格式。

支持平台

支持Mac、Windows、Linux三大操作系统。
支持http抓包,通过安装证书还可以支持https协议,支持手机抓包,包括Android和iOS。
下载地址:www.telerik.com/fiddler

Fiddler使用

fiddler

小结

Fiddler目前是Windows上面非常流行的抓包软件,Mac是最近才支持的,所以功能比较弱,但是正常使用也够用了。如果需要更多的功能,推荐Charles抓包软件,可以免费或付费使用。

抓包

通常学习爬虫,第一步就是要抓包,然后分析网络请求的和结果,知道了数据格式之后就可以程序模拟浏览器的行为,从而实现数据采集的过程。所以抓包是非常重要的一个环节,下面我们利用Chrome浏览器自带功能进行抓包。

Chrome开发者模式

打开谷歌开发者模式, 点击“网络”标签页,可以查看Resquest和Response数据。

chrome-debug

小结

Chrome抓包能满足基本需求,但是功能有限,而且有时候Response数据丢失,所以推荐专业的抓包工具Fiddler和Charles。

超越爬虫beyondspider上线啦!程序员编程技术交流,包括前端、移动APP、Web网站、Restful API, 微服务、爬虫、docker、Jenkins、CI/CD等。

扫码关注公众号:beyondspider

logo