-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsearch.xml
253 lines (253 loc) · 181 KB
/
search.xml
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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title><![CDATA[SCRAPY框架]]></title>
<url>%2F2018%2F07%2F04%2Fspider-scrapy%2F</url>
<content type="text"><![CDATA[Scrapy 框架 Scrapy是用纯Python实现一个为了爬取网站数据、提取结构性数据而编写的应用框架,用途非常广泛。 框架的力量,用户只需要定制开发几个模块就可以轻松的实现一个爬虫,用来抓取网页内容以及各种图片,非常之方便。 Scrapy使用了Twisted(其主要对手是Tornado)异步网络框架来处理网络通讯,可以加快我们的下载速度,不用自己去实现异步框架,并且包含了各种中间件接口,可以灵活的完成各种需求。 Scrapy架构图 Scrapy Engine(引擎): 负责Spider、ItemPipeline、Downloader、Scheduler中间的通讯,信号、数据传递等。 Scheduler(调度器): 它负责接受引擎发送过来的Request请求,并按照一定的方式进行整理排列,入队,当引擎需要时,交还给引擎。 Downloader(下载器):负责下载Scrapy Engine(引擎)发送的所有Requests请求,并将其获取到的Responses交还给Scrapy Engine(引擎),由引擎交给Spider来处理, Spider(爬虫):它负责处理所有Responses,从中分析提取数据,获取Item字段需要的数据,并将需要跟进的URL提交给引擎,再次进入Scheduler(调度器), Item Pipeline(管道):它负责处理Spider中获取到的Item,并进行进行后期处理(详细分析、过滤、存储等)的地方. Downloader Middlewares(下载中间件):你可以当作是一个可以自定义扩展下载功能的组件。 Spider Middlewares(Spider中间件):你可以理解为是一个可以自定扩展和操作引擎和Spider中间通信的功能组件(比如进入Spider的Responses和从Spider出去的Requests)。 编写Scrapy爬虫的步骤 新建项目(scrapy startproject xxx):新建一个新的爬虫项目; 明确目标(编写items.py):明确你想要抓取的目标; 制作爬虫(spiders/xxspider.py):制作爬虫开始爬取网页; 存储内容(pipelines.py):设计管道存储爬取内容。 入门实例新建项目(scrapy startproject) 在开始爬取之前,必须创建一个新的Scrapy项目。进入自定义的项目目录中,运行下列命令: scrapy startproject mySpider 下面来简单介绍一下各个主要文件的作用: scrapy.cfg:项目的配置文件; mySpider/:项目的Python模块,将会从这里引用代码; mySpider/items.py:项目的目标文件; mySpider/pipelines.py:项目的管道文件; mySpider/settings.py:项目的设置文件; mySpider/spiders/:存储爬虫代码目录。 明确目标(mySpider/items.py)抓取的目标:https://hr.tencent.com/position.php?&start=0 腾讯社招网站里的所有职位的名称、工作地点、招聘人数、职位类别、工作职责以及工作要求。 打开mySpider目录下的items.py; Item定义结构化数据字段,用来保存爬取到的数据,有点像Python中的dict,但是提供了一些额外的保护减少错误。 可以通过创建一个scrapy.Item类,并且定义类型为scrapy.Field的类属性来定义一个Item(可以理解成类似于ORM的映射关系)。 接下来,创建一个TencentItem类,和构建item模型(model)。 制作爬虫(spiders/itcastSpider.py) 爬数据 取数据 Scrapy ShellScrapy终端是一个交互终端,我们可以在未启动spider的情况下尝试及调试代码,也可以用来测试XPath或CSS表达式,查看他们的工作方式,方便我们爬取的网页中提取的数据。 启动Scrapy Shell进入项目的根目录,执行下列命令来启动shell: scrapy shell “https://hr.tencent.com/position.php?&start=0“ Scrapy Shell根据下载的页面会自动创建一些方便使用的对象,例如Response对象,以及Selector对象(对HTML及XML内容)。 当shell载入后,将得到一个包含response数据的本地response变量,输入response.body将输出response的响应体,输出response.headers可以看到response的响应头。 输入response.selector时,将获取到一个response初始化的类Selector的对象,此时可以通过使用response.selector.xpath()或response.selector.css()来对response进行查询。 Scrapy也提供了一些快捷方式,例如response.xpath()或response.css()同样可以生效。 Selectors选择器Scrapy Selectors内置XPath和CSS Selector表达式机制 Selector有四个基本的方法,最常用的还是xpath: xpath(): 传入xpath表达式,返回该表达式所对应的所有节点的selector list列表; extract(): 序列化该节点为Unicode字符串并返回list; css(): 传入CSS表达式,返回该表达式所对应的所有节点的selector list列表,语法同BeautifulSoup4; re(): 根据传入的正则表达式对数据进行提取,返回Unicode字符串list列表。 Item Pipeline当Item在Spider中被收集之后,它将会被传递到Item Pipeline,这些Item Pipeline组件按定义的顺序处理Item。 每个Item Pipeline都是实现了简单方法的Python类,比如决定此Item是丢弃还是存储。以下是item pipeline的一些典型应用: 验证爬取的数据(检查item包含某些字段,比如说name字段) 查重(并丢弃) 将爬取结果保存到文件或者数据库中 编写item pipelineitem pipiline组件是一个独立的Python类,其中process_item()方法必须实现。 123456789101112131415161718192021import somethingclass SomethingPipeline(object): def __init__(self): # 可选实现,做参数初始化等 # doing something def process_item(self, item, spider): # item (Item 对象) – 被爬取的item # spider (Spider 对象) – 爬取该item的spider # 这个方法必须实现,每个item pipeline组件都需要调用该方法, # 这个方法必须返回一个 Item 对象,被丢弃的item将不会被之后的pipeline组件所处理。 return item def open_spider(self, spider): # spider (Spider 对象) – 被开启的spider # 可选实现,当spider被开启时,这个方法被调用。 def close_spider(self, spider): # spider (Spider 对象) – 被关闭的spider # 可选实现,当spider被关闭时,这个方法被调用 数据写入json文件item写入JSON文件以下pipeline将所有(从所有’spider’中)爬取到的item,存储到一个独立地items.json 文件,每行包含一个序列化为JSON格式的item: 1234567891011121314import jsonclass TencentJsonPipeline(object): def __init__(self): self.file = open('tencent.json', 'wb') def process_item(self, item, spider): content = json.dumps(dict(item), ensure_ascii=False) + "\n" self.file.write(content) return item def close_spider(self, spider): self.file.close() 启用一个Item Pipeline组件为了启用Item Pipeline组件,必须将它的类添加到settings.py文件ITEM_PIPELINES配置,例如: 123456# Configure item pipelines# See http://scrapy.readthedocs.org/en/latest/topics/item-pipeline.htmlITEM_PIPELINES = { #'mySpider.pipelines.SomePipeline': 300, "mySpider.pipelines.TencentJsonPipeline":300} 分配给每个类的整型值,确定了他们运行的顺序,item按数字从低到高的顺序,通过pipeline,通常将这些数字定义在0-1000范围内(0-1000随意设置,数值越低,组件的优先级越高) SpiderSpider类定义了如何爬取某个(或某些)网站。包括了爬取的动作(例如:是否跟进链接)以及如何从网页的内容中提取结构化数据(爬取item)。 换句话说,Spider就是定义爬取的动作及分析某个网页(或者是有些网页)的地方。 class scrapy.Spider是最基本的类,所有编写的爬虫必须继承这个类。 主要用到的函数及调用顺序为: __init__():初始化爬虫名字和start_urls列表 start_requests()调用make_requests_from url()生成Requests对象交给Scrapy下载并返回response parse():解析response,并返回Item或Requests(需指定回调函数)。Item传给Item pipline持久化,而Requests交由Scrapy下载,并由指定的回调函数处理(默认parse()),一直进行循环,直到处理完所有的数据为止。 CrawlSpiders]]></content>
<categories>
<category>Spider</category>
</categories>
<tags>
<tag>Spider</tag>
<tag>Scrapy</tag>
<tag>data fetch</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Linux的shell编程详解]]></title>
<url>%2F2018%2F07%2F04%2FLinux-shell-explanation%2F</url>
<content type="text"><![CDATA[shell历史Shell的作用是解释执行用户的命令,用户输入一条命令,Shell就解释执行一条,这种方式称为交互式(Interactive),Shell还有一种执行命令的方式称为批处理(Batch),用户事先写一个Shell脚本(Script),其中有很多条命令,让Shell一次把这些命令执行完,而不必一条一条地敲命令。Shell脚本和编程语言很相似,也有变量和流程控制语句,但Shell脚本是解释执行的,不需要编译,Shell程序从脚本中一行一行读取并执行这些命令,相当于一个用户把脚本中的命令一行一行敲到Shell提示符下执行。 由于历史原因,UNIX系统上有很多种Shell: sh(Bourne Shell):由Steve Bourne开发,各种UNIX系统都配有sh。 csh(C Shell):由Bill Joy开发,随BSD UNIX发布,它的流程控制语句很像C语言,支持很多Bourne Shell所不支持的功能:作业控制,命令历史,命令行编辑。 ksh(Korn Shell):由David Korn开发,向后兼容sh的功能,并且添加了csh引入的新功能,是目前很多UNIX系统标准配置的Shell,在这些系统上/bin/sh往往是指向/bin/ksh的符号链接。 tcsh(TENEX C Shell):是csh的增强版本,引入了命令补全等功能,在FreeBSD、Mac OS X等系统上替代了csh。 bash(Bourne Again Shell):由GNU开发的Shell,主要目标是与POSIX标准保持一致,同时兼顾对sh的兼容,bash从csh和ksh借鉴了很多功能,是各种Linux发行版标准配置的Shell,在Linux系统上/bin/sh往往是指向/bin/bash的符号链接。虽然如此,bash和sh还是有很多不同的,一方面,bash扩展了一些命令和参数,另一方面,bash并不完全和sh兼容,有些行为并不一致,所以bash需要模拟sh的行为:当我们通过sh这个程序名启动bash时,bash可以假装自己是sh,不认扩展的命令,并且行为与sh保持一致。 zsh 的命令补全功能非常强大,可以补齐路径,补齐命令,补齐参数等。 用户在命令行输入命令后,一般情况下Shell会fork并exec该命令,但是Shell的内建命令例外,执行内建命令相当于调用Shell进程中的一个函数,并不创建新的进程。例如cd、alias、umask、exit等命令都是内建命令,凡是用which命令查不到程序文件所在位置的命令都是内建命令,内建命令没有单独的man手册,要在man手册中查看内建命令: $ man bash-builtins 如export、shift、if、eval、[、for、while等等。内建命令虽然不创建新的进程,但也会有Exit Status,通常也用0表示成功非零表示失败,虽然内建命令不创建新的进程,但执行结束后也会有一个状态码,也可以用特殊变量$?读出。 执行脚本编写一个简单的脚本test.sh: 123#! /bin/shcd ..ls Shell脚本中用#表示注释,相当于C语言的//注释。但如果#位于第一行开头,并且是#!(称为Shebang)则例外,它表示该脚本使用后面指定的解释器/bin/sh解释执行。 Shell会fork一个子进程并调用exec执行./test.sh这个程序,exec系统调用应该把子进程的代码段替换成./test.sh程序的代码段,并从它的_start开始执行。然而test.sh是个文本文件,根本没有代码段和_start函数,怎么办呢?其实exec还有另外一种机制,如果要执行的是一个文本文件,并且第一行用Shebang指定了解释器,则用解释器程序的代码段替换当前进程,并且从解释器的_start开始执行,而这个文本文件被当作命令行参数传给解释器。 如果将命令行下输入的命令用()括号括起来,那么也会fork出一个子Shell执行小括号中的命令,一行中可以输入由分号;隔开的多个命令,比如: 1$ (cd ..;ls -l) 基本语法变量按照惯例,Shell变量由全大写字母加下划线组成,有两种类型的Shell变量: 环境变量环境变量可以从父进程传给子进程,因此Shell进程的环境变量可以从当前Shell进程传给fork出来的子进程。用printenv命令可以显示当前Shell进程的环境变量。 本地变量只存在于当前Shell进程,用set命令可以显示当前Shell进程中定义的所有变量(包括本地变量和环境变量)和函数。环境变量是任何进程都有的概念,而本地变量是Shell特有的概念。在Shell中,环境变量和本地变量的定义和用法相似。在Shell中定义或赋值一个变量: 1$ VARNAME=value 注意等号两边都不能有空格,否则会被Shell解释成命令和命令行参数。 一个变量定义后仅存在于当前Shell进程,它是本地变量,用export命令可以把本地变量导出为环境变量,定义和导出环境变量通常可以一步完成: 1$ export VARNAME=value 用unset命令可以删除已定义的环境变量或本地变量。 在定义变量时不用$,取变量值时要用$。和C语言不同的是,Shell变量不需要明确定义类型,事实上Shell变量的值都是字符串,比如我们定义VAR=45,其实VAR的值是字符串45而非整数。Shell变量不需要先定义后使用,如果对一个没有定义的变量取值,则值为空字符串。 文件名代换(Globbing):* ? []这些用于匹配的字符称为通配符(Wildcard),具体如下: * 匹配0个或多个任意字符 ? 匹配一个任意字符 [若干字符] 匹配方括号中任意一个字符的一次出现 1234$ ls /dev/ttyS*$ ls ch0?.doc$ ls ch0[0-2].doc$ ls ch[012] [0-9].doc 注意,Globbing所匹配的文件名是由Shell展开的,也就是说在参数还没传给程序之前已经展开了,比如上述ls ch0[012].doc命令,如果当前目录下有ch00.doc和ch02.doc,则传给ls命令的参数实际上是这两个文件名,而不是一个匹配字符串。 命令代换:`或 $()由`反引号括起来的也是一条命令,Shell先执行该命令,然后将输出结果立刻代换到当前命令行中。例如定义一个变量存放date命令的输出: 1234$ DATE=`date`$ echo $DATE$ DATE=$(date) 算术代换:$(())用于算术计算,$(())中的Shell变量取值将转换成整数,同样含义的$[]等价例如: 123456789VAR=45echo $(($VAR+3))# $(())中只能用+-*/和()运算符,并且只能做整数运算。# $[base#n],其中base表示进制,n按照base进制解释,后面再有运算数,按十进制解释。echo $[2#10+11]echo $[8#10+11]echo $[10#10+11] 转义字符\和C语言类似,\在Shell中被用作转义字符,用于去除紧跟其后的单个字符的特殊意义(回车除外),换句话说,紧跟其后的字符取字面值。例如: 123456$ echo $SHELL/bin/bash$ echo \$SHELL$SHELL$ echo \\\ 比如创建一个文件名为“$ $”的文件可以这样: 1$ touch \$\ \$ 还有一个字符虽然不具有特殊含义,但是要用它做文件名也很麻烦,就是-号。如果要创建一个文件名以-号开头的文件,则可以: 12$ touch ./-hello$ touch -- -hello 单引号和C语言不一样,Shell脚本中的单引号和双引号一样都是字符串的界定符,而不是字符的界定符。单引号用于保持引号内所有字符的字面值,即使引号内的\和回车也不例外,但是字符串中不能出现单引号。如果引号没有配对就输入回车,Shell会给出续行提示符,要求用户把引号配上对。 双引号被双引号用括住的内容,将被视为单一字串。它防止通配符扩展,但允许变量扩展。这点与单引号的处理方式不同。 123$ DATE=$(date)$ echo "$DATE"$ echo '$DATE' Shell脚本语法条件测试:test [命令test或[可以测试一个条件是否成立,如果测试结果为真,则该命令的Exit Status为0,如果测试结果为假,则命令的Exit Status为1(注意与C语言的逻辑表示正好相反)。例如测试两个数的大小关系: 12345678910$ var=2$ test $var -gt 1$ echo $?0$ test $var -gt 3$ echo $?1$ [ $var -gt 3 ]$ echo $?1 虽然看起来很奇怪,但左方括号[确实是一个命令的名字,传给命令的各参数之间应该用空格隔开,比如,$VAR、-gt、3、]是[命令的四个参数,它们之间必须用空格隔开。命令test或[的参数形式是相同的,只不过test命令不需要]参数。以[命令为例,常见的测试命令如下所示: [ -d DIR ] 如果DIR存在并且是一个目录则为真 [ -f FILE ] 如果FILE存在且是一个普通文件则为真 [ -z STRING ] 如果STRING的长度为零则为真 [ -n STRING ] 如果STRING的长度非零则为真 [ STRING1 = STRING2 ] 如果两个字符串相同则为真 [ STRING1 != STRING2 ] 如果字符串不相同则为真 [ ARG1 OP ARG2 ] ARG1和ARG2应该是整数或者取值为整数的变量,OP是-eq(等于)-ne(不等于)-lt(小于)-le(小于等于)-gt(大于)-ge(大于等于)之中的一个 测试条件之间还可以做与、或、非逻辑运算: 123[ ! EXPR ] EXPR可以是上表中的任意一种测试条件,!表示逻辑反[ EXPR1 -a EXPR2 ] EXPR1和EXPR2可以是上表中的任意一种测试条件,-a表示逻辑与[ EXPR1 -o EXPR2 ] EXPR1和EXPR2可以是上表中的任意一种测试条件,-o表示逻辑或 例如: 1234$ VAR=abc$ [ -d Desktop -a "$VAR" = 'abc' ]$ echo $?0 注意,如果上例中的$VAR变量事先没有定义,则被Shell展开为空字符串,会造成测试条件的语法错误(展开为[ -d Desktop -a = ‘abc’ ]),作为一种好的Shell编程习惯,应该总是把变量取值放在双引号之中(展开为[ -d Desktop -a “” = ‘abc’ ]) if/then/elif/else/fi和C语言类似,在Shell中用if、then、elif、else、fi这几条命令实现分支控制。这种流程控制语句本质上也是由若干条Shell命令组成的,例如: 123if [ -f ~/.bashrc ]; then . ~/.bashrcfi 其实是三条命令,if [ -f ~/.bashrc ]是第一条,then . ~/.bashrc是第二条,fi是第三条。如果两条命令写在同一行则需要用;号隔开,一行只写一条命令就不需要写;号了,另外,then后面有换行,但这条命令没写完,Shell会自动续行,把下一行接在then后面当作一条命令处理。和[命令一样,要注意命令和各参数之间必须用空格隔开。if命令的参数组成一条子命令,如果该子命令的Exit Status为0(表示真),则执行then后面的子命令,如果Exit Status非0(表示假),则执行elif、else或者fi后面的子命令。if后面的子命令通常是测试命令,但也可以是其它命令。Shell脚本没有{}括号,所以用fi表示if语句块的结束。例如: 12345678#! /bin/shif [ -f /bin/bash ] then echo "/bin/bash is a file"else echo "/bin/bash is NOT a file"fiif :; then echo "always true"; fi :是一个特殊的命令,称为空命令,该命令不做任何事,但Exit Status总是真。此外,也可以执行/bin/true或/bin/false得到真或假的Exit Status。例如: 12345678910111213 #! /bin/shecho "Is it morning? Please answer yes or no."read YES_OR_NOif [ "$YES_OR_NO" = "yes" ]; then echo "Good morning!"elif [ "$YES_OR_NO" = "no" ]; then echo "Good afternoon!"else echo "Sorry, $YES_OR_NO not recognized. Enter yes or no." exit 1fiexit 0 上例中的read命令的作用是等待用户输入一行字符串,将该字符串存到一个Shell变量中。此外,Shell还提供了&&和||语法,和C语言类似,具有Short-circuit特性。 case/esaccase命令可类比C语言的switch/case语句,esac表示case语句块的结束。C语言的case只能匹配整型或字符型常量表达式,而Shell脚本的case可以匹配字符串和Wildcard,每个匹配分支可以有若干条命令,末尾必须以;;结束,执行时找到第一个匹配的分支并执行相应的命令,然后直接跳到esac之后,不需要像C语言一样用break跳出。 1234567891011121314#! /bin/shecho "Is it morning? Please answer yes or no."read YES_OR_NOcase "$YES_OR_NO" in yes|y|Yes|YES) echo "Good Morning!";; [nN]*) echo "Good Afternoon!";; *) echo "Sorry, $YES_OR_NO not recognized. Enter yes or no." exit 1;;esacexit 0 for/do/doneShell脚本的for循环结构和C语言很不一样,它类似于某些编程语言的foreach循环。例如: 12345#! /bin/shfor FRUIT in apple banana pear; do echo "I like $FRUIT"done while/do/donewhile的用法和C语言类似。比如一个验证密码的脚本: 12345678#! /bin/shecho "Enter password:"read TRYwhile [ "$TRY" != "secret" ]; do echo "Sorry, try again" read TRYdone 下面的例子通过算术运算控制循环的次数: 1234567#! /bin/shCOUNTER=1while [ "$COUNTER" -lt 10 ]; do echo "Here we go again" COUNTER=$(($COUNTER+1))done 位置参数和特殊变量常用的位置参数和特殊变量 参数 含义 $0 相当于C语言main函数的argv[0] $1、$2… 这些称为位置参数(Positional Parameter),相当于C语言main函数的argv[1]、argv[2]… $# 相当于C语言main函数的argc - 1,注意这里的#后面不表示注释 $@ 表示参数列表”$1” “$2” …,例如可以用在for循环中的in后面。 $* 表示参数列表”$1” “$2” …,同上 $? 上一条命令的Exit Status $$ 当前进程号 位置参数可以用shift命令左移。比如shift 3表示原来的$4现在变成$1,原来的$5现在变成$2等等,原来的$1、$2、$3丢弃,$0不移动。不带参数的shift命令相当于shift 1。例如: 12345678910#! /bin/shecho "The program $0 is now running"echo "The first parameter is $1"echo "The second parameter is $2"echo "The parameter list is $@"shiftecho "The first parameter is $1"echo "The second parameter is $2"echo "The parameter list is $@" shell输入输出echoecho显示文本行或变量,或者把字符串输入到文件。 echo [option] string -e 解析转义字符 -n 不回车换行。默认情况echo回显的内容后面跟一个回车换行。 echo “hello\n\n” echo -e “hello\n\n” echo “hello” echo -n “hello” 管道|可以通过管道把一个命令的输出传递给另一个命令做输入。管道用竖线表示。 teetee命令把结果输出到标准输出,另一个副本输出到相应文件。 文件重定向 cmd > file 把标准输出重定向到新文件中 cmd >> file 追加 cmd > file 2>&1 标准出错也重定向到1所指向的file里 cmd >> file 2>&1 cmd < file1 > file2 输入输出都定向到文件里 cmd < &fd 把文件描述符fd作为标准输入 cmd > &fd 把文件描述符fd作为标准输出 cmd < &- 关闭标准输入 函数和C语言类似,Shell中也有函数的概念,但是函数定义中没有返回值也没有参数列表。例如: 123456#! /bin/shfoo(){ echo "Function foo is called";}echo "-=start=-"fooecho "-=end=-" 注意函数体的左花括号’{‘和后面的命令之间必须有空格或换行,如果将最后一条命令和右花括号’}’写在同一行,命令末尾必须有;号。 在定义foo()函数时并不执行函数体中的命令,就像定义变量一样,只是给foo这个名字一个定义,到后面调用foo函数的时候(注意Shell中的函数调用不写括号)才执行函数体中的命令。Shell脚本中的函数必须先定义后调用,一般把函数定义都写在脚本的前面,把函数调用和其它命令写在脚本的最后(类似C语言中的main函数,这才是整个脚本实际开始执行命令的地方)。 Shell函数没有参数列表并不表示不能传参数,事实上,函数就像是迷你脚本,调用函数时可以传任意个参数,在函数内同样是用$0、$1、$2等变量来提取参数,函数中的位置参数相当于函数的局部变量,改变这些变量并不会影响函数外面的$0、$1、$2等变量。函数中可以用return命令返回,如果return后面跟一个数字则表示函数的Exit Status。 下面这个脚本可以一次创建多个目录,各目录名通过命令行参数传入,脚本逐个测试各目录是否存在,如果目录不存在,首先打印信息然后试着创建该目录。 123456789101112131415161718192021222324#! /bin/shis_directory(){ DIR_NAME=$1 if [ ! -d $DIR_NAME ]; then return 1 else return 0 fi}for DIR in "$@"; do if is_directory "$DIR" then : else echo "$DIR doesn't exist. Creating it now..." mkdir $DIR > /dev/null 2>&1 if [ $? -ne 0 ]; then echo "Cannot create directory $DIR" exit 1 fi fidone Shell脚本的调试方法Shell提供了一些用于调试脚本的选项,如下所示: 选项 说明 -n 读一遍脚本中的命令但不执行,用于检查脚本中的语法错误 -v 一边执行脚本,一边将执行过的脚本命令打印到标准错误输出 -x 提供跟踪执行信息,将执行的每一条命令和结果依次打印出来 使用这些选项有三种方法: 在命令行提供参数 $ sh -x ./script.sh 在脚本开头提供参数 #! /bin/sh -x 在脚本中用set命令启用或禁用参数 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261 #! /bin/sh if [ -z "$1" ]; then set -x echo "ERROR: Insufficient Args." exit 1 set +x fi ``` *其中,set -x和set +x分别表示启用和禁用-x参数,这样可以只对脚本中的某一段进行跟踪调试。* ### 正则表达式正则表达式:规定一些特殊语法表示字符类、数量限定符和位置关系,然后用这些特殊语法和普通字符一起表示一个模式。 #### 基本语法我们知道C的变量和Shell脚本变量的定义和使用方法很不相同,表达能力也不相同,C的变量有各种类型,而Shell脚本变量都是字符串。同样道理,各种工具和编程语言所使用的正则表达式规范的语法并不相同,表达能力也各不相同,有的正则表达式规范引入很多扩展,能表达更复杂的模式,但各种正则表达式规范的基本概念都是相通的。##### 字符类|字符|含义|例子||:---|---|--------|.| 匹配任意一个字符| abc.可以匹配abcd、abc9等[]| 匹配括号中的任意一个字符| [abc]d可以匹配ad、bd或cd-| 在[]括号内表示字符范围| [0-9a-fA-F]可以匹配一位十六进制数字^| 位于[]括号内的开头,匹配除括号中的字符之外的任意一个字符| [^xy]匹配除xy之外的任一字符,因此[^xy]1可以匹配a1、b1但不匹配x1、y1[[:xxx:]]| grep工具预定义的一些命名字符类| [[:alpha:]]匹配一个字母,[[:digit:]]匹配一个数字##### 数量限定符|字符|含义|例子||:---|---|---------|?| 紧跟在它前面的单元应匹配零次或一次| [0-9]?\.[0-9]匹配0.0、2.3、.5等,由于.在正则表达式中是一个特殊字符,所以需要用\转义一下,取字面值+| 紧跟在它前面的单元应匹配一次或多次| [a-zA-Z0-9_.-]+@[a-zA-Z0-9_.-]+\.[a-zA-Z0-9_.-]+匹配email地址*| 紧跟在它前面的单元应匹配零次或多次| [0-9][0-9]*匹配至少一位数字,等价于[0-9]+,[a-zA-Z_]+[a-zA-Z_0-9]*匹配C语言的标识符{N}| 紧跟在它前面的单元应精确匹配N次| [1-9][0-9]{2}匹配从100到999的整数{N,}| 紧跟在它前面的单元应匹配至少N次| [1-9][0-9]{2,}匹配三位以上(含三位)的整数{,M}| 紧跟在它前面的单元应匹配最多M次| [0-9]{,1}相当于[0-9]?{N,M}| 紧跟在它前面的单元应匹配至少N次,最多M次| [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}匹配IP地址##### 位置限定符|字符|含义|例子||:---|----|-------------||^| 匹配行首的位置| ^Content匹配位于一行开头的Content|$| 匹配行末的位置| ;$匹配位于一行结尾的;号,^$匹配空行|\\<| 匹配单词开头的位置| \\<th匹配... this,但不匹配ethernet、tenth|\\>| 匹配单词结尾的位置| p\\>匹配leap ...,但不匹配parent、sleepy|\\b| 匹配单词开头或结尾的位置| \bat\b匹配... at ...,但不匹配cat、atexit、batch|\\B| 匹配非单词开头和结尾的位置| \Bat\B匹配battery,但不匹配... attend、hat ...##### 其它特殊字符|字符|含义|例子||:---|----|-------||\|转义字符,普通字符转义为特殊字符,特殊字符转义为普通字符| 普通字符<写成\\<表示单词开头的位置,特殊字符.写成\\.以及\写成\\\\就当作普通字符来匹配|()|将正则表达式的一部分括起来组成一个单元,可以对整个单元使用数量限定符| ([0-9]{1,3}\.){3}[0-9]{1,3}匹配IP地址|&#124;|连接两个子表达式,表示或的关系|n(o &#124; either)匹配no或neither### grep#### 作用Linux系统中grep命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹 配的行打印出来。grep全称是Global Regular Expression Print,表示全局正则表达式版本,它的使用权限是所有用户。grep家族包括grep、egrep和fgrep。egrep和fgrep的命令只跟grep有很小不同。egrep是grep的扩展,支持更多的re元字符, fgrep就是fixed grep或fast grep,它们把所有的字母都看作单词,也就是说,正则表达式中的元字符表示回其自身的字面意义,不再特殊。linux使用GNU版本的grep。它功能更强,可以通过-G、-E、-F命令行选项来使用egrep和fgrep的功能。#### 格式> grep [option]#### 主要参数> grep --help [options]主要参数: -c:只输出匹配行的计数。 -i:不区分大小写。 -h:查询多文件时不显示文件名。 -l:查询多文件时只输出包含匹配字符的文件名。 -n:显示匹配行及行号。 -s:不显示不存在或无匹配文本的错误信息。 -v:显示不包含匹配文本的所有行。 --color=auto :可以将找到的关键词部分加上颜色的显示。 #### pattern正则表达式主要参数> \: 忽略正则表达式中特殊字符的原有含义。 ^:匹配正则表达式的开始行。 $: 匹配正则表达式的结束行。 \\<:从匹配正则表达式的行开始。 \\>:到匹配正则表达式的行结束。 [ ]:单个字符,如[A]即A符合要求。 [ - ]:范围,如[A-Z],即A、B、C一直到Z都符合要求。 .:所有的单个字符。 *:有字符,长度可以为0。 #### grep命令使用简单实例> $ grep 'test' d\* 显示所有以d开头的文件中包含test的行。 &emsp; $ grep 'test' aa bb cc 显示在aa,bb,cc文件中匹配test的行。 &emsp; $ grep '[a-z]\{5\}' aa 显示所有包含每个字符串至少有5个连续小写字符的字符串的行。 &emsp; $ grep 'w\(es\)t.\*\1' aa 如果west被匹配,则es就被存储到内存中,并标记为1,然后搜索任意个字符(.\*),这些字符后面紧跟着另外一个es(\1),找到就显示该行。如果用egrep或grep -E,就不用”\”号进行转义,直接写成'w(es)t.*\1'就可以了。 #### grep命令使用复杂实例> grep -i pattern files:不区分大小写地搜索。默认情况区分大小写。 grep -l pattern files:只列出匹配的文件名。 grep -L pattern files:列出不匹配的文件名。 grep -w pattern files:只匹配整个单词,而不是字符串的一部分(如匹配’magic’,而不是’magical’)。 grep -C number pattern files:匹配的上下文分别显示[number]行。 grep pattern1 | pattern2 files:显示匹配pattern1或pattern2的行。 例如:grep "abc\|xyz" testfile:表示过滤包含abc或xyz的行 grep pattern1 files | grep pattern2:显示既匹配pattern1又匹配pattern2的行。 grep -n pattern files:即可显示行号信息 grep -c pattern files:即可查找总行数 用于搜索的特殊符号> \\< 和 \\> 分别标注单词的开始与结尾。 &emsp; 例如: grep man \*:匹配'Batman'、'manic'、'man'等; grep '\<man' \* 匹配'manic'和'man',但不是'Batman'; grep '\<man\>' 只匹配'man',而不是'Batman'或'manic'等其他的字符串。 '^':指匹配的字符串在行首; '$':指匹配的字符串在行尾。 ### find#### find命令格式> find pathname -options [-print -exec -ok ...]#### find命令参数|参数|说明||:---|---------||pathname|查找的目录路径。例如用.来表示当前目录,用/来表示系统根目录,递归查找。|-print|将匹配的文件输出到标准输出。|-exec|对匹配的文件执行该参数所给出的shell命令。相应命令的形式为'command' { } \;,注意{ }和\;之间的空格。|-ok|和-exec的作用相同,只不过以一种更为安全的模式来执行该参数所给出的shell命令,在执行每一个命令之前,都会给出提示,让用户来确定是否执行。#### find命令选项|选项|说明||:---|---------||-name|按照文件名查找文件||-perm|按照文件权限来查找文件||-prune|使用这一选项可以使find命令不在当前指定的目录中查找,如果同时使用-depth选项,那么-prune将被find命令忽略||-user|按照文件属主来查找文件||-group|按照文件所属的组来查找文件||-mtime -n +n|按照文件的更改时间来查找文件,-n表示文件更改时间距现在n天以内,+n表示文件更改时间距现在n天以前。find命令还有-atime和-ctime 选项,但它们都和-m time选项||-nogroup|查找无有效所属组的文件,即该文件所属的组在/etc/groups中不存在||-nouser|查找无有效属主的文件,即该文件的属主在/etc/passwd中不存在||-newer file1 ! file2|查找更改时间比文件file1新但比文件file2旧的文件||-type|查找某一类型的文件,诸如:b - 块设备文件。d - 目录。c - 字符设备文件。p - 管道文件。l - 符号链接文件。f - 普通文件||-size n:[c]|查找文件长度为n块的文件,带有c时表示文件长度以字节计||-depth|在查找文件时,首先查找当前目录中的文件,然后再在其子目录中查找||-fstype|查找位于某一类型文件系统中的文件,这些文件系统类型通常可以在配置文件/etc/fstab中找到,该配置文件中包含了本系统中有关文件系统的信息||-mount|在查找文件时不跨越文件系统mount点||-follow|如果find命令遇到符号链接文件,就跟踪至链接所指向的文件|下面三个的区别:> -amin n 查找系统中最后N分钟访问的文件 -atime n 查找系统中最后n*24小时访问的文件 -cmin n 查找系统中最后N分钟被改变文件状态的文件 -ctime n 查找系统中最后n*24小时被改变文件状态的文件 -mmin n 查找系统中最后N分钟被改变文件数据的文件 -mtime n 查找系统中最后n*24小时被改变文件数据的文件 #### 使用exec或ok来执行shell命令使用find时,只要把想要的操作写在一个文件里,就可以用exec来配合find查找,很方便 在有些操作系统中只允许-exec选项执行诸如ls或ls -l这样的命令。大多数用户使用这一选项是为了查找旧文件并删除它们。建议在真正执行rm命令删除文件之前,最好先用ls命令看一下,确认它们是所要删除的文件。exec选项后面跟随着所要执行的命令或脚本,然后是一对儿{},一个空格和一个\\,最后是一个分号。为了使用exec选项,必须要同时使用print选项。如果验证一下find命令,会发现该命令只输出从当前路径起的相对路径及文件名。 例如:为了用ls -l命令列出所匹配到的文件,可以把ls -l命令放在find命令的-exec选项中:> $ find . -type f -exec ls -l {} \;上面的例子中,find命令匹配到了当前目录下的所有普通文件,并在-exec选项中使用ls -l命令将它们列出。在/logs目录中查找更改时间在5日以前的文件并删除它们:> $ find logs -type f -mtime +5 -exec rm {} \;在下面的例子中, find命令在当前目录中查找所有文件名以.LOG结尾、更改时间在5日以上的文件,并删除它们,只不过在删除之前先给出提示:> $ find . -name "*.conf" -mtime +5 -ok rm { } \;在下面的例子中使用grep命令。find命令首先匹配所有文件名为“ passwd*”的文件,例如passwd、passwd.old、passwd.bak,然后执行grep命令看看在这些文件中是否存在一个root用户:> \# find /etc -name "passwd*" -exec grep "itcast" { } \;### xargs在使用find命令的-exec选项处理匹配到的文件时, find命令将所有匹配到的文件一起传递给exec执行。但有些系统对能够传递给exec的命令长度有限制,这样在find命令运行几分钟之后,就会出现 溢出错误。错误信息通常是“参数列太长”或“参数列溢出”。这就是xargs命令的用处所在,特别是与find命令一起使用。 find命令把匹配到的文件传递给xargs命令,而xargs命令每次只获取一部分文件而不是全部,不像-exec选项那样。这样它可以先处理最先获取的一部分文件,然后是下一批,并如此继续下去。 在有些系统中,使用-exec选项会为处理每一个匹配到的文件而发起一个相应的进程,并非将匹配到的文件全部作为参数一次执行;这样在有些情况下就会出现进程过多,系统性能下降的问题,因而效率不高。 而使用xargs命令则只有一个进程。另外,在使用xargs命令时,究竟是一次获取所有的参数,还是分批取得参数,以及每一次获取参数的数目都会根据该命令的选项及系统内核中相应的可调参数来确定。 下面的例子查找系统中的每一个普通文件,然后使用xargs命令来测试它们分别属于哪类文件:> \# find . -type f -print | xargs file在当前目录下查找所有用户具有读、写和执行权限的文件,并收回相应的写权限:> \# ls -l \# find . -perm -7 -print | xargs chmod o-w \# ls -l 用grep命令在所有的普通文件中搜索hello这个词:> \# find . -type f -print | xargs grep "hello"用grep命令在当前目录下的所有普通文件中搜索hello这个词:> \# find . -name \\* -type f -print | xargs grep "hello"### sedsed意为流编辑器(Stream Editor),在Shell脚本和Makefile中作为过滤器使用非常普遍,也就是把前一个程序的输出引入sed的输入,经过一系列编辑命令转换为另一种格式输出。sed和vi都源于早期UNIX的ed工具,所以很多sed命令和vi的末行命令是相同的。#### sed命令行的基本格式> sed option 'script' file1 file2 ... sed option -f scriptfile file1 file2 ... #### 选项含义|选项|说明||:---:|---||--version| 显示sed版本。|--help| 显示帮助文档。|-n,--quiet,--silent| 静默输出,默认情况下,sed程序在所有的脚本指令执行完毕后,将自动打印模式空间中的内容,这些选项可以屏蔽自动打印。|-e script| 允许多个脚本指令被执行。|-f script-file, --file=script-file| 从文件中读取脚本指令,对编写自动脚本程序来说很棒!|-i,--in-place| 直接修改源文件,经过脚本指令处理后的内容将被输出至源文件(源文件被修改)慎用!|-l N, --line-length=N| 该选项指定l指令可以输出的行长度,l指令用于输出非打印字符。|--posix| 禁用GNU sed扩展功能。|-r, --regexp-extended| 在脚本指令中使用扩展正则表达式|-s, --separate| 默认情况下,sed将把命令行指定的多个文件名作为一个长的连续的输入流。而GNU sed则允许把他们当作单独的文件,这样如正则表达式则不进行跨文件匹配。|-u, --unbuffered| 最低限度的缓存输入与输出```commandline# 在输出testfile内容的第二行后添加"hello"$ sed "2a hello" ./testfile$ sed "2,5d" testfile 常用的sed命令 /pattern/p 打印匹配pattern的行 /pattern/d 删除匹配pattern的行 /pattern/s/pattern1/pattern2/ 查找符合pattern的行,将该行第一个匹配pattern1的字符串替换为pattern2 /pattern/s/pattern1/pattern2/g 查找符合pattern的行,将该行所有匹配pattern1的字符串替换为pattern2 使用p命令需要注意,sed是把待处理文件的内容连同处理结果一起输出到标准输出的,因此p命令表示除了把文件内容打印出来之外还额外打印一遍匹配pattern的行。要想只输出处理结果,应加上-n选项。 例如,testfile.txt文件的内容如下: 123 abc 456 123456789101112131415161718192021222324252627282930$ sed '/abc/p' testfile123abcabc456$ sed -n '/abc/p' testfileabc$ sed '/abc/d' testfile123456$ sed 's/bc/-&-/' testfile123a-bc-456# pattern2中的&表示原文件的当前行中与pattern1相匹配的字符串$ sed 's/\([0-9]\)\([0-9]\)/-\1-~\2~/' testfile-1-~2~3abc-4-~5~6# pattern2中的\1表示与pattern1的第一个()括号相匹配的内容,\2表示与pattern1的第二个()括号相匹配的内容。sed默认使用Basic正则表达式规范,如果指定了-r选项则使用Extended规范,那么()括号就不必转义了。$ sed 's/yes/no/;s/static/dhcp/' ./testfile# 使用分号隔开指令。$ sed -e 's/yes/no/' -e 's/static/dhcp/' testfile# 使用-e选项。 如果testfile.txt的内容如下: \\\Hello World\\ \Welcome to the world of regexp!\\ 1$ sed 's/<[^>]*>//g' testfile awksed以行为单位处理文件,awk比sed强的地方在于不仅能以行为单位还能以列为单位处理文件。awk缺省的行分隔符是换行,缺省的列分隔符是连续的空格和Tab,但是行分隔符和列分隔符都可以自定义,比如/etc/passwd文件的每一行有若干个字段,字段之间以:分隔,就可以重新定义awk的列分隔符为:并以列为单位处理这个文件。 awk的基本形式 awk option ‘script’ file1 file2 … awk option -f scriptfile file1 file2 … 和sed一样,awk处理的文件既可以由标准输入重定向得到,也可以当命令行参数传入,编辑命令可以直接当命令行参数传入,也可以用-f参数指定一个脚本文件,编辑命令的格式为: /pattern/{actions} condition{actions} 自动变量$1、$2分别表示第一列、第二列等,类似于Shell脚本的位置参数,而$0表示整个当前行。 awk常用的内建变量 变量名 说明 FILENAME 当前输入文件的文件名,该变量是只读的 NR 当前行的行号,该变量是只读的,R代表record NF 当前行所拥有的列数,该变量是只读的,F代表field OFS 输出格式的列分隔符,缺省是空格 FS 输入文件的列分融符,缺省是连续的空格和Tab ORS 输出格式的行分隔符,缺省是换行符 RS 输入文件的行分隔符,缺省是换行符 Linux核心命令]]></content>
<categories>
<category>Linux</category>
</categories>
<tags>
<tag>Linux</tag>
<tag>Shell</tag>
</tags>
</entry>
<entry>
<title><![CDATA[爬虫之动态html的处理]]></title>
<url>%2F2018%2F07%2F02%2Fspider_dynamic_html%2F</url>
<content type="text"><![CDATA[关于爬虫部分一些建议: 尽量减少请求次数,能抓列表页就不抓详情页,减轻服务器压力,程序员都是混口饭吃不容易。 不要只看Web网站,还有手机App和H5,这样的反爬虫措施一般比较少。 实际应用时候,一般防守方做到根据IP限制频次就结束了,除非很核心的数据,不会再进行更多的验证,毕竟成本的问题会考虑到。 如果真的对性能要求很高,可以考虑多线程(一些成熟的框架如 Scrapy都已支持),甚至分布式… DHTML与Ajax一样,动态HTML(Dynamic HTML, DHTML)也是一系列用于解决网络问题的技术集合。DHTML是用客户端语言改变页面的HTML元素(HTML、CSS,或者二者皆被改变)。比如页面上的按钮只有当用户移动鼠标之后才出现,背景色可能每次点击都会改变,或者用一个Ajax请求触发页面加载一段新内容,网页是否属于DHTML,关键要看有没有用JavaScript控制HTML和CSS元素。 那些使用了Ajax或DHTML技术改变/加载内容的页面,可能有一些采集手段。但是用Python解决这个问题只有两种途径: 直接从JavaScript代码里采集内容(费时费力) 用Python的第三方库运行JavaScript,直接采集你在浏览器里看到的页面(这个可以有)。 Selenium和phantomjsSeleniumSelenium是一个Web的自动化测试工具,最初是为网站自动化测试而开发的,类型像我们玩游戏用的按键精灵,可以按指定的命令自动操作,不同是Selenium可以直接运行在浏览器上,它支持所有主流的浏览器(包括PhantomJS这些无界面的浏览器)。Selenium可以根据我们的指令,让浏览器自动加载页面,获取需要的数据,甚至页面截屏,或者判断网站上某些动作是否发生。Selenium自己不带浏览器,不支持浏览器的功能,它需要与第三方浏览器结合在一起才能使用。但是我们有时候需要让它内嵌在代码中运行,所以我们可以用一个叫PhantomJS的工具代替真实的浏览器。 PhantomJSPhantomJS是一个基于Webkit的“无界面”(headless)浏览器,它会把网站加载到内存并执行页面上的JavaScript,因为不会展示图形界面,所以运行起来比完整的浏览器要高效。如果把Selenium和PhantomJS结合在一起,就可以运行一个非常强大的网络爬虫了,这个爬虫可以处理JavaScrip、Cookie、headers,以及任何我们真实用户需要做的事情。]]></content>
<categories>
<category>Spider</category>
</categories>
<tags>
<tag>Spider</tag>
<tag>dynamic html</tag>
</tags>
</entry>
<entry>
<title><![CDATA[非结构化和结构化数据提取]]></title>
<url>%2F2018%2F06%2F26%2Fspider_data_fetch%2F</url>
<content type="text"><![CDATA[页面解析和数据提取一般来讲对我们而言,需要抓取的是某个网站或者某个应用的内容,提取有用的价值。内容一般分为两部分,非结构化的数据和结构化的数据。 非结构化数据:先有数据,再有结构 结构化数据:先有结构、再有数据不同类型的数据,我们需要采用不同的方式来处理。 非结构化的数据处理文本、电话号码、邮箱地址 正则表达式 HTML 文件 正则表达式 XPath CSS选择器 结构化的数据处理JSON 文件 JSON Path 转化成Python类型进行操作(json类) XML 文件 转化成Python类型(xmltodict) XPath CSS选择器 正则表达式 正则表达式 正则表达式匹配规则 Python的re模块在Python中,可以使用内置的re模块来使用正则表达式。有一点需要特别注意的是,正则表达式使用对特殊字符进行转义,所以如果我们要使用原始字符串,只需加一个 r 前缀,例如: r’chuanzhiboke\t.\tpython’ re模块的一般使用步骤 使用compile()函数将正则表达式的字符串形式编译为一个Pattern对象; 通过Pattern对象提供的一系列方法对文本进行匹配查找,获得匹配结果,一个Match对象; 最后使用Match对象提供的属性和方法获得信息,根据需要进行其他的操作。 compile 函数compile函数用于编译正则表达式,生成一个Pattern对象,它的一般使用形式如下: 1234import re# 将正则表达式编译成 Pattern 对象pattern = re.compile(r'\d+') 在上面代码中,将一个正则表达式编译成Pattern对象,接下来,就可以利用pattern的一系列方法对文本进行匹配查找了。 Pattern 对象的一些常用方法主要有: match 方法:从起始位置开始查找,一次匹配 search 方法:从任何位置开始查找,一次匹配 findall 方法:全部匹配,返回列表 finditer 方法:全部匹配,返回迭代器 split 方法:分割字符串,返回列表 sub 方法:替换 match 方法match方法用于查找字符串的头部(也可以指定起始位置),它是一次匹配,只要找到了一个匹配的结果就返回,而不是查找所有匹配的结果。它的一般使用形式如下: match(string[, pos[, endpos]]) 其中,string是待匹配的字符串,pos和endpos 是可选参数,指定字符串的起始和终点位置,默认值分别是0和len(字符串长度)。因此,当不指定pos和endpos时,match 方法默认匹配字符串的头部。当匹配成功时,返回一个Match对象,如果没有匹配上,则返回None。 1234567891011121314151617181920212223>>> import re>>> pattern = re.compile(r'\d+') # 用于匹配至少一个数字>>> m = pattern.match('one12twothree34four') # 查找头部,没有匹配>>> print(m)None>>> m = pattern.match('one12twothree34four', 2, 10) # 从'e'的位置开始匹配,没有匹配>>> print(m)None>>> m = pattern.match('one12twothree34four', 3, 10) # 从'1'的位置开始匹配,正好匹配>>> print(m) # 返回一个 Match 对象<_sre.SRE_Match object at 0x10a42aac0>>>> m.group(0) # 可省略 0'12'>>> m.start(0) # 可省略 03>>> m.end(0) # 可省略 05>>> m.span(0) # 可省略 0(3, 5) 在上面,当匹配成功时返回一个Match对象,其中: group([group1, …])方法用于获得一个或多个分组匹配的字符串,当要获得整个匹配的子串时,可直接使用group()或group(0); start([group])方法用于获取分组匹配的子串在整个字符串中的起始位置(子串第一个字符的索引),参数默认值为0; end([group])方法用于获取分组匹配的子串在整个字符串中的结束位置(子串最后一个字符的索引+1),参数默认值为0; span([group])方法返回(start(group), end(group))。 再看看一个例子: 1234567891011121314151617181920212223242526272829303132>>> import re>>> pattern = re.compile(r'([a-z]+) ([a-z]+)', re.I) # re.I 表示忽略大小写>>> m = pattern.match('Hello World Wide Web')>>> print(m) # 匹配成功,返回一个 Match 对象<_sre.SRE_Match object at 0x10bea83e8>>>> m.group(0) # 返回匹配成功的整个子串'Hello World'>>> m.span(0) # 返回匹配成功的整个子串的索引(0, 11)>>> m.group(1) # 返回第一个分组匹配成功的子串'Hello'>>> m.span(1) # 返回第一个分组匹配成功的子串的索引(0, 5)>>> m.group(2) # 返回第二个分组匹配成功的子串'World'>>> m.span(2) # 返回第二个分组匹配成功的子串(6, 11)>>> m.groups() # 等价于 (m.group(1), m.group(2), ...)('Hello', 'World')>>> m.group(3) # 不存在第三个分组Traceback (most recent call last): File "<stdin>", line 1, in <module>IndexError: no such group search方法search方法用于查找字符串的任何位置,它也是一次匹配,只要找到了一个匹配的结果就返回,而不是查找所有匹配的结果,它的一般使用形式如下: search(string[, pos[, endpos]]) 其中,string 是待匹配的字符串,pos和endpos是可选参数,指定字符串的起始和终点位置,默认值分别是0和len(字符串长度)。当匹配成功时,返回一个Match对象,如果没有匹配上,则返回None。 1234567891011121314>>> import re>>> pattern = re.compile('\d+')>>> m = pattern.search('one12twothree34four') # 这里如果使用 match 方法则不匹配>>> m<_sre.SRE_Match object at 0x10cc03ac0>>>> m.group()'12'>>> m = pattern.search('one12twothree34four', 10, 30) # 指定字符串区间>>> m<_sre.SRE_Match object at 0x10cc03b28>>>> m.group()'34'>>> m.span()(13, 15) findall方法上面的match和search方法都是一次匹配,只要找到了一个匹配的结果就返回。然而,在大多数时候,我们需要搜索整个字符串,获得所有匹配的结果。findall方法的使用形式如下: findall(string[, pos[, endpos]]) 其中,string是待匹配的字符串,pos和endpos是可选参数,指定字符串的起始和终点位置,默认值分别是0和len(字符串长度)。findall以列表形式返回全部能匹配的子串,如果没有匹配,则返回一个空列表。 12345678import repattern = re.compile(r'\d+') # 查找数字result1 = pattern.findall('hello 123456 789')result2 = pattern.findall('one1two2three3four4', 0, 10)print(result1)print(result2) finditer方法finditer方法的行为跟findall的行为类似,也是搜索整个字符串,获得所有匹配的结果。但它返回一个顺序访问每一个匹配结果(Match 对象)的迭代器。 split方法split方法按照能够匹配的子串将字符串分割后返回列表,它的使用形式如下: split(string[, maxsplit]) 其中,maxsplit用于指定最大分割次数,不指定将全部分割。 123import rep = re.compile(r'[\s\,\;]+')print(p.split('a,b;; c d')) sub方法sub方法用于替换。它的使用形式如下: sub(repl, string[, count]) 其中,repl可以是字符串也可以是一个函数: 如果repl是字符串,则会使用repl去替换字符串每一个匹配的子串,并返回替换后的字符串,另外,repl还可以使用id的形式来引用分组,但不能使用编号0; 如果repl是函数,这个方法应当只接受一个参数(Match 对象),并返回一个字符串用于替换(返回的字符串中不能再引用分组)。 count用于指定最多替换次数,不指定时全部替换。 123456789101112import rep = re.compile(r'(\w+) (\w+)') # \w = [A-Za-z0-9]s = 'hello 123, hello 456'print(p.sub(r'hello world', s)) # 使用 'hello world' 替换 'hello 123' 和 'hello 456'print(p.sub(r'\2 \1', s)) # 引用分组def func(m): return 'hi' + ' ' + m.group(2)print(p.sub(func, s))print(p.sub(func, s, 1)) # 最多替换一次 匹配中文在某些情况下,需要匹配文本中的汉字,有一点需要注意的是,中文的unicode编码范围 主要在[u4e00-u9fa5],这里说主要是因为这个范围并不完整,比如没有包括全角(中文)标点,不过,在大部分情况下,应该是够用的。 假设现在想把字符串title = u’你好,hello,世界’中的中文提取出来,可以: 1234567import retitle = u'你好,hello,世界'pattern = re.compile(ur'[\u4e00-\u9fa5]+')result = pattern.findall(title)print(result) 贪婪模式与非贪婪模式 贪婪模式:在整个表达式匹配成功的前提下,尽可能多的匹配( * ); 非贪婪模式:在整个表达式匹配成功的前提下,尽可能少的匹配( ? ); Python里数量词默认是贪婪的。 使用正则表达式的爬虫使用正则表达式爬去腾讯社招的信息:腾讯社招 XPath与lxml库XPath(XML Path Language)是一门在XML文档中查找信息的语言,可用来在XML文档中对元素和属性进行遍历。 XPath开发工具 开源的XPath表达式编辑工具:XMLQuire(XML格式文件可用) Chrome插件 XPath Helper Firefox插件 XPath Checker 选取节点XPath使用路径表达式来选取XML文档中的节点或者节点集。这些路径表达式和我们在常规的电脑文件系统中看到的表达式非常相似。 最常用的路径表达式如下: 表达式 描述 nodename 选取此节点的所有子节点 / 从根节点选取 // 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置 . 选取当前节点 .. 选取当前节点的父节点 @ 选取属性 谓语(Predicates)谓语用来查找某个特定的节点或者包含某个指定的值的节点,被嵌在方括号中。在下面的表格中,列出了带有谓语的一些路径表达式,以及表达式的结果: 路径表达式 结果 /bookstore/book[1] 选取属于 bookstore 子元素的第一个 book 元素。 /bookstore/book[last()] 选取属于 bookstore 子元素的最后一个 book 元素。 /bookstore/book[last()-1] 选取属于 bookstore 子元素的倒数第二个 book 元素。 /bookstore/book[position()<3] 选取最前面的两个属于 bookstore 元素的子元素的 book 元素。 //title[@lang] 选取所有拥有名为 lang 的属性的 title 元素。 //title[@lang=’eng’] 选取所有 title 元素,且这些元素拥有值为 eng 的 lang 属性。 /bookstore/book[price>35.00] 选取 bookstore 元素的所有 book 元素,且其中的 price 元素的值须大于 35.00。 /bookstore/book[price>35.00]/title 选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35.00。 选取未知节点XPath通配符可用来选取未知的XML元素。 通配符 描述 * 匹配任何元素节点。 @* 匹配任何属性节点。 node() 匹配任何类型的节点。 选取若干路径通过在路径表达式中使用|运算符,可以选取若干个路径。在下面的表格中,列出了一些路径表达式,以及这些表达式的结果: 路径表达式 结果 //book/title | //book/price 选取 book 元素的所有 title 和 price 元素。 //title | //price 选取文档中的所有 title 和 price 元素。 /bookstore/book/title | //price 选取属于 bookstore 元素的 book 元素的所有 title 元素,以及文档中所有的 price 元素。 lxml库 lxml是一个HTML/XML的解析器,主要的功能是如何解析和提取 HTML/XML 数据。 lxml和正则一样,也是用 C 实现的,是一款高性能的 Python HTML/XML 解析器,可以利用XPath语法,来快速的定位特定元素以及节点信息。 使用xpath获取腾讯社招每个职位的详细信息12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182from urllib import requestfrom lxml import etreeimport jsonimport codecsclass TencentSpider(object): def __init__(self, file, beginPage, endPage): self.url = "https://hr.tencent.com/position.php?&start=" self.headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36" } self.beginPage = beginPage self.endPage = endPage self.file = file self.positionJson = [] def start_spider(self): for page in range(self.beginPage, self.endPage + 1): offsetNumber = (page - 1) * 10 fullUrl = self.url + str(offsetNumber) self.load_page(fullUrl) self.file.write(json.dumps(self.positionJson, ensure_ascii=False)) def load_page(self, url): req = request.Request(url, headers=self.headers) res = request.urlopen(req) html = etree.HTML(res.read()) links = html.xpath('//div[@class="left wcont_b box"]//tr[@class="even" or "odd"]/td[1]/a/@href') for link in links: fullLink = "https://hr.tencent.com/" + link self.get_position_detail(fullLink) def get_position_detail(self, url): req = request.Request(url, headers=self.headers) res = request.urlopen(req) html = etree.HTML(res.read()) positionDetail = {} # 职位名称 positionDetail['positionName'] = html.xpath('//div[@class="box wcont_a"]/table//tr[1]/td/text()')[0] # 工作地点 positionDetail['positionAddress'] = html.xpath('//div[@class="box wcont_a"]/table//tr[2]/td[1]/text()')[0] # 职位类别 if(html.xpath('//div[@class="box wcont_a"]/table//tr[2]/td[2]/text()')): positionDetail['positionCategory'] = html.xpath('//div[@class="box wcont_a"]/table//tr[2]/td[2]/text()')[0] else: positionDetail['positionCategory'] = "" # 招聘人数 positionDetail['postionNumber'] = html.xpath('//div[@class="box wcont_a"]/table//tr[2]/td[3]/text()')[0] # 工作职责 positionDutyList = html.xpath('//div[@class="box wcont_a"]/table//tr[3]/td/ul//li') positionDutyStr = "" for duty in positionDutyList: positionDutyStr += duty.text # print(positionDutyStr) positionDetail['positionDutyStr'] = positionDutyStr # 工作要求 positionRequirementList = html.xpath('//div[@class="box wcont_a"]/table//tr[4]/td/ul//li') positionRequirementStr = "" for requirement in positionRequirementList: positionRequirementStr += requirement.text # print(positionRequirementStr) positionDetail['positionRequirementStr'] = positionRequirementStr self.positionJson.append(positionDetail)if __name__ == "__main__": beginPage = int(input("请输入起始页:")) endPage = int(input("请输入终止页")) file = codecs.open("tencentposition.json", "w", "utf-8") tencentspider = TencentSpider(file, beginPage, endPage) tencentspider.start_spider() file.close() 数据提取之JSON与JsonPATHJSON(JavaScript Object Notation)是一种轻量级的数据交换格式,它使得人们很容易的进行阅读和编写。同时也方便了机器进行解析和生成。适用于进行数据交互的场景,比如网站前台与后台之间的数据交互。 JSONjson简单说就是javascript中的对象和数组,所以这两种结构就是对象和数组两种结构,通过这两种结构可以表示各种复杂的结构。 对象:对象在js中表示为{ }括起来的内容,数据结构为{ key:value, key:value, ... }的键值对的结构,在面向对象的语言中,key为对象的属性,value为对应的属性值,所以很容易理解,取值方法为 对象.key 获取属性值,这个属性值的类型可以是数字、字符串、数组、对象这几种。 数组:数组在js中是中括号[ ]括起来的内容,数据结构为["Python", "javascript", "C++", ...],取值方式和所有语言中一样,使用索引获取,字段值的类型可以是 数字、字符串、数组、对象几种。 json模块json模块提供了四个功能:dumps、dump、loads、load,用于字符串和python数据类型间进行转换。 json.loads()把Json格式字符串解码转换成Python对象 从json到python的类型转化对照如下: Python JSON dict object list, tuple array str, unicode string int, long, float number True true False false None null json.dumps()实现python类型转化为json字符串,返回一个str对象 把一个Python对象编码转换成Json字符串。 json.dump()将Python内置类型序列化为json对象后写入文件。 1234567import jsonlistStr = [{"city": "北京"}, {"name": "大刘"}]json.dump(listStr, open("listStr.json","w"), ensure_ascii=False)dictStr = {"city": "北京", "name": "大刘"}json.dump(dictStr, open("dictStr.json","w"), ensure_ascii=False) json.load()读取文件中json形式的字符串元素转化成python类型。 1234import jsonstrList = json.load(open("listStr.json"))print(strList) JsonPathJsonPath是一种信息抽取类库,是从JSON文档中抽取指定信息的工具,提供多种语言实现版本,包括:Javascript、Python、PHP和Java。JsonPath对于JSON来说,相当于XPATH对于XML。 JsonPath与XPath语法对比 XPath JSONPath 描述 / $ 根节点 . @ 现行节点 / .or[] 取子节点 .. n/a 取父节点,Jsonpath未支持 // .. 就是不管位置,选择所有符合条件的条件 * * 匹配所有元素节点 @ n/a 根据属性访问,Json不支持,因为Json是个Key-value递归结构,不需要。 [] [] 迭代器标示(可以在里边做简单的迭代操作,如数组下标,根据内容选值等) | [,] 支持迭代器中做多选。 [] ?() 支持过滤操作. n/a () 支持表达式计算 () n/a 分组,JsonPath不支持 注意事项json.loads()是把Json格式字符串解码转换成Python对象,如果在json.loads的时候出错,要注意被解码的Json字符的编码。如果传入的字符串的编码不是UTF-8的话,需要指定字符编码的参数encoding: 12import jsondataDict = json.loads(jsonStrGBK, encoding="GBK"); decode的作用是将其他编码的字符串转换成 Unicode 编码; encode的作用是将 Unicode 编码转换成其他编码的字符串。 一句话:UTF-8是对Unicode字符集进行编码的一种编码方式。 多线程爬虫实例Queue(队列对象)Queue是python中的标准库,可以直接import Queue引用,队列是线程间最常用的交换数据的形式。 python下多线程的思考对于资源,加锁是个重要的环节。因为python原生的list,dict等,都是not thread safe的。而Queue是线程安全的,因此在满足使用条件下,建议使用队列。 初始化:class Queue.Queue(maxsize) FIFO先进先出 包中的常用方法: Queue.qsize() 返回队列的大小; Queue.empty() 如果队列为空,返回True,反之False; Queue.full() 如果队列满了,返回True,反之False; Queue.full与maxsize大小对应; Queue.get([block[, timeout]])获取队列,其中timeout为等待时间。 创建一个“队列”对象 import Queue myqueue = Queue.Queue(maxsize=10) 将一个值放入队列中 myqueue.put(10) 将一个值从队列中取出 myqueue.get() 多线程示意图 12]]></content>
<categories>
<category>Spider</category>
</categories>
<tags>
<tag>Spider</tag>
<tag>data fetch</tag>
</tags>
</entry>
<entry>
<title><![CDATA[爬虫原理与数据抓取]]></title>
<url>%2F2018%2F06%2F23%2Fspider_principle_and_wireshark%2F</url>
<content type="text"><![CDATA[通用爬虫和聚焦爬虫根据使用场景,网络爬虫可分为通用爬虫和聚焦爬虫两种。 通用爬虫通用网络爬虫是搜索引擎抓取系统的重要组成部分。主要目的是将互联网上的网页下载到本地,形成一个互联网内容的镜像备份。 通用搜索引擎的工作原理通用网络爬虫 从互联网中搜集网页,采集信息,这些网页信息用于为搜索引擎建立索引从而提供支持,它决定着整个引擎系统的内容是否丰富,信息是否即时,因此其性能的优劣直接影响着搜索引擎的效果。 第一步:抓取网页搜索引擎网络爬虫的基本工作流程如下: 首先选取一部分的种子URL 将这些URL放入待抓取URL队列; 取出待抓取URL,解析DNS得到主机的IP,并将URL对应的网页下载下来,存储进已下载网页库中,并且将这些URL放进已抓取URL队列; 分析已抓取URL队列中的URL,分析其中的其他URL,并且将URL放入待抓取URL队列,从而进入下一个循环。 但是搜索引擎蜘蛛的爬行是被输入了一定的规则的,它需要遵从一些命令或文件的内容,如标注为nofollow的链接,或者是Robots协议。 Robots协议(也叫爬虫协议、机器人协议等),全称是“网络爬虫排除标准”(Robots Exclusion Protocol),网站通过Robots协议告诉搜索引擎哪些页面可以抓取,哪些页面不能抓取,例如: 淘宝网:https://www.taobao.com/robots.txt 腾讯网: http://www.qq.com/robots.txt 第二步:数据存储搜索引擎通过爬虫爬取到的网页,将数据存入原始页面数据库。其中的页面数据与用户浏览器得到的HTML是完全一样的。搜索引擎蜘蛛在抓取页面时,也做一定的重复内容检测,一旦遇到访问权重很低的网站上有大量抄袭、采集或者复制的内容,很可能就不再爬行。 第三步:预处理搜索引擎将爬虫抓取回来的页面,进行各种步骤的预处理。 提取文字 中文分词 消除噪音(比如版权声明文字、导航条、广告等……) 索引处理 链接关系计算 特殊文件处理 … 除了HTML文件外,搜索引擎通常还能抓取和索引以文字为基础的多种文件类型,如 PDF、Word、WPS、XLS、PPT、TXT 文件等。我们在搜索结果中也经常会看到这些文件类型。但搜索引擎还不能处理图片、视频、Flash 这类非文字内容,也不能执行脚本和程序。 第四步:提供检索服务,网站排名搜索引擎在对信息进行组织和处理后,为用户提供关键字检索服务,将用户检索相关的信息展示给用户。同时会根据页面的PageRank值(链接的访问量排名)来进行网站排名,这样Rank值高的网站在搜索结果中会排名较前,当然也可以直接使用 Money 购买搜索引擎网站排名,简单粗暴。 但是,这些通用性搜索引擎也存在着一定的局限性: 通用搜索引擎所返回的结果都是网页,而大多情况下,网页里90%的内容对用户来说都是无用的。 不同领域、不同背景的用户往往具有不同的检索目的和需求,搜索引擎无法提供针对具体某个用户的搜索结果。 万维网数据形式的丰富和网络技术的不断发展,图片、数据库、音频、视频多媒体等不同数据大量出现,通用搜索引擎对这些文件无能为力,不能很好地发现和获取。 通用搜索引擎大多提供基于关键字的检索,难以支持根据语义信息提出的查询,无法准确理解用户的具体需求。 聚焦爬虫聚焦爬虫,是”面向特定主题需求”的一种网络爬虫程序,它与通用搜索引擎爬虫的区别在于:聚焦爬虫在实施网页抓取时会对内容进行处理筛选,尽量保证只抓取与需求相关的网页信息。 HTTP/HTTPS的请求与相应HTTP和HTTPSHTTP协议(HyperText Transfer Protocol,超文本传输协议):是一种发布和接收 HTML页面的方法。HTTPS(Hypertext Transfer Protocol over Secure Socket Layer)简单讲是HTTP的安全版,在HTTP下加入SSL层。SSL(Secure Sockets Layer 安全套接层)主要用于Web的安全传输协议,在传输层对网络连接进行加密,保障在Internet上数据传输的安全。 HTTP的端口号为80 HTTPS的端口号为443 HTTP的请求与响应HTTP通信由两部分组成:客户端请求消息与服务器响应消息。 浏览器发送HTTP请求的过程:当用户在浏览器的地址栏中输入一个URL并按回车键之后,浏览器会向HTTP服务器发送HTTP请求。HTTP请求主要分为“Get”和“Post”两种方法。当我们在浏览器输入URL http://www.baidu.com 的时候,浏览器发送一个Request请求去获取 http://www.baidu.com 的html文件,服务器把Response文件对象发送回给浏览器。浏览器分析Response中的 HTML,发现其中引用了很多其他文件,比如Images文件,CSS文件,JS文件。 浏览器会自动再次发送Request去获取图片,CSS文件,或者JS文件。当所有的文件都下载成功后,网页会根据HTML语法结构,完整的显示出来了。URL(Uniform / Universal Resource Locator的缩写):统一资源定位符,是用于完整地描述Internet上网页和其他资源的地址的一种标识方法。 基本格式:1scheme://host[:port#]/path/…/[?query-string][#anchor] scheme:协议(例如:http, https, ftp) host:服务器的IP地址或者域名 port#:服务器的端口(如果是走协议默认端口,缺省端口80) path:访问资源的路径 query-string:参数,发送给http服务器的数据 anchor:锚(跳转到网页的指定锚点位置) 客户端HTTP请求URL只是标识资源的位置,而HTTP是用来提交和获取资源。客户端发送一个HTTP请求到服务器的请求消息,包括以下格式: 请求行、请求头部、空行、请求数据 一个典型的HTTP请求示例:12345678910GET https://www.baidu.com/ HTTP/1.1Host: www.baidu.comConnection: keep-aliveUpgrade-Insecure-Requests: 1User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8Referer: http://www.baidu.com/Accept-Encoding: gzip, deflate, sdch, brAccept-Language: zh-CN,zh;q=0.8,en;q=0.6Cookie: BAIDUID=04E4001F34EA74AD4601512DD3C41A7B:FG=1; BIDUPSID=04E4001F34EA74AD4601512DD3C41A7B; PSTM=1470329258; MCITY=-343%3A340%3A; BDUSS=nF0MVFiMTVLcUh-Q2MxQ0M3STZGQUZ4N2hBa1FFRkIzUDI3QlBCZjg5cFdOd1pZQVFBQUFBJCQAAAAAAAAAAAEAAADpLvgG0KGyvLrcyfrG-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFaq3ldWqt5XN; H_PS_PSSID=1447_18240_21105_21386_21454_21409_21554; BD_UPN=12314753; sug=3; sugstore=0; ORIGIN=0; bdime=0; H_PS_645EC=7e2ad3QHl181NSPbFbd7PRUCE1LlufzxrcFmwYin0E6b%2BW8bbTMKHZbDP0g; BDSVRTM=0 HTTP请求主要分为Get和Post两种方法GET是从服务器上获取数据,POST是向服务器传送数据。GET请求参数显示,都显示在浏览器网址上,HTTP服务器根据该请求所包含URL中的参数来产生响应内容,即“Get”请求的参数是URL的一部分。 例如: http://www.baidu.com/s?wd=ChinesePOST请求参数在请求体当中,消息长度没有限制而且以隐式的方式进行发送,通常用来向HTTP服务器提交量比较大的数据(比如请求中包含许多参数或者文件上传操作等),请求的参数包含在“Content-Type”消息头里,指明该消息体的媒体类型和编码。注意:避免使用Get方式提交表单,因为有可能会导致安全问题。 比如说在登陆表单中用Get方式,用户输入的用户名和密码将在地址栏中暴露无遗。 常用的请求报头 Host (主机和端口号)Host:对应网址URL中的Web名称和端口号,用于指定被请求资源的Internet主机和端口号,通常属于URL的一部分。 Connection (链接类型)Connection:表示客户端与服务连接类型 Client 发起一个包含 Connection:keep-alive 的请求,HTTP/1.1使用 keep-alive 为默认值。 Server收到请求后:如果 Server 支持 keep-alive,回复一个包含 Connection:keep-alive 的响应,不关闭连接;如果 Server 不支持 keep-alive,回复一个包含 Connection:close 的响应,关闭连接; 如果client收到包含 Connection:keep-alive 的响应,向同一个连接发送下一个请求,直到一方主动关闭连接。 keep-alive在很多情况下能够重用连接,减少资源消耗,缩短响应时间,比如当浏览器需要多个文件时(比如一个HTML文件和相关的图形文件),不需要每次都去请求建立连接。 Upgrade-Insecure-Requests (升级为HTTPS请求)Upgrade-Insecure-Requests:升级不安全的请求,意思是会在加载 http 资源时自动替换成 https 请求,让浏览器不再显示https页面中的http请求警报。HTTPS 是以安全为目标的 HTTP 通道,所以在 HTTPS 承载的页面上不允许出现 HTTP 请求,一旦出现就是提示或报错。 User-Agent (浏览器名称)User-Agent:是客户浏览器的名称。 Accept (传输文件类型)Accept:指浏览器或其他客户端可以接受的MIME(Multipurpose Internet Mail Extensions(多用途互联网邮件扩展))文件类型,服务器可以根据它判断并返回适当的文件格式。 Accept: /:表示什么都可以接收; Accept:image/gif:表明客户端希望接受GIF图像格式的资源; Accept:text/html:表明客户端希望接受html文本; Accept: text/html, application/xhtml+xml;q=0.9, image/*;q=0.8:表示浏览器支持的 MIME 类型分别是 html文本、xhtml和xml文档、所有的图像格式资源。 q是权重系数,范围 0 =< q <= 1,q 值越大,请求越倾向于获得其“;”之前的类型表示的内容。若没有指定q值,则默认为1,按从左到右排序顺序;若被赋值为0,则用于表示浏览器不接受此内容类型。 Text:用于标准化地表示的文本信息,文本消息可以是多种字符集和或者多种格式的;Application:用于传输应用程序数据或者二进制数据。 Referer(页面跳转处)Referer:表明产生请求的网页来自于哪个URL,用户是从该 Referer页面访问到当前请求的页面。这个属性可以用来跟踪Web请求来自哪个页面,是从什么网站来的等。 有时候遇到下载某网站图片,需要对应的referer,否则无法下载图片,那是因为人家做了防盗链,原理就是根据referer去判断是否是本网站的地址,如果不是,则拒绝,如果是,就可以下载; Accept-Encoding(文件编解码格式)Accept-Encoding:指出浏览器可以接受的编码方式。编码方式不同于文件格式,它是为了压缩文件并加速文件传递速度。浏览器在接收到Web响应之后先解码,然后再检查文件格式,许多情形下这可以减少大量的下载时间。 Accept-Encoding:gzip;q=1.0, identity; q=0.5, *;q=0 如果有多个Encoding同时匹配, 按照q值顺序排列,本例中按顺序支持 gzip, identity压缩编码,支持gzip的浏览器会返回经过gzip编码的HTML页面。 如果请求消息中没有设置这个域服务器假定客户端对各种内容编码都可以接受。 Accept-Language(语言种类)Accept-Langeuage:指出浏览器可以接受的语言种类,如en或en-us指英语,zh或者zh-cn指中文,当服务器能够提供一种以上的语言版本时要用到。 Accept-Charset(字符编码)Accept-Charset:指出浏览器可以接受的字符编码。 举例:Accept-Charset:iso-8859-1,gb2312,utf-8 ISO8859-1:通常叫做Latin-1。Latin-1包括了书写所有西方欧洲语言不可缺少的附加字符,英文浏览器的默认值是ISO-8859-1. gb2312:标准简体中文字符集; utf-8:UNICODE 的一种变长字符编码,可以解决多种语言文本显示问题,从而实现应用国际化和本地化。如果在请求消息中没有设置这个域,缺省是任何字符集都可以接受。 Cookie (Cookie)Cookie:浏览器用这个属性向服务器发送Cookie。Cookie是在浏览器中寄存的小型数据体,它可以记载和服务器相关的用户信息,也可以用来实现会话功能,以后会详细讲。 Content-Type (POST数据类型)Content-Type:POST请求里用来表示的内容类型。 Content-Type = Text/XML; charset=gb2312: 指明该请求的消息体中包含的是纯文本的XML类型的数据,字符编码采用“gb2312”。 服务端HTTP响应HTTP响应也由四个部分组成,分别是: 状态行、消息报头、空行、响应正文 12345678910111213HTTP/1.1 200 OKServer: TengineConnection: keep-aliveDate: Wed, 30 Nov 2016 07:58:21 GMTCache-Control: no-cacheContent-Type: text/html;charset=UTF-8Keep-Alive: timeout=20Vary: Accept-EncodingPragma: no-cacheX-NWS-LOG-UUID: bd27210a-24e5-4740-8f6c-25dbafa9c395Content-Length: 180945<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" .... 常用的响应报头理论上所有的响应头信息都应该是回应请求头的。但是服务端为了效率,安全,还有其他方面的考虑,会添加相对应的响应头信息: Cache-Control:must-revalidate, no-cache, private。这个值告诉客户端,服务端不希望客户端缓存资源,在下次请求资源时,必须要从新请求服务器,不能从缓存副本中获取资源。 Cache-Control是响应头中很重要的信息,当客户端请求头中包含Cache-Control:max-age=0请求,明确表示不会缓存服务器资源时,Cache-Control作为作为回应信息,通常会返回no-cache,意思就是说,”那不缓存了”。 当客户端在请求头中没有包含Cache-Control时,服务端往往会定,不同的资源不同的缓存策略,比如说oschina在缓存图片资源的策略就是Cache-Control:max-age=86400,这个意思是,从当前时间开始,在86400秒的时间内,客户端可以直接从缓存副本中读取资源,而不需要向服务器请求。 Connection:keep-alive这个字段作为回应客户端的Connection:keep-alive,告诉客户端服务器的tcp连接也是一个长连接,客户端可以继续使用这个tcp连接发送http请求。 Content-Encoding:gzip告诉客户端,服务端发送的资源是采用gzip编码的,客户端看到这个信息后,应该采用gzip对资源进行解码。 Content-Type:text/html;charset=UTF-8告诉客户端,资源文件的类型,还有字符编码,客户端通过utf-8对资源进行解码,然后对资源进行html解析。如果我们看到有些网站是乱码的,往往就是服务器端没有返回正确的编码。 Date:Sun, 21 Sep 2016 06:18:21 GMT这个是服务端发送资源时的服务器时间,GMT是格林尼治所在地的标准时间。http协议中发送的时间都是GMT的,这主要是解决在互联网上,不同时区在相互请求资源的时候,时间混乱问题。 Expires:Sun, 1 Jan 2000 01:00:00 GMT这个响应头也跟缓存有关,告诉客户端在这个时间前,可以直接访问缓存副本,很显然这个值会存在问题,因为客户端和服务器的时间不一定会都是相同的,如果时间不同就会导致问题。所以这个响应头是没有Cache-Control:max-age=*这个响应头准确的,因为max-age=date中的date是个相对时间,不仅更好理解,也更准确。 Pragma:no-cache这个含义与Cache-Control等同。 Server:Tengine/1.4.6这个是服务器和相对应的版本,只是告诉客户端服务器的信息。 Transfer-Encoding:chunked这个响应头告诉客户端,服务器发送的资源的方式是分块发送的。一般分块发送的资源都是服务器动态生成的,在发送时还不知道发送资源的大小,所以采用分块发送,每一块都是独立的,独立的块都能标示自己的长度,最后一块是0长度的,当客户端读到这个0长度的块时,就可以确定资源已经传输完了。 Vary: Accept-Encoding告诉缓存服务器,缓存压缩文件和非压缩文件两个版本,现在这个字段用处并不大,因为现在的浏览器都是支持压缩的。 响应状态码响应状态代码有三位数字组成,第一个数字定义了响应的类别,且有五种可能取值。 常见状态码: 100~199:表示服务器成功接收部分请求,要求客户端继续提交其余请求才能完成整个处理过程。 200~299:表示服务器成功接收请求并已完成整个处理过程。常用200(OK 请求成功)。 300~399:为完成请求,客户需进一步细化请求。例如:请求的资源已经移动一个新地址、常用302(所请求的页面已经临时转移至新的url)、307和304(使用缓存资源)。 400~499:客户端的请求有错误,常用404(服务器无法找到被请求的页面)、403(服务器拒绝访问,权限不够)。 500~599:服务器端出现错误,常用500(请求未完成。服务器遇到不可预知的情况)。 Cookie 和 Session:服务器和客户端的交互仅限于请求/响应过程,结束之后便断开,在下一次请求时,服务器会认为新的客户端。为了维护他们之间的链接,让服务器知道这是前一个用户发送的请求,必须在一个地方保存客户端的信息。Cookie:通过在 客户端 记录的信息确定用户的身份。Session:通过在 服务器端 记录的信息确定用户的身份。 HTTP代理神器Fiddlerurllib库的基本使用所谓网页抓取,就是把URL地址中指定的网络资源从网络流中读取出来,保存到本地。 在Python3中一般使用urllib库。 urlopen和Request可以直接使用urlopen()打开一个网页;但是,如果需要执行更复杂的操作,比如增加HTTP报头,必须创建一个 Request 实例来作为urlopen()的参数;而需要访问的url地址则作为 Request 实例的参数。 123456789101112131415161718192021from urllib import requestdef get_page_info(): headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36" } req = request.Request("http://www.baidu.com/", headers=headers) res = request.urlopen(req) html = res.read() # 请求页面的源代码 print(html) # 请求的状态码 print(res.getcode()) # 请求的链接 print(res.geturl()) # 请求头信息 print(res.info())if __name__ == "__main__": get_page_info() 新建Request实例,除了必须要有 url 参数之外,还可以设置另外两个参数: data(默认空):是伴随 url 提交的数据(比如要post的数据),同时 HTTP 请求将从 “GET”方式 改为 “POST”方式。 headers(默认空):是一个字典,包含了需要发送的HTTP报头的键值对。 User-Agent浏览器就是互联网世界上公认被允许的身份,如果我们希望我们的爬虫程序更像一个真实用户,那我们第一步,就是需要伪装成一个被公认的浏览器。用不同的浏览器在发送请求的时候,会有不同的User-Agent头。 urllib默认的User-Agent头为:Python-urllib/x.y(x和y是Python主版本和次版本号) 添加更多的Header信息在 HTTP Request 中加入特定的 Header,来构造一个完整的HTTP请求消息。 可以通过调用Request.add_header() 添加/修改一个特定的header 也可以通过调用Request.get_header()来查看已有的header。 parse.urlencode()一般HTTP请求提交数据,需要编码成URL编码格式,然后做为url的一部分,或者作为参数传到Request对象中。此时需要使用parse.urlencode对需要提交的数据进行编码。 Get方式GET请求一般用于向服务器获取数据。 12345678910111213141516171819202122from urllib import request, parsedef baidu_search_by_keyword(kw): url = "http://www.baidu.com/" wd = {"wd": kw} wd = parse.urlencode(wd) full_url = url + "s?" + wd headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36" } req = request.Request(full_url, headers=headers) res = request.urlopen(req) with open("02_result.html", "wb") as f: f.write(res.read())if __name__ == "__main__": keyword = input("请输入要搜索的内容:") baidu_search_by_keyword(keyword) 批量爬取贴吧页面数据首先需要对百度贴吧的链接进行分析,找出其中的规律。 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859from urllib import request, parsedef tieba_spider(url, beginpage, endpage): """ 作用:负责处理url,分配每个url去发送请求 url:需要处理的第一个url beginPage: 爬虫执行的起始页面 endPage: 爬虫执行的截止页面 """ for page in range(beginpage, endpage + 1): pn = (page - 1) * 50 filename = "第" + str(page) + "页.html" # 组合为完整的 url,并且pn值每次增加50 fullurl = url + "&pn=" + str(pn) # 调用loadPage()发送请求获取HTML页面 html = load_page(fullurl, filename) # 将获取到的HTML页面写入本地磁盘文件 write_file(html, filename)def load_page(url, filename): """ 作用:根据url发送请求,获取服务器响应文件 url:需要爬取的url地址 filename: 文件名 """ print("正在下载" + filename) headers = {"User-Agent": "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0;"} req = request.Request(url, headers=headers) res = request.urlopen(req) return res.read()def write_file(html, filename): """ 作用:保存服务器响应文件到本地磁盘文件里 html: 服务器响应文件 filename: 本地磁盘文件名 """ print("正在存储" + filename) with open(filename, 'wb') as f: f.write(html) print("-" * 20)if __name__ == "__main__": kw = input("请输入需要爬取的贴吧:") # 输入起始页和终止页,str转成int类型 beginPage = int(input("请输入起始页:")) endPage = int(input("请输入终止页:")) url = "http://tieba.baidu.com/f?" key = parse.urlencode({"kw": kw}) # 组合后的url示例:http://tieba.baidu.com/f?kw=python url = url + key tieba_spider(url, beginPage, endPage) POST方式Request请求对象的里有data参数,它就是用在POST里的,此时要传送的数据就是这个参数data,data是一个字典,里面要匹配键值对。 123456789101112131415161718192021222324252627282930from urllib import request, parsedef youdao_translate(keyword): url = "http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule" headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36" } formdata = { "from": "AUTO", "to": "AUTO", "i": keyword, "smartresult": "dict", "client": "fanyideskweb", "doctype": "json", "version": "2.1", "keyfrom": "fanyi.web", "ue": "UTF-8", "action": "FY_BY_ENTER", "typoResult": "false" } data = parse.urlencode(formdata).encode('utf-8') req = request.Request(url, data=data, headers=headers) res = request.urlopen(req) print(res.read().decode('utf-8'))if __name__ == "__main__": youdao_translate("黑暗") 获取AJAX加载的内容有些网页内容使用AJAX加载,AJAX一般返回的是JSON,直接对AJAX地址进行post或get,就返回JSON数据了。在写爬虫程序时,最需要关注的,是数据的来源。 处理HTTPS请求 SSL证书验证在访问网页的时候则会报出SSLError:urllib.error.URLError:<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verity failed (.ssl.c:777) 此时需要单独处理SSL证书,让程序忽略SSL证书验证错误,即可正常访问。解决办法: 123import sslssl._create_default_https_context = ssl._create_unverified_context 关于CACA(Certificate Authority)是数字证书认证中心的简称,是指发放、管理、废除数字证书的受信任的第三方机构,如北京数字认证股份有限公司、上海市数字证书认证中心有限公司等。CA的作用是检查证书持有者身份的合法性,并签发证书,以防证书被伪造或篡改,以及对证书和密钥进行管理。现实生活中可以用身份证来证明身份, 那么在网络世界里,数字证书就是身份证。和现实生活不同的是,并不是每个上网的用户都有数字证书的,往往只有当一个人需要证明自己的身份的时候才需要用到数字证书。普通用户一般是不需要,因为网站并不关心是谁访问了网站,现在的网站只关心流量。但是反过来,网站就需要证明自己的身份了。比如说现在钓鱼网站很多的,比如你想访问的是www.baidu.com,但其实你访问的是www.daibu.com”,所以在提交自己的隐私信息之前需要验证一下网站的身份,要求网站出示数字证书。一般正常的网站都会主动出示自己的数字证书,来确保客户端和网站服务器之间的通信数据是加密安全的。]]></content>
<categories>
<category>Spider</category>
</categories>
<tags>
<tag>Spider</tag>
</tags>
</entry>
<entry>
<title><![CDATA[python3基础数据类型详解]]></title>
<url>%2F2018%2F02%2F12%2Fpython3-base-datatype%2F</url>
<content type="text"><![CDATA[数据类型Integral类型Python提供了两种内置的Integral类型,即int与bool。 浮点类型Python提供了3中浮点值:内置的float与complex类型,以及来自标准库的decimal.Decimal类型。 字符串字符串是使用固定不变的str数据类型表示的,其中存放Unicode字符序列。由于字符串是固定序列,所有可用于固定序列的功能都可用于字符串。 组合数据类型序列类型序列类型支持成员关系操作符(in)、大小计算函数(len())、分片([]),并且是可以迭代的。Python提供了5中内置的序列类型:bytearray、bytes、list、str与tuple,以及标准类库中提供的collections.namedtuple。 元组tuple元组是有序的序列,其中包含0个或多个对象引用。元组是固定的,不能替换或删除其中包含的任意数据项。元组使用小括号()表示,中间的元素用逗号分隔。元组是可以迭代的(iterable)。 列表list列表是包含0个或多个对象引用的有序序列,支持与字符串以及元组一样的分片与步距语法。列表是可变的,可以对列表中的项进行删除或替换。列表使用方括号[]表示,中间的元素用逗号分隔。列表是可以迭代的(iterable)。 集合类型setset是可以迭代的(iterable)。在进行迭代时,集合类型以任意顺序提供其数据项。Python提供了两种内置的集合类型:可变的set类型,固定的frozenset类型。只有可哈希运算的对象可以添加到集合中,可哈希运算的对象包含一个hash()特殊方法。所有内置的固定数据类型(例如float、frozenset、int、str、tuple)都是可以哈希运算的,都可以添加到集合中。内置的可变数据类型(例如dict、list、set)都不是可哈希运算的,因为其哈希值会随着包含项数的变化而变化,因此这些数据类型不能添加到集合中。 集合是0个或多个对象引用的无序组合,这些对象引用所引用的对象都是可哈希运算的。集合是可变的,但其中的项是无序的,所以没有索引位置的概念。集合中包含的每个数据项都是独一无二的,不会出现重复的数据项。集合使用大括号{}表示,数据项用逗号分隔。 固定集合是指那种一旦创建后就不能改变的集合,固定集合只能使用frozenset数据类型函数进行创建。集合与固定集合都可以包含固定集合。 映射类型映射类型是一种支持成员关系操作符(in)与尺寸函数(len())的数据类型,并且也是可以迭代的。映射是键-值数据项的组合,并提供了存取数据项及其键、值的方法。在进行迭代时,映射类型以任意顺序提供其数据项。Python3支持三种无序的映射类型-内置的dict类型,标准库中的collections.defaultdict和collections.OrderedDict。只有可哈希运算的对象可用作字典的键,因此固定数据类型都可以用作字典的值,可变的数据类型则不能。 字典dict是一种无序的组合数据类型,其中包含0个或多个键-值对。字典是可变的,可以对其进行数据项的添加或移除操作。字典的键是独一无二的,所以不存在重复的键。 默认字典也是一种字典,但是可以对遗失的键进行处理,其他与普通字典一样。 有序字典可用作对无序字典dict的下降替代,有序字典以数据项插入的顺序进行存储。 组合数据类型的迭代与复制iterable数据类型每次返回其中的一个数据项。任意包含iter()方法的对象或任意序列(即包含getitem()方法的对象)都是一个iterable,并可以提供一个迭代子。迭代子是一个对象,该对象可以提供next()方法。 浅复制和深复制深复制需要调用copy模块中的deepcopy函数。]]></content>
<categories>
<category>python</category>
</categories>
<tags>
<tag>python</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Linux shell的实用脚本]]></title>
<url>%2F2018%2F02%2F12%2FLinux-shell-script%2F</url>
<content type="text"><![CDATA[归档]]></content>
<categories>
<category>Linux</category>
</categories>
<tags>
<tag>Linux</tag>
<tag>Shell</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Hadoop配置文件详解]]></title>
<url>%2F2018%2F02%2F11%2Fhadoop-configure-file%2F</url>
<content type="text"><![CDATA[配置文件的层级关系core-site.xml文件 参数 属性值 解释 fs.defaultFS NameNode URL hdfs://host:port/ io.file.buffer.size 131072 SequenceFiles文件中.读写缓存size设定 hadoop.tmp.dir /home/hadoop/tmp hadoop文件系统依赖的基础配置 ha.zookeeper.quorum hostname:port zookeeper的地址,多个地址以逗号分隔 12345678910111213141516<configuration> <property> <name>fs.default.name</name> <value>hdfs://hadoop1:9000</value> <description>hadoop1为服务器主机名,其实也可以使用IP地址</description> </property> <property> <name>hadoop.tmp.dir</name> <value>/home/hadoop/tmp</value> </property> <property> <name>io.file.buffer.size</name> <value>131072</value> <description>该属性值单位为KB,131072KB即为默认的64M</description> </property></configuration> hdfs-site.xml文件 参数 属性值 解释 dfs.namenode.name.dir 本地文件系统所在的NameNode的存储空间和持续化处理日志的路径 可以是按逗号分隔的目录列表,fsimage文件会存储在全部目录,冗余安全 dfs.blocksize 268435456 大文件系统HDFS块大小为256M,默认值为64M dfs.datanode.data.dir datanode存放数据块文件的目录 如果这是一个以逗号分隔的目录列表,那么数据将被存储在所有命名的目录,通常在不同的设备 dfs.replication hdfs保存数据的副本数量 副本数目不能大于datanode数目,伪分布式可以将其配置成1 dfs.permissions true/false 是否对远程读写hdfs进行权限检查,可以设置为false,即不检查 dfs.nameservices clustername 使用federation,启动两个HDFS集群,clustername为集群的别名,可以为任意,但不能重复 dfs.ha.namenodes.clustername hostname 指定nameservice是clustername时的namenode有哪些,这里的值是逻辑名称,可以随意,但不能重复 dfs.namenode.rpc-address.clustername.hostname hostname:9000 指定rpc地址 dfs.namenode.http-address.clustername.hostname hostname:50070 指定http地址 dfs.namenode.shared.edits.dir qjournal://hostname:port;hostname:port/clustername 指定clustername的NameNode共享edits文件目录时,使用的JournalNode集群信息 dfs.ha.automatic-failover.enabled.cluster1 true/false cluster1是否启用自动故障恢复,即当NameNode出故障时,是否切换到另一台NameNode dfs.client.failover.proxy.provider.cluster1 org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider 指定cluster1出故障时,哪个实现类负责执行故障切换 dfs.ha.fencing.methods sshfence NameNode需要进行切换时,使用ssh方式进行操作 dfs.ha.fencing.ssh.private-key-files /home/hadoop/.ssh/id_rsa 如果使用ssh方式,指定密钥存储的位置 12345678910111213141516171819202122<configuration> <property> <name>dfs.name.dir</name> <value>/home/hadoop/hdfs/name</value> </property> <property> <name>dfs.data.dir</name> <value>/home/hadoop/hdfs/data</value> </property> <property> <name>dfs.replication</name> <value>2</value> </property> <property> <name>dfs.permissions</name> <value>false</value> <description>need not permissions</description> </property></configuration> slaves文件从节点的主机名,直接添加即可。 mapred-site.xml文件yarn-site.xml文件]]></content>
<categories>
<category>大数据</category>
</categories>
<tags>
<tag>Hadoop</tag>
<tag>大数据</tag>
</tags>
</entry>
<entry>
<title><![CDATA[hadoop安装和基本使用]]></title>
<url>%2F2018%2F02%2F07%2Fhadoop-install-use%2F</url>
<content type="text"><![CDATA[Hadoop安装创建hadoop用户1useradd -m hadoop -s /bin/bash 安装java环境 如果是系统自带的java,请先卸载: 12rpm -qa | grep jdkrpm -e --nodeps XXXX #XXXX是上一条命令的查询结构 到Oracle官网下载jdk,并安装(这里下载的是.tar.gz版) 1234mkdir /usr/java/mv jdk-8u161-linux-x64.tar.gz /usr/java/tar zxvf jdk-8u161-linux-x64.tar.gzmv jdk1.8.0_161/ jdk1.8 编辑配置文件,配置环境变量 12345678vim /etc/profileJAVA_HOME=/usr/java/jdk1.8CLASSPATH=$JAVA_HOME/lib/PATH=$PATH:$JAVA_HOME/binexport PATH JAVA_HOME CLASSPATHsource /etc/profile 安装Hadoop2从hadoop的官网下载已经编译好的(binary)hadoop压缩包,在这里使用的是hadoop2.8.3版本。 123cd /home/hadooptar -zxvf hadoop-2.8.3.tar.gzmv hadoop-2.8.3 hadoop 修改配置文件,添加环境变量 1234567suvim /etc/profileexport HADOOP_HOME=/home/hadoop/hadoopexport PATH=.:$HADOOP_HOME/bin:$HADOOP_HOME/sbin:$PATHsource /etc/profile Hadoop目录结构说明12345678910111213$ cd /home/hadoop/hadoop$ lldrwxr-xr-x. 2 hadoop hadoop 4096 Dec 5 12:28 bindrwxr-xr-x. 3 hadoop hadoop 19 Dec 5 12:28 etcdrwxr-xr-x. 2 hadoop hadoop 101 Dec 5 12:28 includedrwxr-xr-x. 3 hadoop hadoop 19 Dec 5 12:28 libdrwxr-xr-x. 2 hadoop hadoop 4096 Dec 5 12:28 libexec-rw-r--r--. 1 hadoop hadoop 99253 Dec 5 12:28 LICENSE.txtdrwxrwxr-x. 3 hadoop hadoop 4096 Feb 10 11:20 logs-rw-r--r--. 1 hadoop hadoop 15915 Dec 5 12:28 NOTICE.txt-rw-r--r--. 1 hadoop hadoop 1366 Dec 5 12:28 README.txtdrwxr-xr-x. 2 hadoop hadoop 4096 Dec 5 12:28 sbindrwxr-xr-x. 4 hadoop hadoop 29 Dec 5 12:28 share bin:Hadoop最基本的管理脚本和使用脚本的目录,这些脚本是sbin目录下管理脚本的基础实现,用户可以直接使用这些脚本管理和使用Hadoop; etc:Hadoop配置文件所在的目录,包括core-site,xml、hdfs-site.xml、mapred-site.xml等从Hadoop1.0继承而来的配置文件和yarn-site.xml等Hadoop2.0新增的配置文件; include:对外提供的编程库头文件(具体动态库和静态库在lib目录中),这些头文件均是用C++定义的,通常用于C++程序访问HDFS或者编写MapReduce程序; lib:该目录包含了Hadoop对外提供的编程动态库和静态库,与include目录中的头文件结合使用; libexec:各个服务对用的shell配置文件所在的目录,可用于配置日志输出、启动参数(比如JVM参数)等基本信息; sbin:Hadoop管理脚本所在的目录,主要包含HDFS和YARN中各类服务的启动/关闭脚本; share:Hadoop各个模块编译后的jar包所在的目录。 Hadoop伪集群环境安装在/home/hadoop/目录下,建立tmp、hdfs/name、hdfs/data目录123456$ cd /home/hadoop$ mkdir tmp$ mkdir hdfs$ cd hdfs/$ mkdir data$ mkdir name 修改hadoop的配置文件 配置hadoop-env.sh和yarn-env.sh 123456789$ cd /home/hadoop/hadoop/etc/hadoop$ vim hadoop-env.sh#修改export JAVA_HOMEexport JAVA_HOME=/usr/java/jdk1.8$ vim yarn-env.sh#修改export JAVA_HOMEexport JAVA_HOME=/usr/java/jdk1.8 配置core-site.xml 其中fs.defaultFS是NameNode的master节点的URI,hadoop.tmp.dir是namenode上本地的hadoop临时文件夹 1234567891011<configuration> <property> <name>fs.defaultFS</name> <value>hdfs://hadoop1:9000</value> </property> <property> <name>hadoop.tmp.dir</name> <value>/home/hadoop/tmp</value> </property></configuration> 配置hdfs-site.xml 其中dfs.name.dir是namenode上存储hdfs名字空间元数据,dfs.data.dir是namenode上数据块的物理存储位置,dfs.replication是副本的个数,默认为3,一般小于datanode的机器数量,在伪集群配置中设置为1。 12345678910111213141516<configuration> <property> <name>dfs.name.dir</name> <value>/home/hadoop/hdfs/name</value> </property> <property> <name>dfs.data.dir</name> <value>/home/hadoop/hdfs/data</value> </property> <property> <name>dfs.replication</name> <value>1</value> </property></configuration> 配置mapred-site.xml 注意,默认文件夹中并没有这个文件,而是有一个mapred-site.xml.template,可以将该文件复制并重命名 123456<configuration> <property> <name>mapreduce.framework.name</name> <value>yarn</value> </property></configuration> 配置yarn-site.xml 12345678910<configuration> <property> <name>yarn.nodemanager.aux-services</name> <value>mapreduce_shuffle</value> </property> <property> <name>yarn.resourcemanager.hostname</name> <value>hadoop1</value> </property></configuration> Hadoop启动格式化namenode1$ ./bin/hdfs namenode -format 启动NameNode和DataNode的守护进程1$ ./sbin/start-dfs.sh 启动ResourceManager和NodeManager的守护进程1$ ./sbin/start-yarn.sh 验证启动执行jps命令 1234567$ jps3994 SecondaryNameNode3803 DataNode4156 ResourceManager4333 Jps3695 NameNode4255 NodeManager SecondaryNameNode:它不是namenode的冗余守护进程,而是提供周期检查点和清理任务。DataNode:它负责管理连接到节点的存储(一个集群中可以有多个节点)。每个存储数据的节点运行一个datanode守护进程。ResourceManager:接收客户端任务请求,接收和监控NodeManager(NM)的资源情况汇报,负责资源的分配与调度,启动和监控ApplicationMaster(AM)。Jps:JDK提供查看当前java进程的小工具。NameNode:它是Hadoop中的主服务器,管理文件系统名称空间和对集群中存储的文件的访问。NodeManager:NodeManager(NM)是YARN中每个节点上的代理,它管理Hadoop集群中单个计算节点,包括与ResourceManger保持通信,监督Container的生命周期管理,监控每个Container的资源使用(内存、CPU等)情况,追踪节点健康状况,管理日志和不同应用程序用到的附属服务(auxiliaryservice)。 免密登陆每次在启动或者停止hadoop是都需要输入密码进行验证,此时可以设置免密登陆: 安装ssh服务 1$ yum install -y openssh-server openssh-clients 进入用户目录,生成密钥 123456$ cd ~$ cd .ssh/$ ssh-keygen -t rsa (然后一路回车)$ cp id_rsa.pub authorized_keys$ ssh localhost #如果此时不提示任何错误,则表明设置成功 Hadoop集群安装安装3台机器 安装3个虚拟机,主机名分别为hadoop1,hadoop2和hadoop3,对应的ip分别为192.168.17.133,192.168.17.134以及192.168.17.135。 修改机器名123hostnamectl set-hostname hadoop1hostnamectl set-hostname hadoop2hostnamectl set-hostname hadoop3 修改/etc/hosts文件123192.168.17.133 hadoop1192.168.17.134 hadoop2192.168.17.135 hadoop3 免密登陆123456$ cd ~$ cd .ssh/$ ssh-keygen -t rsa (然后一路回车)$ cp id_rsa.pub authorized_keys 然后修改authorized_keys文件,将三台机器的文件内容合并,然后复制到每台机器中 配置Hadoop在hadoop1机器中执行以下命令: 12345mkdir /home/hadoop/tmp mkdir /home/hadoop/var mkdir /home/hadoop/hdfs mkdir /home/hadoop/hdfs/name mkdir /home/hadoop/hdfs/data 修改core-site.xml文件: 1234567891011<configuration> <property> <name>hadoop.tmp.dir</name> <value>/home/hadoop/tmp</value> <description>Abase for other temporary directories.</description> </property> <property> <name>fs.default.name</name> <value>hdfs://hadoop1:9000</value> </property></configuration> 修改hadoop-env.sh文件: 略 修改hdfs-site.xml文件: 123456789101112131415161718<configuration> <property> <name>dfs.name.dir</name> <value>/home/hadoop/hdfs/name</value> </property> <property> <name>dfs.data.dir</name> <value>/home/hadoop/hdfs/data</value> </property> <property> <name>dfs.replication</name> <value>2</value> </property> <property> <name>dfs.permissions</name> <value>false</value> </property></configuration> 修改mapred-site.xml文件: 1234567891011121314<configuration> <property> <name>mapred.job.tracker</name> <value>hadoop1:49001</value> </property> <property> <name>mapred.local.dir</name> <value>/home/hadoop/var</value> </property> <property> <name>mapreduce.framework.name</name> <value>yarn</value> </property></configuration> 修改slaves文件: hadoop2 hadoop3 修改yarn-site.xml文件: 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556<configuration> <property> <name>yarn.resourcemanager.hostname</name> <value>hadoop1</value> </property> <property> <description>The address of the applications manager interface in the RM.</description> <name>yarn.resourcemanager.address</name> <value>${yarn.resourcemanager.hostname}:8032</value> </property> <property> <description>The address of the scheduler interface.</description> <name>yarn.resourcemanager.scheduler.address</name> <value>${yarn.resourcemanager.hostname}:8030</value> </property> <property> <description>The http address of the RM web application.</description> <name>yarn.resourcemanager.webapp.address</name> <value>${yarn.resourcemanager.hostname}:8088</value> </property> <property> <description>The https adddress of the RM web application.</description> <name>yarn.resourcemanager.webapp.https.address</name> <value>${yarn.resourcemanager.hostname}:8090</value> </property> <property> <name>yarn.resourcemanager.resource-tracker.address</name> <value>${yarn.resourcemanager.hostname}:8031</value> </property> <property> <description>The address of the RM admin interface.</description> <name>yarn.resourcemanager.admin.address</name> <value>${yarn.resourcemanager.hostname}:8033</value> </property> <property> <name>yarn.nodemanager.aux-services</name> <value>mapreduce_shuffle</value> </property> <property> <name>yarn.scheduler.maximum-allocation-mb</name> <value>2048</value> <discription>每个节点可用内存,单位MB,默认8182MB</discription> </property> <property> <name>yarn.nodemanager.vmem-pmem-ratio</name> <value>2.1</value> </property> <property> <name>yarn.nodemanager.resource.memory-mb</name> <value>2048</value> </property> <property> <name>yarn.nodemanager.vmem-check-enabled</name> <value>false</value> </property></configuration> 启动hadoop略 测试hadoop在浏览器访问 http://192.168.17.133:50070 以及 http://192.168.17.133:8088/]]></content>
<categories>
<category>大数据</category>
</categories>
<tags>
<tag>hadoop</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Zookeeper的安装和使用]]></title>
<url>%2F2018%2F02%2F05%2Fzookeeper-install%2F</url>
<content type="text"><![CDATA[jdk1.8的安装 由于采用最小化安装,所以centOS中并没有预安装的jdk,故不需要先卸载 12345rpm -qa|grep javamkdir /usr/java/mv jdk-8u161-linux-x64.tar.gz /usr/java/tar zxvf jdk-8u161-linux-x64.tar.gzmv jdk1.8.0_161/ jdk1.8 编辑配置文件,配置环境变量 12345678vim /etc/profileJAVA_HOME=/usr/java/jdk1.8CLASSPATH=$JAVA_HOME/lib/PATH=$PATH:$JAVA_HOME/binexport PATH JAVA_HOME CLASSPATHsource /etc/profile zookeeper安装123456mkdir /usr/zookeeper/mv zookeeper-3.4.11.tar.gz /usr/zookeeper/tar zxvf zookeeper-3.4.11.tar.gzcd zookeeper-3.4.11cd confcp zoo_sample.cfg zoo.cfg 新增zookeeper用户以及zookeeper组 12groupadd zookeeperuseradd -g zookeeper zookeeper 修改文件夹用户和组 12chown -R zookeeper zookeeper-3.4.11chgrp -R zookeeper zookeeper-3.4.11 新增data和logs文件夹 123cd /usr/zookeeper/zookeeper-3.4.11mkdir datamkdir logs 修改/usr/zookeeper/zookeeper-3.4.11/conf目录下的zoo.cfg文件 1234567891011121314151617181920212223242526272829303132333435363738# The number of milliseconds of each tick# zookeeper 定义的基准时间间隔,单位:毫秒tickTime=2000# The number of ticks that the initial# synchronization phase can takeinitLimit=10# The number of ticks that can pass between# sending a request and getting an acknowledgementsyncLimit=5# the directory where the snapshot is stored.# do not use /tmp for storage, /tmp here is just# example sakes.# dataDir=/tmp/zookeeper # 数据文件夹dataDir=/usr/zookeeper/zookeeper-3.4.11/data # 日志文件夹dataLogDir=/usr/zookeeper/zookeeper-3.4.11/logs # the port at which the clients will connect# 客户端访问 zookeeper 的端口号clientPort=2181 # the maximum number of client connections.# increase this if you need to handle more clients#maxClientCnxns=60## Be sure to read the maintenance section of the# administrator guide before turning on autopurge.## http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance## The number of snapshots to retain in dataDir#autopurge.snapRetainCount=3# Purge task interval in hours# Set to "0" to disable auto purge feature#autopurge.purgeInterval=1 修改系统配置文件,添加环境变量 123456789vim /etc/profileJAVA_HOME=/usr/java/jdk1.8ZOOKEEPER_HOME=/usr/zookeeper/zookeeper-3.4.11CLASSPATH=$JAVA_HOME/lib/PATH=$PATH:$JAVA_HOME/bin:$ZOOKEEPER_HOME/binexport PATH JAVA_HOME CLASSPATHsource /etc/profile zookeeper常用命令1234zkServer.sh startzkServer.sh stopzkServer.sh statuszkServer.sh restart 以集群方式启动zookeeper 先备份配置文件,然后将配置文件中的注释行去除 12mv zoo.cfg zoo.cfg.standalonegrep -v "^$" zoo.cfg.standalone | grep -v "^#" > zoo.cfg 修改配置文件,如下 123456789tickTime=2000initLimit=10syncLimit=5dataDir=/usr/zookeeper/zookeeper-3.4.11/datadataLogDir=/usr/zookeeper/zookeeper-3.4.11/logsclientPort=2181server.1=192.168.17.133:2888:3888server.2=192.168.17.134:2888:3888server.3=192.168.17.135:2888:3888 然后在配置的datadir目录下,创建一个名为myid的文件,在该文件的第一行写上一个数字,与配置文件中server.后的数字一直 123echo 1 > data/myidecho 2 > data/myidecho 3 > data/myid 在启动zookeeper集群前,需要先关闭防火墙 123systemctl stop firewalld.servicesystemctl disable firewalld.servicefirewall-cmd --state zookeeper的可执行脚本 脚本 说明 zkCleanup 清理Zookeeper的历史数据,包括事务日志和快照数据文件 zkCli ZooKeeper的一个建议客户端 zkEvn 设置ZooKeeper的环境变量 zkServer ZooKeeper服务器的启动、停止和重启脚本]]></content>
<categories>
<category>Zookeeper</category>
</categories>
<tags>
<tag>Linux</tag>
<tag>Zookeeper</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Linux的shell编程]]></title>
<url>%2F2018%2F02%2F04%2FLinux-shell%2F</url>
<content type="text"><![CDATA[shell历史Shell的作用是解释执行用户的命令,用户输入一条命令,Shell就解释执行一条,这种方式称为交互式(Interactive),Shell还有一种执行命令的方式称为批处理(Batch),用户事先写一个Shell脚本(Script),其中有很多条命令,让Shell一次把这些命令执行完,而不必一条一条地敲命令。Shell脚本和编程语言很相似,也有变量和流程控制语句,但Shell脚本是解释执行的,不需要编译,Shell程序从脚本中一行一行读取并执行这些命令,相当于一个用户把脚本中的命令一行一行敲到Shell提示符下执行。 由于历史原因,UNIX系统上有很多种Shell: sh(Bourne Shell):由Steve Bourne开发,各种UNIX系统都配有sh。 csh(C Shell):由Bill Joy开发,随BSD UNIX发布,它的流程控制语句很像C语言,支持很多Bourne Shell所不支持的功能:作业控制,命令历史,命令行编辑。 ksh(Korn Shell):由David Korn开发,向后兼容sh的功能,并且添加了csh引入的新功能,是目前很多UNIX系统标准配置的Shell,在这些系统上/bin/sh往往是指向/bin/ksh的符号链接。 tcsh(TENEX C Shell):是csh的增强版本,引入了命令补全等功能,在FreeBSD、Mac OS X等系统上替代了csh。 bash(Bourne Again Shell):由GNU开发的Shell,主要目标是与POSIX标准保持一致,同时兼顾对sh的兼容,bash从csh和ksh借鉴了很多功能,是各种Linux发行版标准配置的Shell,在Linux系统上/bin/sh往往是指向/bin/bash的符号链接。虽然如此,bash和sh还是有很多不同的,一方面,bash扩展了一些命令和参数,另一方面,bash并不完全和sh兼容,有些行为并不一致,所以bash需要模拟sh的行为:当我们通过sh这个程序名启动bash时,bash可以假装自己是sh,不认扩展的命令,并且行为与sh保持一致。 zsh 的命令补全功能非常强大,可以补齐路径,补齐命令,补齐参数等。 创建shell脚本文件在创建shell脚本文件时,必须在文件的第一行指定要使用的shell。其格式为 #!/bin/bash 注意:shell只会去处理第一行注释行,并不会处理其他的注释行。 创建shell脚本文件后,给文件添加执行权限 chmod u+x filename 如果想把脚本中的文本字符串和命令输出显示在同一行中,可以用echo语句的-n参数 echo -n “The time and date are: “ date 使用等号将值赋给用户变量时,在变量、等号和值之间不能出现空格。 testing=`date` testing=$(date) 引用一个变量值时需要使用$,而引用变量来对其进行赋值时则不要使用$: value1=10 value2=$value1 # 注意:没有使用$,shell会将变量名解释成普通的文本字符串。 命令替换有两种方法可以将命令输出赋给变量: 反引号字符`` $()格式 123456testing=`date`testing=$(date)echo "The date and time are: " $testingtoday=$(date +%y%m%d)ls /usr/bin -al > log.$today 重定向重定向包括输出重定向> >>以及输入重定向< << 内联输入重定向 执行数学运算expr命令12expr 1 + 56 使用方括号如果需要将一个数学运算结果赋给某个变量,可以用美元符和方括号: 1234var1=100var2=50var3=30var4=$[$var1 * ($var3 - $var2)] 需要注意的是,bash shell数学运算符只支持整数运算。 浮点解决方案在脚本中使用bc,基本格式如下: variable=$(echo “options; expression” | bc) 123var1=20var2=3.14159var3=$(echo "scale=4; $var1 * var2" | bc) 1234567891011121314var1=10.46var2=43.67var3=33.2var4=71var5=$(bc << EOFscale = 4a1 = ($var1 * $var2)b1 = ($var3 * $var4)a1 + b1EOF)echo $var5 退出脚本退出状态码的查看$? 状态码 描述 0 命令成功结束 1 通用未知错误 2 误用Shell命令 126 命令不可执行 127 没找到命令 128 无效退出参数 128+x Linux信号x的严重错误 130 命令通过Ctrl+C控制码越界 255 退出码越界 exit命令 结构化命令if-then123if command; then commandsfi 123if pwd; then echo "It worked"fi if-then-else123456if commandthen commandselse commandsfi 嵌套if1234567891011if command1then commandselse if command2 then more commands else more commands fifi 1234567if command1then commandselif command2then more commandsfi test命令如果test命令中列出的条件成立,test命令就会退出并返回退出状态码0。 test condition 或者可以用在if-then语句中 1234if test conditionthen commandsfi 也可以使用方括号进行测试 1234if [ condition ]then commandsfi 数值比较 比较 描述 n1 -eq n2 检查n1是否等于n2 n1 -ge n2 检查n1是否大于等于n2 n1 -gt n2 检查n1是否大于n2 n1 -le n2 检查n1是否小于等于n2 n1 -lt n2 检查n1是否小于n2 n1 -ne n2 检查n1是否不等于n2 字符串比较 比较 描述 str1 = str2 检查字符串是否相同 str1 != str2 检查字符串是否不同 str1 < str2 检查str1是否比str2大 str1 > str2 检查str1是否比str2小 -n str1 检查str1的长度是否非0 -z str1 检查str1的长度是否为0 需要注意的是,大于号和小于号在使用时需要转义 文件比较 比较 描述 -e file 如果file存在,则为真 -d file 如果file存在并为目录,则为真 -f file 如果file为常规文件,则为真 -r file 如果file存在并可读,则为真 -s file 如果file存在并非空,则为真 -w file 如果file存在并可写,则为真 -x file 如果file存在并可执行,则为真 -O file 如果file存在并属于当前用户,则为真 -G file 如果file存在并且默认组与当前用户相同,则为真 file1 -nt file2 如果file1比file2新,则为真 file1 -ot file2 如果file1比file2旧,则为真 复合条件测试if-then可以用&&和||来组合测试 if-then的高级特性使用双括号双括号命令允许你在比较过程中使用高级数学表达式。其格式如下: ((expression)) 双括号命令符号包括以下:val++,val–,++val,–val,!,~,**(幂运算),<<,>>,&,|,&&,|| 使用双方括号双方括号命令提供了针对字符串比较的高级特性。其格式如下: [[expression]] 1if [[ $USER == r* ]] case命令12345case variable inpattern1 | pattern2) commands1;;pattern3) commands2;;*) default commands;;esac for命令1234for var in listdo commandsdone for循环假定每个值都是用空格分割的。可以使用内部字段分隔符IFS来自定义分隔符,例如 IFS=$’\n’ IFS=$’\n’:;” C语言分隔的for命令命令格式: for (( variable assignment ; condition ; iteration process )) while命令while命令的基本格式: 1234while test commanddo other commandsdone until命令until命令和while命令正好相反,只有测试命令的退出状态码不为0,bash shell才会执行循环中列出的命令。 命令格式: 1234until test commandsdo other commandsdone 循环处理文件数据需要使用嵌套循环以及修改IFS环境变量 1234567891011121314IFS.OLD=$IFSIFS=$'\n'for entry in $(cat /etc/passwd)do echo "Value in $entry" IFS=: for value in $entry do if [ -n "$value" ] then echo "$value" fi donedone 控制循环break命令可以用break退出任意的循环,包括while和until循环。也可以使用break -n跳出外部循环,默认为1。 continue命令continue命令可以提前终止某次循环中的命令,但并不会完全终止整个循环。也可以使用continue -n继续执行哪一层循环。 处理循环的输出可以对循环的输出使用管道或重定向。通过在done命令之后添加一个处理命令来实现。 done > output.txt 例子创建多个用户账户 123456input="user.csv"while IFS="," read -r userid namedo echo "adding $userid" useradd -c "$name" -m "userid" done < "$input" 处理用户输入命令行参数向shell脚本传递数据的最基本方法是使用命令行参数。命令行参数允许在运行脚本时向命令行添加数据。 1./test.sh 10 abc bash shell会将一些位置参数的特殊变量分配给输入到命令行中的所有参数。这也包括shell所执行的脚本命令。其中:$0是程序名,$1是第一个参数,$2是第二个参数,一直到$9。 在使用时,需要用空格将每个命令行参数分隔开,例如: 1count=$[ $1 * $2 ] 注意,当命令行参数中出现空格时,需要使用引号: 1./test1.sh 'hello world' 如果命令行参数的数量超过9个时,从第十个参数开始,需要使用花括号,例如${10}、${11}等。 使用basename命令可以返回不包含路径的脚本名,例如: 12echo "$0"echo "$(basename $0)" 在使用命令行参数的脚本中,需要先检测其中是否存在数据: 1if [ -n "$1" ] 特殊的参数变量特殊变量$#含有脚本运行时携带的命令行参数的个数,例如: 1echo There are $# parameters supplied. 使用${!#}可以返回最后一个命令行参数的值,如果命令行参数的个数为0,则返回当前脚本的名称。 使用$*和$@可以访问所有的参数。其中$*变量会将命令行上提供的所有参数当作一个单词保存。这个单词包括了命令行中出现的每一个参数值;$@变量会将命令行上所有参数当作同一个字符串中的多个独立的单词,然后通过遍历获取所有的参数值。 12345678910111213count=1for param in "$*"do echo "\$* parameter #count = $param" count=$[ $count + 1 ]doneechocount=1for param in "$@"do echo "\$@ parameter #count = $param" count=$[ $count + 1 ]done 移动变量bash shell的shift命令可以用来操作命令行参数,shift命令会根据命令行参数的相对位置来移动。在默认情况下,会将每个参数变量向左移动一个位置。其中$2的值会移动到$1,而$1的值则会被删除,$0不会改变。 12345while [ -n "$1" ]do echo "$1" shiftdone 也可以一次性移动多个位置 shift n 处理选项选项是跟在单破折号后面的单个字母,可以用来改变命令的行为。可以使用--来表明选项列表结束。 getopt命令getopt命令能够识别命令行参数,从而在脚本中解析更加方便。 命令格式: getopt optstring parameters 其中optstring定义了命令行有效的选项字母,还定义了哪些选项字母需要参数值。 12getopt ab:cd -a -b test1 -cd test2 test3-a -b test1 -c -d -- test2 test3 如果指定了一个不再optstring中的选项,默认情况下,getopt命令会产生一条错误消息。可以在命令后加-q忽略。 在脚本中使用getopt set – $(getopt -q ab:cd “$@”) getopts命令命令格式如下: getopts optstring variable 如果选项需要跟一个参数值,OPTARG环境变量就会保存这个值。OPTIND环境变量保存了参数列表中getopts正在处理的参数位置。 获取用户输入使用read命令获取用户输入。 read命令从标准输入或另一个文件描述符接收输入。在收到输入后,read命令会将数据放进一个变量。 12read -p "Enter your name: " first lastecho $last, $first 如果在read命令行中不指定变量,那么read命令会将它收到的任何数据都放进特殊环境变量REPLY中: 12read -p "Enter your name: "echo $REPLY 在使用read命令时,需要注意超时时间,可以使用-t选项来指定计时器 1read -t 5 -p "Please enter your name: " name 如果需要隐藏输入的值时,可以使用-s选项。read在读取文件时,每次从文件中读取一行文本,当文件中没有内容时,read命令将会退出并返回非零退出状态码。 1cat test | while read line 呈现数据 文件描述符 缩写 描述 0 STDIN 标准输入 1 STDOUT 标准输出 2 STDERR 标准错误 默认情况下,STDERR文件描述符和STDOUT文件描述符指向同样的地方。 只重定向错误: ls -al errorfile 2> test 重定向错误和数据: ls -al test.txt errorfile 2>test 1>test1 同时重定向STDERR和STDOUT: ls -al test.txt errorfile &>test2 如果需要重定向到某个文件描述符时,必须在文件描述符之前加一个&: 1echo "This is an error" >&2 可以使用exec命令进行永久重定向: 12exec 1> testoutexec 0< testin 关闭文件描述符: 1exec 3>&- 如果需要阻止命令输出,可以将STDERR重定向到/dev/null。 也可以在/tmp目录中创建临时文件或文件夹。使用mktemp在本地目录创建临时文件。创建时,只需要指定一个临时模板: 123456#在当前目录创建临时文件,并返回文件名mktemp testing.xxxxxx#在系统临时目录创建临时文件,并返回全路径mktemp -t tmp.xxxxxx#在当前目录创建临时文件夹,并返回文件夹名mktemp -d dir.xxxxxx 使用tee命令可以将输出同时发送到显示器和日志文件中 date | tee testfile #将文件进行追加,使用-a选项 date | tee -a testfile 实例1234567891011#!/bin/bashoutputfile="person.sql"IFS=','while read name age addressdo cat >> $outputfile << EOF insert into person(name,age,address) values('$name','$age','$address'); EOFdone < $1 ./test.sh testfile 脚本控制处理信号常用的Linux信号如下: 信号 值 描述 1 SIGHUP 挂起进程 2 SIGINT 终止进程 3 SIGQUIT 停止进程 9 SIGKILL 无条件终止进程 15 SIGTERM 尽可能终止进程 17 SIGSTOP 无条件停止进程,但不是终止进程 18 SIGTSTP 停止或暂停进程,但不终止进程 19 SIGCONT 继续运行停止的进程 Ctrl+Z组合键会生成一个SIGTSTP信号,停止shell中运行的任何进程。停止进程会让程序继续保留在内存中,并能从上次停止的位置继续运行。 使用exit退出停止的作业,使用ps -l查看已停止的作业。 可以使用trap命令来捕获信号,其命令格式为: trap command signals 或者在trap命令后加上EXIT信号来捕获脚本的退出: 1trap "echo end..." EXIT 也可以重新使用带有选项的trap命令在脚本中的不同位置进行不同的捕获处理。 以后台模式运行脚本直接在命令后面添加&即可: ./test.sh & 注意:在ps命令的输出中,每一个后台进程都和终端会话终端联系在一起。如果终端会话退出,那么后台进程也会随之退出。 此时可以使用nohup命令来阻止后台进程在终端退出时也一起终止: nohup ./test.sh & 作业控制作业控制:启动、停止终止以及恢复作业的功能。 使用jobs命令查看shell当前正在处理的作业。jobs命令参数如下: 参数 描述 -l 列出进程的PID以及作业号 -n 只列出上次shell发出的通知后改变了状态的作业 -p 只列出作业的PID -r 只列出运行中的作业 -s 只列出已停止的作业 如果要以后台模式重启一个作业,可以用bg命令加上作业号: bg 2 如果要以前台模式重启一个作业,可以用fg命令加上作业号: fg 2 调整优先级调度优先级:内核分配给进程的CPU时间。调度优先级是一个整数值,从-20(最高优先级)到+19(最低优先级)。默认情况下以优先级0来启动所有进程。 使用nice命令设置命令启动时的调度优先级,例如: nice -n 10 ./test.sh > test.out & 使用renice命令改变运行中进程的PID,例如: renice -n 10 -p 8888 定时运行作业使用at命令来计划执行作业。at命令会将作业提交到队列中,指定shell何时运行该作业。at命令的格式如下: at [-f filename] time 当作业在运行时,Linux系统会将提交该作业的用户的电子邮件地址作为STDOUT和STDERR。所以需要在脚本中对输出进行重定向。 使用atq命令查看系统中有哪些作业在等待。 使用atrm命令来删除等待中的作业。 使用cron程序Linux系统使用cron程序来安排要定期执行的作业。cron程序会在后台运行并检查一个特殊的表,以获知已安排执行的作业。 cron时间表的格式如下: min hour dayofmonth month dayof week command 如果想在每天下午15:20执行某个文件,可以设置为: 20 15 * * * * /home/zyj/shell/tesh.sh > test.out 使用crontab命令来处理cron时间表。 函数基本函数创建函数 123function name { commands} 在函数中使用变量向函数传递参数在脚本中指定函数时,必须将参数和函数放在同一行,例如: func1 $value1 10 12345678910111213141516171819#!/bin/bashfunction add { if [ $# -eq 0] || [ $# -gt 2] then echo -1 elif [ $# -eq 1 ] then echo $[ $1 + $1 ] else echo $[ $1 + $2 ] fi}value1=$(add 10 15)value2=$(add 10)value3=$(add)value4=$(add 5 10 15)echo $value1 $value2 $value3 $value4 全局变量和局部变量使用local关键字定义局部变量。 local temp local关键字保证了变量只局限在该函数中。如果脚本中在该函数之外有同样名字的变量,那么shell将会保持这两个变量的值是分离的。 数组变量和函数向函数传递数组参数 12345678910#!/bin/bashfunction testArr { local newArr newArr=("$@") echo "The new array is ${newArr[*]}"}myArr=(1 2 3 4 5)testArr ${myArr[*]} 从函数返回数组 函数递归计算阶乘 12345678910111213141516#!/bin/bashfunction factorial { if [ $1 -eq 1 ] then echo 1 else local temp=$[ $1 - 1 ] local result=$(factorial $temp) echo $[ $result * $1 ] fi}read -p "Enter a number:" valueresult=$(factorial $value)echo "The result is: " $result]]></content>
<categories>
<category>Linux</category>
</categories>
<tags>
<tag>Linux</tag>
<tag>Shell</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Nginx中proxy_pass和rewrite详解]]></title>
<url>%2F2018%2F02%2F04%2Fnginx-proxypass-rewrite%2F</url>
<content type="text"><![CDATA[proxy_pass和rewriteproxy_pass123Syntax: proxy_pass URL;Default: —Context: location, if in location, limit_except 不影响浏览器地址栏的url 设置被代理server的协议和地址,URI可选(可以有,也可以没有) 协议可以为http或https 地址可以为域名或者IP,端口可选;eg: 1proxy_pass http://localhost:8000/uri/; 如果一个域名可以解析到多个地址,那么这些地址会被轮流使用,此外,还可以把一个地址指定为 server group(如:nginx的upstream), eg: 1234567891011121314upstream backend { server backend1.example.com weight=5; server backend2.example.com:8080; server unix:/tmp/backend3; server backup1.example.com:8080 backup; server backup2.example.com:8080 backup;} server { location / { proxy_pass http://backend; }} server name,port, URI支持变量的形式,eg: 1proxy_pass http://$host$uri; 这种情况下,nginx会在server groups(upstream后端server)里搜索server name,如果没有找到,会用dns解析请求的URI按照下面的规则传给后端server 6.1. 如果proxy_pass的URL定向里包括URI,那么请求中匹配到location中URI的部分会被proxy_pass后面URL中的URI替换,eg: 1234location /name/ { proxy_pass http://127.0.0.1/remote/;}# 请求http://127.0.0.1/name/test.html 会被代理到http://127.0.0.1/remote/test.html 6.2. 如果proxy_pass的URL定向里不包括URI,那么请求中的URI会保持原样传送给后端server,eg: 1234location /name/ { proxy_pass http://127.0.0.1;}#请求http://127.0.0.1/name/test.html 会被代理到http://127.0.0.1/name/test.html 6.3. 一些情况下,不能确定替换的URI: location里是正则表达式,这种情况下,proxy_pass里最好不要有URI; 在proxy_pass前面用了rewrite,如下,这种情况下,proxy_pass是无效的,eg:1234location /name/ { rewrite /name/([^/]+) /users?name=$1 break; proxy_pass http://127.0.0.1;} rewrite123syntax: rewrite regex replacement [flag]Default: —Context: server, location, if 如果正则表达式(regex)匹配到了请求的URI(request URI),这个URI会被后面的replacement替换 rewrite的定向会根据他们在配置文件中出现的顺序依次执行 通过使用flag可以终止定向后进一步的处理 如果replacement以“http://”, “https://”, or “$scheme”开头,处理将会终止,请求结果会以重定向的形式返回给客户端(client) 如果replacement字符串里有新的request参数,那么之前的参数会附加到其后面,如果要避免这种情况,那就在replacement字符串后面加上“?”,eg: 1rewrite ^/users/(.*)$ /show?user=$1? last;= 如果正则表达式(regex)里包含“}” or “;”字符,需要用单引号或者双引号把正则表达式引起来 可选的flag参数如下: last 结束当前的请求处理,用替换后的URI重新匹配location; 可理解为重写(rewrite)后,发起了一个新请求,进入server模块,匹配location; 如果重新匹配循环的次数超过10次,nginx会返回500错误; 返回302 http状态码 ; 浏览器地址栏显示重地向后的url break 结束当前的请求处理,使用当前资源,不在执行location里余下的语句; 返回302 http状态码 ; 浏览器地址栏显示重定向后的url redirect 临时跳转,返回302 http状态码; 浏览器地址栏显示重定向后的url permanent 永久跳转,返回301 http状态码; 浏览器地址栏显示重定向后的url]]></content>
<categories>
<category>Linux</category>
</categories>
<tags>
<tag>Linux</tag>
<tag>Nginx</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Linux之grep详解]]></title>
<url>%2F2018%2F02%2F03%2FLinux-grep%2F</url>
<content type="text"><![CDATA[grep(global search regular expression(RE) and print out the line)是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。 选项 -a 不要忽略二进制数据。 -A<显示列数> 除了显示符合范本样式的那一行之外,并显示该行之后的内容。 -b 在显示符合范本样式的那一行之外,并显示该行之前的内容。 -c 计算符合范本样式的列数。 -C<显示列数>或-<显示列数> 除了显示符合范本样式的那一列之外,并显示该列之前后的内容。 -d<进行动作> 当指定要查找的是目录而非文件时,必须使用这项参数,否则grep命令将回报信息并停止动作。 -e<范本样式> 指定字符串作为查找文件内容的范本样式。 -E 将范本样式为延伸的普通表示法来使用,意味着使用能使用扩展正则表达式。 -f<范本文件> 指定范本文件,其内容有一个或多个范本样式,让grep查找符合范本条件的文件内容,格式为每一列的范本样式。 -F 将范本样式视为固定字符串的列表。 -G 将范本样式视为普通的表示法来使用。 -h 在显示符合范本样式的那一列之前,不标示该列所属的文件名称。 -H 在显示符合范本样式的那一列之前,标示该列的文件名称。 -i 忽略字符大小写的差别。 -l 列出文件内容符合指定的范本样式的文件名称。 -L 列出文件内容不符合指定的范本样式的文件名称。 -n 在显示符合范本样式的那一列之前,标示出该列的编号。 -q 不显示任何信息。 -R/-r 此参数的效果和指定“-d recurse”参数相同。 -s 不显示错误信息。 -v 反转查找。 -w 只显示全字符合的列。 -x 只显示全列符合的列。 -y 此参数效果跟“-i”相同。 -o 只输出文件中匹配到的部分。 常见用法在文件中搜索一个单词,命令会返回一个包含“match_pattern”的文本行: grep match_pattern file_name grep “match_pattern” file_name 在多个文件中查找: grep “match_pattern” file_1 file_2 file_3 … 输出除之外的所有行 -v 选项: grep -v “match_pattern” file_name 使用正则表达式 -E 选项: grep -E “[1-9]+” 或 egrep “[1-9]+” 只输出文件中匹配到的部分 -o 选项: echo this is a test line. | grep -o -E “[a-z]+.“ line. echo this is a test line. | egrep -o “[a-z]+.“ line. 统计文件或者文本中包含匹配字符串的行数 -c 选项: grep -c “text” file_name 输出包含匹配字符串的行数 -n 选项: grep “text” -n file_name 或 cat file_name | grep “text” -n #多个文件 grep “text” -n file_1 file_2 搜索多个文件并查找匹配文本在哪些文件中: grep -l “text” file1 file2 file3… 练习 获取root用户的shell程序 1cat /etc/passwd|grep ^root.*"/root:" | cut -d : -f 7 显示CentOS7的/etc/grub2.cfg文件中,至少以一个空白 字符开头的且后面存非空白字符的行 1cat /etc/grub2.cfg | egrep "^[[:space:]] [^[:space:]]" 找出netstat -tan命令的结果中以LISTEN后跟任意多个空白字符结尾的行 1netstat -tan | grep ".*LISTEN.*$"]]></content>
<categories>
<category>Linux</category>
</categories>
<tags>
<tag>Linux</tag>
<tag>grep</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Linux的正则表达式]]></title>
<url>%2F2018%2F02%2F03%2FLinux-regular%2F</url>
<content type="text"><![CDATA[通配符 元字符 作用 * 匹配0个或任意多个字符,也就是可以匹配任何内容 ? 匹配任意一个字符 [] 匹配[ ]中任意一个字符 [-] 匹配括号中任意一个字符,-代表一个范围,例如:[a-z]代表匹配一个小写字母 [^] 逻辑非,表示匹配不是中括号内的一个字符,例如[^0-9]代表匹配一个不是数字的字符 正则表达式基础正则表达式 元字符 作用 * 前一个字符匹配0次或任意多次,匹配0次前一个字符则表示匹配任意字符,包括空白行 . 匹配除了换行符以外任意一个字符,“.*”匹配所有内容 ^ 用于指定匹配字符串的头部,也称行首定位符;匹配行首。例如:^hello会匹配以hello开头的行,grep -n “^$” test.txt匹配空白行并显示行号 $ 用于指定匹配字符串的尾部,也称行尾定位符;匹配行尾。例如:hello$会匹配以hello结尾的行 [] 匹配中括号中指定的任意一个字符,只匹配一个字符,要匹配[则要转义[ [^] 匹配除中括号的字符以外的任意一个字符 \ 转义符用于取消特殊符号的含义,匹配包含以.结尾的行grep “.$” test.txt {n} 表示其前面的字符恰好出现n次。例如:[0-9]{4}匹配4位数字,但注意添加两边的定界符,以精确匹配 {n,} 表示其前面的字符出现不小于n次。例如:[0-9]{2,}匹配2位以上的数字 {n,m} 表示其前面的字符至少出现n次,最多出现m次。例如:[a-z]{6,8}匹配6到8位的小写字母 注1:?、()是扩展正则中的元字符 注2:正则表达式中使用以上的元字符,如[]、{}、*、.等所以在匹配字符串中包含有这些元字符时必须使用反斜杠\\转义,但像<>这个非元字符符号就不需要转义。 特殊字符正则表达式识别的特殊字符包括: .*[]^${}\+?() 如果需要将特殊字符当作普通字符来使用,必须对特殊字符进行转义。 特殊字符组 组 描述 [[:alpha:]] 匹配任意的字母字符,不管是大写还是小写 [[:alnum:]] 匹配任意的字母数字字符0~9,A~Z或a~z [[:blank:]] 匹配空格或制表符 [[:digit:]] 匹配0~9之间的数字 [[:lower:]] 匹配小写字母字符a~z [[:print:]] 匹配任意可打印字符 [[:punct:]] 匹配标点符号 [[:space:]] 匹配任意空白字符:空格、制表符、NF、FF、VT和CR [[:upper:]] 匹配任意大写字母字符A~Z 扩展正则表达式 需要注意的是,gawk程序可以识别扩展正则表达式,而sed编辑器不能。 元字符 作用 | 管道符,表示或,即匹配其中任何一个,book|desk将匹配book或desk () 小括号,可以将正则字符和元字符或表达式进行组合,(book|desk)s将匹配books或desks ? 问号,匹配0个或1个前导表达式,如a?匹配其他字符串或a \< 反斜杠+小于号,词首定位符, \< abc表示所有包含以abc开头的单词的行 \> 反斜杠+大于号,词尾定位符, \>abc表示所有包含以abc结尾的单词的行 - 减号,用于指明字符范围, [a-c]将匹配包含a、b和c中任意一个字符的字符串 + 加号,匹配一个或多个前导表达式,相当于expr{1,} {} 为重复的正则表达式设定一个范围 练习目录文件计数123456789101112131415#!/bin/bashmypath=$(echo $PATH | sed 's/:/ /g')count=0for dir in $mypathdo subdir=$(ls $dir) for item in $subdir do count=$[ $count + 1] done echo "$dir ---- $count" count=0done 解析邮件地址1^([a-zA-Z0-9_\-\.\+]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$]]></content>
<categories>
<category>Linux</category>
</categories>
<tags>
<tag>Linux</tag>
<tag>Shell</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Linux之awk详解]]></title>
<url>%2F2018%2F02%2F03%2FLinux-awk%2F</url>
<content type="text"><![CDATA[awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。在awk中可以定义变量来保存数据,使用算术和字符串操作符来处理数据,使用结构化编程概念来为数据处理增加处理逻辑,以及提取文件的数据并做处理生成报告。awk有3个不同版本: awk、nawk和gawk,未作特别说明,一般指gawk,gawk是AWK的GNU版本。 命令格式 awk ‘{pattern + action}’ {filenames} 其中pattern表示AWK在数据中查找的内容,而action是在找到匹配内容时所执行的一系列命令。花括号({})不需要在程序中始终出现,但它们用于根据特定的模式对一系列指令进行分组。pattern就是要表示的正则表达式,用斜杠括起来。 调用方式awk的调用方式通常分为以下三种: 命令行方式 awk [-F field-separator] ‘commands’ input-file(s) 其中,commands 是真正awk命令,[-F域分隔符]是可选的。 input-file(s) 是待处理的文件。在awk中,文件的每一行中,由域分隔符分开的每一项称为一个域。通常,在不指名-F域分隔符的情况下,默认的域分隔符是空格。 shell脚本方式将所有的awk命令插入一个文件,并使awk程序可执行,然后awk命令解释器作为脚本的首行,一遍通过键入脚本名称来调用。 相当于shell脚本首行的:#!/bin/sh 可以换成:#!/bin/awk 将所有的awk命令插入一个单独文件,然后调用 awk -f awk-script-file input-file(s) 其中,-f选项加载awk-script-file中的awk脚本,input-file(s)跟上面的是一样的。 入门实例 显示最近登录的5个账号名 1last -n 5 | awk '{print $1}' awk工作流程是这样的:读入有’\n’换行符分割的一条记录,然后将记录按指定的域分隔符划分域,填充域,$0则表示所有域,$1表示第一个域,$n表示第n个域。默认域分隔符是”空白键” 或 “[tab]键”,所以$1表示登录用户,$3表示登录用户ip,以此类推。 只显示/etc/passwd的账户名 1cat /etc/passwd | awk -F':' '{print $1}' 这种是awk+action的示例,每行都会执行action{print $1}。 -F指定域分隔符为:。 只显示/etc/passwd的账户和账户对应的shell,并且账户与shell之间以tab键分割 1cat /etc/passwd | awk -F':' '{print $1"\t"$7}' 只显示/etc/passwd的账户和账户对应的shell,账户与shell之间以逗号分割,并且在所有行前添加列名name,shell,在最后一行添加”blue,/bin/nosh”。 1cat /etc/passwd | awk -F':' 'BEGIN{print "name,shell"} {print $1","$7} END{print "blue,/bin/nosh"}' awk工作流程是这样的:先执行BEGIN,然后读取文件,读入有/n换行符分割的一条记录,然后将记录按指定的域分隔符划分域,填充域,$0则表示所有域,$1表示第一个域,$n表示第n个域,随后开始执行模式所对应的动作action。接着开始读入第二条记录······直到所有的记录都读完,最后执行END操作。 搜索/etc/passwd有root关键字的所有行 1cat /etc/passwd | awk -F':' '/root/' 这种是pattern的使用示例,匹配了pattern(这里是root)的行才会执行action(没有指定action,默认输出每行的内容)。 搜索支持正则,例如找root开头的: awk -F: '/^root/' /etc/passwd 获取/etc/passwd有root关键字的所有行,并显示对应的shell 1cat /etc/passwd | awk -F: '/root/{print $7}' awk内置变量awk有许多内置变量用来设置环境信息,这些变量可以被改变,下面给出了最常用的一些变量。 变量名 说明 ARGC 命令行参数个数 ARGV 命令行参数排列 ARGIND 当前文件在ARGV中的位置 ENVIRON 支持队列中系统环境变量的使用 ERRNO 当读取或关闭输入文件发生错误时的系统错误号 FILENAME awk浏览的文件名 FNR 当前数据文件中的数据行数 FS 设置输入域分隔符,等价于命令行 -F选项 NF 数据文件中的字段总数 NR 已处理的输入记录数 OFS 输出域分隔符 ORS 输出记录分隔符 RS 控制记录分隔符 FIELDWIDTHS 由空格分隔的一列数字,定义了每个数据字段确切宽度;一旦设置,会忽略FS变量 练习 统计/etc/passwd:文件名,每行的行号,每行的列数,对应的完整行内容 1awk -F':' '{print "filename: " FILENAME ", linenumber: " NR ", columns: " NF ", linecontent: " $0}' /etc/passwd print和printfawk中同时提供了print和printf两种打印输出的函数。其中print函数的参数可以是变量、数值或者字符串。字符串必须用双引号引用,参数用逗号分隔。如果没有逗号,参数就串联在一起而无法区分。这里,逗号的作用与输出文件的分隔符的作用是一样的,只是后者是空格而已。printf函数,其用法和c语言中printf基本相似,可以格式化字符串,输出复杂时,printf更加好用,代码更易懂。 控制字母 描述 c 将一个数作为ASCII字符显示 d 显示一个整数值 i 显示一个整数值(跟d一样) e 用科学计数法显示一个数 f 显示一个浮点数 g 用科学计数法或浮点数显示(选择较短的格式) o 显示一个八进制值 s 显示一个文本字符串 x 显示一个十六进制值 X 显示一个十六进制值,单用大写字母 可以将上面的例子1改写为以下形式: 12 awk -F':' '{printf("filename: %10s, linenumber: %s, columns: %s, linecontent: %s\n", FILENAME, NR, NF, $0)}' /etc/passwd awk编程变量和赋值除了awk的内置变量,awk还可以自定义变量。 统计/etc/passwd的账户人数 1awk 'BEGIN{count=0} {count++} END{print "the number of users is ",count}' /etc/passwd 统计某个文件夹下的文件占用的字节数 1ls -l | awk 'BEGIN{size=0} {size+=$5;} END{print "[end]size is ",size}' 条件语句awk中的条件语句是从C语言中借鉴来的,声明方式如下: if (expression) { statement; statement; … … } 或 if (expression) { statement; } else { statement2; } 或 if (expression) { statement1; } else if (expression1) { statement2; } else { statement3; } 统计某个文件夹下的文件占用的字节数,过滤4096大小的文件 1ls -l | awk 'BEGIN{size=0} {if($5==4096){size+=$5}} END{print "the size of file is ",size}' 循环语句awk中的循环语句同样借鉴于C语言,支持while、do/while、for、break、continue,这些关键字的语义和C语言中的语义完全相同。 数组因为awk中数组的下标可以是数字和字母,数组的下标通常被称为关键字(key)。值和关键字都存储在内部的一张针对key/value应用hash的表格里。由于hash不是顺序存储,因此在显示数组内容时会发现,它们并不是按照你预料的顺序显示出来的。数组和变量一样,都是在使用时自动创建的,awk也同样会自动判断其存储的是数字还是字符串。一般而言,awk中的数组用来从记录中收集信息,可以用于计算总和、统计单词以及跟踪模板被匹配的次数等等。 显示/etc/passwd的账户 1awk -F':' 'BEGIN{count=0;} {name[count]=$1;count++} END{for(i=0;i<NR;i++){print i, name[i]}}' /etc/passwd 删除数组变量 delete array[index] 练习 取出/etc/passwd中的账户名以a或b开头的行并排序 1awk '$1~/^(a|b)/{print $0}' /etc/passwd | sort 这里需要注意~是进行对$1的模糊匹配的意思。 取出常用服务及其端口号 1cat /etc/services | awk -F'[ /]+' '$1~/^(ssh|ftp|https)/{print $1,$2}'| uniq 获取文件中空行的数量 123awk 'BEGIN{count=0} {if($0==""){count++}} END{print count}' filename或awk 'BEGIN{count=0} /^$/{count++} END{print count}' filename 从链接中获取域名 1awk -F'/' '{array[$3]++}END{for(key in array){print key,array[key]}}' filename 获取非root用户的信息 1awk -F":" '$1 !~ /root/{print $1, $NF}' /etc/passwd]]></content>
<categories>
<category>Linux</category>
</categories>
<tags>
<tag>Linux</tag>
<tag>awk</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Linux之sed详解]]></title>
<url>%2F2018%2F02%2F03%2FLinux-sed%2F</url>
<content type="text"><![CDATA[sed是一种流编辑器,它是文本处理中常营的工具,能够完美的配合正则表达式使用。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。文件内容并没有 改变,除非你使用重定向存储输出。Sed主要用来自动编辑一个或多个文件;简化对文件的反复操作;编写转换程序等。 命令格式sed [-nefri] ‘command’ 输入文本 常用选项-n∶使用安静(silent)模式。在一般 sed 的用法中,所有来自STDIN的资料一般都会被列出到屏幕上。但如果加上-n参数后,则只有经过sed特殊处理的那一行(或者动作)才会被列出来。-e∶直接在指令列模式上进行sed的动作编辑;或者需要在sed命令行上执行多个命令;例如sed -e 's/brown/green/; s/dog/cat/' test.txt;-f∶直接将sed的动作写在一个档案内,-f filename则可以执行 filename 内的sed 动作;-r∶sed的动作支援的是延伸型正规表示法的语法。(预设是基础正规表示法语法)-i∶直接修改读取的档案内容,而不是由屏幕输出。 常用命令a:新增,a的后面可以接字串,而这些字串会在新的一行出现(目前的下一行)c:取代,c的后面可以接字串,这些字串可以取代n1,n2之间的行d:删除,由于是删除,所以d后面通常不接任何符号g:新文本将会替换所有匹配的文本i:插入,i的后面可以接字串,而这些字串会在新的一行出现(目前的上一行)l:打印数据流中的文本和不可打印的ASCII字符p:打印,即将某个匹配的字符串打印。通常p会与参数 sed -n 一起使用r:将一个独立文件中的数据插入到数据流中s:替换,直接将匹配的字符串进行替换。通常与正则表达式一起使用w file:将替换的结果写到文件中 使用文本过滤器格式如下: /pattern/command 1sed '/jimmy/s/bash/csh/' /etc/passwd sed进阶多行命令N:将数据流中的下一行加进来创建一个多行组来处理;D:删除多行组中的一行;注意:D命令会强制sed编辑器返回到脚本的顶部,而不读取新的行;P:打印多行组中的一行。 next命令 123sed '/head/{n ; d}' data.txt #删除含有head行的下一行sed '/first/{N ; s/\n/ /}' data.txt #将含有first的行以及下一行当作一行处理sed 'N ; s/System.Administrator/Desktop User' data.txt 多行删除 1sed '/^$/{N ; /header/D}' data.txt #首先找到空白行,然后将下一行合并到模式空间内,由于D只会删除模式空间里的第一行,所以只会删除含有header行前的空白行 多行打印 1sed -n 'N ; /System\nAdministrator/P' data.txt #只打印多行模式空间中的第一行 保持空间模式空间是一块活跃的缓冲区,在sed编辑器执行命令时它会保存待检查的文本。但它并不是sed编辑器保存文本的唯一空间。 sed编辑器有另一块称作保持空间的缓冲区域。在处理模式空间中的某些行时,可以用保持空间来临时保存一些行。 sed编辑器的保持空间命令: 命令 描述 h 将模式空间复制到保持空间 H 将模式空间附加到保持空间 g 将保持空间复制到模式空间 G 将保持空间附加到模式空间 x 交换模式空间和保持空间的内容 1sed -n '/first/{h ; n ; p; g; p}' data.txt #将含有first的行和后面一行交换顺序输出 排除命令使用感叹号(!)来排除命令,即让原本会起作用的命令不起作用。 1sed -n '{1!G ; h ; $p}' data.txt 改变流分支命令b,格式如下:[address]b [label] 1sed '{2,3b; s/This is/Is this/; s/line./test?/}' data.txt #在第2、3行跳过替换 测试命令t,根据替换命令的结果跳转到某个标签,而不是根据地址进行跳转,格式如下:[address]t [label] 模式替代使用&符号用来代表替换命令中的匹配的模式 1$ echo "The cat sleeps in his hat." | sed 's/.at/"&"/g' sed使用圆括号来定义替换模式中的子模式。 12$ echo "The System Administrator manual" | sed 's/\(System\) Administrator/\1 User/g' 实例删除行12345sed '1d' filename #删除第一行 sed '$d' filename #删除最后一行sed '1,2d' filename #删除第一行到第二行sed '2,$d' filename #删除第二行到最后一行sed '/1/,/3/d' filename #在遇到数据行中有1时开始删除,遇到有3的行停止删除 显示行1234sed -n '1p' filename #显示第一行 sed -n '$p' filename #显示最后一行sed -n '1,2p' filename #显示第一行到第二行sed -n '2,$p' filename #显示第二行到最后一行 查询12sed -n '/centos/p' filename #查询包括关键字centos所在所有行sed -n '/\$/p' filename #查询包括关键字$所在所有行,使用反斜线\对特殊字符进行转义 增加一行或多行字符串123sed '1a drink tea' filename #第一行后增加字符串"drink tea"sed '1,3a drink tea' filename #第一行到第三行后增加字符串"drink tea"sed '1a drink\ncoffee' filename #第一行后增加多行,使用换行符\n 替换一行或多行12sed '1c Hi' filename #第一行代替为Hised '1,2c Hi' filename #第一行到第二行代替为Hi 替换一行中的某部分 格式 sed ‘s/要替换的字符串/新的字符串/g’ (要替换的字符串可以用正则表达式) 123sed -n '/centos/p' filename | sed 's/centos/redhat/g' #替换centos为redhatsed -n '/centos/p' filename | sed 's/centos//g' #删除centossed 's/test/trial/2' data.txt #只替换每行第二次出现的test 插入12sed -i '$a bye' filename #在文件filenamede 最后一行直接输入"bye"sed -n '2,$p' filename #显示第二行到最后一行 转换1sed 'y/123/789/' test.txt 将1替换为7,2替换为8,3替换为9 习题 从ip addr中找到当前主机的ip 12ip addr|sed -nr 's/.*inet (.*)\/24.*$/\1/gp'192.168.17.131 将/etc/passwd第一项和最后一项互换 1cat /etc/passwd | sed -nr 's/(.*)(:x.*:)(.*$)/\3\2\1/gp' 加倍行间距 123$ sed '$!G' data.txt#如果文本中本身就有空白行$ sed '/^$/d; $!G' data.txt 给文件中的行编号 1$ sed "=" data.txt | sed 'N; s/\n/ /g' 打印文件末尾的若干行 12345$ sed '{ :start $q; N ; 11,$D b start }' data.txt 删除连续的空白行 1$ sed '/./,/^$/!d' data.txt 删除开头的空白行 1$ sed '/./,$!d' data.txt 删除结尾的空白行 1234$ sed '{ :start /^\n*$/{$d ; N ; b start} }' data.txt 删除HTML标签 1$ sed 's/<[^>]*>//g ; /^$/d' data.txt]]></content>
<categories>
<category>Linux</category>
</categories>
<tags>
<tag>Linux</tag>
<tag>sed</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Linux常用命令]]></title>
<url>%2F2018%2F02%2F01%2FLinux-commands%2F</url>
<content type="text"><![CDATA[系统信息显示机器的处理器架构 arch uname -m 显示正在使用的内核版本 uname -r 显示CPU的信息 cat /proc/cpuinfo 显示内存使用 cat /proc/meminfo 显示内核的版本 cat /proc/version 显示系统日期 date 同步时间 ntpdate time.ntp.org 关机关闭系统 shutdown -h now init 0 重启 shutdown -r now reboot 注销 logout 文件和目录cd /home 进入/home目录 .. 返回上一级目录 - 返回上次所在的目录 pwd显示工作路径 ls -F 查看目录中的文件 -l 显示文件和目录的详细资料 -a 显示隐藏文件 mkdir创建目录 -Z:设置安全上下文,当使用SELinux时有效; -m<目标属性>或–mode<目标属性>建立目录的同时设置目录的权限; -p或–parents 若所要建立目录的上层目录目前尚未建立,则会一并建立上层目录; –version 显示版本信息。 rm rm -f file1 删除一个叫做 ‘file1’ 的文件’ rm dir dir1 删除一个叫做 ‘dir1’ 的目录’ rm -rf dir1 删除一个叫做 ‘dir1’ 的目录并同时删除其内容 rm -rf dir1 dir2 同时删除两个目录及它们的内容 mv mv dir1 new_dir 重命名/移动 一个目录 cp cp file1 file2 复制一个文件 cp dir/* . 复制一个目录下的所有文件到当前工作目录 cp -a /tmp/dir1 . 复制一个目录到当前工作目录 cp -a dir1 dir2 复制一个目录 ln文件搜索find find / -name file1 从 ‘/‘ 开始进入根文件系统搜索文件和目录 find / -user user1 搜索属于用户 ‘user1’ 的文件和目录 find /home/user1 -name *.bin 在目录 ‘/ home/user1’ 中搜索带有’.bin’ 结尾的文件 find /usr/bin -type f -atime +100 搜索在过去100天内未被使用过的执行文件 find /usr/bin -type f -mtime -10 搜索在10天内被创建或者修改过的文件 find / -name *.rpm -exec chmod 755 ‘{}’ \; 搜索以 ‘.rpm’ 结尾的文件并定义其权限 find / -xdev -name *.rpm 搜索以 ‘.rpm’ 结尾的文件,忽略光驱、捷盘等可移动设备 locate locate *.ps 寻找以 ‘.ps’ 结尾的文件 - 先运行 ‘updatedb’ 命令 whereis whereis halt 显示一个二进制文件、源码或man的位置 which which halt 显示一个二进制文件或可执行文件的完整路径 挂载文件系统mountunmount磁盘空间df -a或–all:包含全部的文件系统; –block-size=<区块大小>:以指定的区块大小来显示区块数目; -h或–human-readable:以可读性较高的方式来显示信息; -H或–si:与-h参数相同,但在计算时是以1000 Bytes为换算单位而非1024 Bytes; -i或–inodes:显示inode的信息; -k或–kilobytes:指定区块大小为1024字节; -l或–local:仅显示本地端的文件系统; -m或–megabytes:指定区块大小为1048576字节; –no-sync:在取得磁盘使用信息前,不要执行sync指令,此为预设值; -P或–portability:使用POSIX的输出格式; –sync:在取得磁盘使用信息前,先执行sync指令; -t<文件系统类型>或–type=<文件系统类型>:仅显示指定文件系统类型的磁盘信息; -T或–print-type:显示文件系统的类型; -x<文件系统类型>或–exclude-type=<文件系统类型>:不要显示指定文件系统类型的磁盘信息; –help:显示帮助; –version:显示版本信息。 du -a或-all 显示目录中个别文件的大小。 -b或-bytes 显示目录或文件大小时,以byte为单位。 -c或–total 除了显示个别目录或文件的大小外,同时也显示所有目录或文件的总和。 -k或–kilobytes 以KB(1024bytes)为单位输出。 -m或–megabytes 以MB为单位输出。 -s或–summarize 仅显示总计,只列出最后加总的值。 -h或–human-readable 以K,M,G为单位,提高信息的可读性。 -x或–one-file-xystem 以一开始处理时的文件系统为准,若遇上其它不同的文件系统目录则略过。 -L<符号链接>或–dereference<符号链接> 显示选项中所指定符号链接的源文件大小。 -S或–separate-dirs 显示个别目录的大小时,并不含其子目录的大小。 -X<文件>或–exclude-from=<文件> 在<文件>指定目录或文件。 –exclude=<目录或文件> 略过指定的目录或文件。 -D或–dereference-args 显示指定符号链接的源文件大小。 -H或–si 与-h参数相同,但是K,M,G是以1000为换算单位。 -l或–count-links 重复计算硬件链接的文件。 用户和组useradd创建的新的系统用户。使用useradd指令所建立的帐号,实际上是保存在/etc/passwd文本文件中。 -c<备注>:加上备注文字。备注文字会保存在passwd的备注栏位中; -d<登入目录>:指定用户登入时的启始目录; -D:变更预设值; -e<有效期限>:指定帐号的有效期限; -f<缓冲天数>:指定在密码过期后多少天即关闭该帐号; -g<群组>:指定用户所属的群组; -G<群组>:指定用户所属的附加群组; -m:自动建立用户的登入目录; -M:不要自动建立用户的登入目录; -n:取消建立以用户名称为名的群组; -r:建立系统帐号; -s:指定用户登入后所使用的shell; -u:指定用户id。 userdel删除给定的用户,以及与用户相关的文件。若不加选项,则仅删除用户帐号,而不删除相关文件。 -f:强制删除用户,即使用户当前已登录; -r:删除用户的同时,删除与用户相关的所有文件。 passwd设置用户的认证信息,包括用户密码、密码过期时间等。系统管理者则能用它管理系统用户的密码。只有管理者可以指定用户名称,一般用户只能变更自己的密码。 -d:删除密码,仅有系统管理者才能使用; -f:强制执行; -k:设置只有在密码过期失效后,方能更新; -l:锁住密码; -s:列出密码的相关信息,仅有系统管理者才能使用; -u:解开已上锁的帐号。 groupadd创建一个新的工作组,新工作组的信息将被添加到系统文件中。 -g:指定新建工作组的id; -r:创建系统工作组,系统工作组的组ID小于500; -K:覆盖配置文件“/ect/login.defs”; -o:允许添加组ID号不唯一的工作组。 groupdel删除指定的工作组,本命令要修改的系统文件包括/ect/group和/ect/gshadow。若该群组中仍包括某些用户,则必须先删除这些用户后,方能删除群组。 文件权限chmod用来变更文件或目录的权限。在UNIX系统家族里,文件或目录权限的控制分别以读取、写入、执行3种一般权限来区分,另有3种特殊权限可供运用。用户可以使用chmod指令去变更文件与目录的权限,设置方式采用文字或数字代号皆可。符号连接的权限无法变更,如果用户对符号连接修改权限,其改变会作用在被连接的原始文件。 权限范围表示法如下:u User,即文件或目录的拥有者;g Group,即文件或目录的所属群组;o Other,除了文件或目录拥有者或所属群组之外,其他用户皆属于这个范围;a All,即全部的用户,包含拥有者,所属群组以及其他用户;r 读取权限,数字代号为“4”;w 写入权限,数字代号为“2”;x 执行或切换权限,数字代号为“1”;- 不具任何权限,数字代号为“0”;s 特殊功能说明:变更文件或目录的权限。 -c或——changes:效果类似“-v”参数,但仅回报更改的部分; -f或–quiet或——silent:不显示错误信息; -R或——recursive:递归处理,将指令目录下的所有文件及子目录一并处理; -v或——verbose:显示指令执行过程; –reference=<参考文件或目录>:把指定文件或目录的所属群组全部设成和参考文件或目录的所属群组相同; <权限范围>+<权限设置>:开启权限范围的文件或目录的该选项权限设置; <权限范围>-<权限设置>:关闭权限范围的文件或目录的该选项权限设置; <权限范围>=<权限设置>:指定权限范围的文件或目录的该选项权限设置; chownchgrp打包和压缩gziptarzipyum软件包管理 yum install package_name 下载并安装一个rpm包 yum localinstall package_name.rpm 将安装一个rpm包,使用你自己的软件仓库为你解决所有依赖关系 yum update package_name.rpm 更新当前系统中所有安装的rpm包 yum update package_name 更新一个rpm包 yum remove package_name 删除一个rpm包 yum list 列出当前系统中安装的所有包 yum search package_name 在rpm仓库中搜寻软件包 yum clean packages 清理rpm缓存删除下载的包 yum clean headers 删除所有头文件 yum clean all 删除所有缓存的包和头文件]]></content>
<categories>
<category>Linux</category>
</categories>
<tags>
<tag>Linux</tag>
</tags>
</entry>
<entry>
<title><![CDATA[docker的安装和使用]]></title>
<url>%2F2018%2F02%2F01%2Fdocker%2F</url>
<content type="text"><![CDATA[docker安装在最小化安装的情况下,docker是没有安装的,所以不需要先卸载。 安装yum-config-manager工具 1yum -y install yum-utils 设置Docker仓库 1yum-config-manager --add-repo https://docs.docker.com/v1.13/engine/installation/linux/repo_files/centos/docker.repo 更新yum源并安装最新的docker 12yum makecache fastyum -y install docker-engine 启动docker 12systemctl start dockersystemctl enable docker 升级docker 123yum makecache fastyum list docker-engine.x86_64 --showduplicates |sort -ryum -y install docker-engine-<VERSION_STRING>]]></content>
<categories>
<category>Linux</category>
</categories>
<tags>
<tag>Linux</tag>
<tag>docker</tag>
</tags>
</entry>
<entry>
<title><![CDATA[vim基础]]></title>
<url>%2F2018%2F02%2F01%2Fvim-base%2F</url>
<content type="text"><![CDATA[vim编辑器在内存缓冲区中处理数据。 vim编辑器有两种操作模式:普通模式和插入模式。 vim移动光标的命令:h-左 j-下 k-上 l-右 快速移动命令:PageDown、PageUp、G(最后一行)、num G(移动到第num行)、gg(移动到第一行) 编辑数据x 删除当前光标所在位置的字符dd 删除当前光标所在行dw 删除当前光标所在位置的单词d$ 删除当前光标所在位置至行尾的内容J 删除当前光标所在行尾的换行符u 撤销前一编辑命令a 在当前光标后追加数据 复制和粘贴先使用dd删除,然后使用p粘贴yw 复制一个单词y$ 复制到行尾 查找和替换/content n:s/old/new/ 替换:s/old/new/g:n,ms/old/new/g 替换行号n和m之间所有old:%s/old/new/g 替换整个文件中所有old:%s/old/new/gc 替换整个文件中的所有old,但在每次出现时提示]]></content>
<categories>
<category>Linux</category>
</categories>
<tags>
<tag>Linux</tag>
<tag>vim</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Nginx+Keepalived的安装和使用]]></title>
<url>%2F2018%2F01%2F31%2Fkeepalived-nginx%2F</url>
<content type="text"><![CDATA[vim安装1yum install vim -y 修改ip修改/etc/sysconfig/network-scripts/ifcfg-eth0的内容(如果该文件不存在,先新建) 12345678DEVICE=eth0 #网卡对应的设备别名BOOTPROTO=static #设置为静态IP,staticONBOOT=yesDNS1=114.114.114.114HWADDR=00:07:E9:05:E8:B4 #对应的网卡物理地址,可以不用配置IPADDR=192.168.17.133 #ip地址静态指定NETMASK=255.255.255.0 GATEWAY=192.168.17.2 然后在虚拟机->设置->网络适配器中选择自定义VMnet8 可以将原有的ifcfg-enoxxxxxxx文件删除,然后修改grub文件vim /etc/default/grub然后在GRUB_CMDLINE_LINUX原有的参数后面加上"net.ifnames=0 biosdevname=0",保存退出后,执行grub2-mkconfig -o /boot/grub2/grub.cfg然后重启计算机 添加用户和权限123456789$ useradd apache$ passwd apache$ visudo $ /root$ yyp 安装apache12345678910111213141516171819yum install httpd httpd-devel#开启apache服务systemctl start httpd.service#关闭apache服务systemctl stop httpd.service#设置为开机启动systemctl enable httpd.service#关闭防火墙systemctl stop firewalld.service#开机不启动防火墙systemctl disable firewalld.service#apache默认使用/var/www/html文件夹里的资源,故可以创建一个index.html文件echo apache133 > index.html 安装Nginx使用压缩包安装nginx 切换为root用户 进入/usr/local/src目录下 下载Nginx、openssl、pcre以及zlib 1234wget http://nginx.org/download/nginx-1.12.2.tar.gzwget https://www.openssl.org/source/openssl-fips-2.0.16.tar.gzwget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.40.tar.gzwget http://www.zlib.net/zlib-1.2.11.tar.gz 可能需要先安装c++编译环境 1yum install gcc-c++ 安装openssl 1234tar zxvf openssl-fips-2.0.16.tar.gz cd openssl-fips-2.0.16/./configmake && make install 安装pcre 1234tar zxvf pcre-8.40.tar.gz cd pcre-8.40/./configuremake && make install 安装zlib 1234tar zxvf zlib-1.2.11.tar.gz cd zlib-1.2.11/./configuremake && make install 安装Nginx 1234tar zxvf nginx-1.12.2.tar.gz cd nginx-1.12.2/./configuremake && make install 启动Nginx 1/usr/local/nginx/sbin/nginx Nginx基本操作 12345678910#启动[root@localhost ~]# /usr/local/nginx/sbin/nginx#停止/重启[root@localhost ~]# /usr/local/nginx/sbin/nginx -s stop(quit、reload)#命令帮助[root@localhost ~]# /usr/local/nginx/sbin/nginx -h#验证配置文件[root@localhost ~]# /usr/local/nginx/sbin/nginx -t#配置文件[root@localhost ~]# vim /usr/local/nginx/conf/nginx.conf 获取Nginx的安装位置 1whereis nginx 修改Nginx的配置文件 12[root@localhost conf]# cd /usr/local/nginx/conf/[root@localhost conf]# vim nginx.conf 在http内添加 1234upstream test.com{ server 192.168.17.133:80 weight=5; server 192.168.17.134:80 weight=1;} 在http->server中的location中添加 12345678location / { proxy_pass http://test.com; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; root html; index index.html index.htm;} 安装rz和sz 1yum install lrzsz 使用yum安装nginx(推荐) 本地yum源中没有我们想要的nginx,那么就需要创建一个/etc/yum.repos.d/nginx.repo的文件,新增一个yum源。 1vim /etc/yum.repos.d/nginx.repo 然后加入如下内容 12345[nginx]name=nginx repobaseurl=http://nginx.org/packages/centos/$releasever/$basearch/gpgcheck=0enabled=1 查询nginx的相关信息并安装 12yum list | grep nginxyum install -y nginx 安装Keepalived安装Keepalived12345wget http://www.keepalived.org/software/keepalived-1.2.24.tar.gztar -zxvf keepalived-1.2.24.tar.gzcd keepalived-1.2.24./configure --prefix=/usr/local/keepalivedmake && make install 在安装时可能会出现如下错误\!!! OpenSSL is not properly installed on your system. !!!\!!! Can not include OpenSSL headers files.\解决办法:yum -y install openssl-devel 也可以直接使用yum安装 1yum install keepalived 配置Keepalivedkeepalived启动时会从/etc/keepalived目录下查找keepalived.conf配置文件,如果没有找到则使用默认的配置。/etc/keepalived目录安装时默认是没有安装的,需要手动创建。 先备份配置文件 1cp keepalived.conf keepalived.conf.bak 在启动keepalived前先关闭防火墙和selinux 12345678910systemctl stop firewalld.servicesystemctl disable firewalld.servicegetenforce/usr/sbin/sestatus -v#临时关闭setenforce 0#永久关闭vim /etc/selinux/config#将SELINUX=enforcing改为SELINUX=disabled,必须重启才能生效]]></content>
<categories>
<category>Linux</category>
</categories>
<tags>
<tag>Linux</tag>
<tag>Nginx</tag>
<tag>Keepalived</tag>
</tags>
</entry>
<entry>
<title><![CDATA[HEXO安装与使用]]></title>
<url>%2F2018%2F01%2F30%2Fhexo-install-use%2F</url>
<content type="text"><![CDATA[nodejs安装 通过EPEL的方式进行安装 12345678# 安装epelyum install -y epel-releaseyum repolist# 安装nodeyum install -y nodejsnode --versionyum install npm hexo安装1npm install hexo-cli -g 快速新建一个博客系统 1234hexo init blogcd blognpm installhexo server hexo常用命令123456# 清空缓存hexo clean# 生成静态网页hexo g# 启动hexo服务,默认端口为4000hexo s 安装NEXT主题 资源链接 https://github.com/iissnan/hexo-theme-next 安装方法 12345$ cd hexo$ ls_config.yml node_modules package.json public scaffolds source themes$ mkdir themes/next$ curl -s https://api.github.com/repos/iissnan/hexo-theme-next/releases/latest | grep tarball_url | cut -d '"' -f 4 | wget -i - -O- | tar -zx -C themes/next --strip-components=1 NEXT的相关配置 对于整个项目,有一个站点配置文件_config.yml,该文件位于根目录下,在本项目中位于/root/blog目录下,对于每个主题,都有一个主题的配置文件_config.yml,位于每个主题的根目录下,在本项目中位于/root/blog/themes/next目录下: 1234567$ ls /root/blog/_config.yml node_modules public sourcedb.json package.json scaffolds themes$ ls /root/blog/themes/next/bower.json gulpfile.coffee layout package.json README.md source_config.yml languages LICENSE README.cn.md scripts test 添加分类标签 如果需要给首页添加分页,首先修改主题配置文件,将menu下的about前的#去除: 123456789menu: home: / #tags: /tags/ || tags categories: /categories/ archives: /archives/ about: /about/ #schedule: /schedule/ || calendar #sitemap: /sitemap.xml || sitemap #commonweal: /404/ || heartbeat 然后在source目录下新建一个categories文件夹,并在该文件夹中添加一个index.md文件 123$ cd /root/blog/source$ mkdir categories/$ vim index.md 在文件中添加以下内容 123456---title: 文章分类date: 日期type: "categories"comments: false--- 然后在文件的头部添加以下内容: 12345---title: Hello Worldcategories: - test--- 添加动态背景 打开 next/layout/_layout.swig在</body>之前添加代码(注意不要放在</head>的后面): 123{% if theme.canvas_nest %}<script type="text/javascript" src="//cdn.bootcss.com/canvas-nest.js/1.0.0/canvas-nest.min.js"></script>{% endif %} 修改主题配置文件,将canvas_nest修改为true 1canvas_nest: true 添加更新时间 修改语言配置文件/themes/next/languages/zh_Hans.yml,在post下添加以下内容: 12post: updated: 更新于 修改主题配置文件/themes/next/_config.yml 1updated_at: true 写文章的时候可以直接在文章开头设置更新时间 1modified: 添加站内搜索安装hexo-generator-search 在站点的根目录下执行以下命令: 1npm install hexo-generator-search --save 安装 hexo-generator-searchdb 在站点的根目录下执行以下命令: 1npm install hexo-generator-searchdb --save 启用搜索 编辑站点配置文件,新增以下内容到最后: 12345search: path: search.xml field: post format: html limit: 10000 编辑主题配置文件,将local_search下的enable改为true: 12local_search: enable: true 上传代码到github注册Github的账号略 创建Repository创建的时候需要注意Repository的名字。例如我的Github账号是pchad321,那么应该创建的Repository的名字为:pchad321.github.io 修改配置文件 进入刚刚创建的Repository,复制Repository的连接,例如https://github.com/pchad321/pchad321.github.io.git 修改站点配置文件 12345deploy: type: git repo: https://github.com/pchad321/pchad321.github.io.git branch: master message: 'updated at:{{now("YYYY-MM-DD HH/mm/ss")}}' 设置SSH keys 配置本机全局git环境 12git config --global user.email "[email protected]"git config --global user.name "Your Name" 生成SSH密钥 1234# -C后面是github上的用户邮箱地址ssh-keygen -t rsa -C [email protected]# 然后一路回车 将SSH密钥添加到github中 1less ~/.ssh/id_rsa.pub 复制出现的一堆密码,然后在github的SSH and GPG keys中粘贴这一段密码 设置的验证 在本地输入以下代码: 1ssh -T [email protected] 如果在最后出现了你配置的用户名,说明配置成功 提交代码到github上 12hexo generatehexo deploy 在提交代码时可能会出现ERROR Deployer not found: git的错误,此时只需要运行以下命令 1npm install --save hexo-deployer-git 将Hexo的源码备份到Github分支里面上传到分支里存储,修改本地的时候先上传存储,再发布。更换电脑的时候再下载下来源文件 12345$ git init$ git remote add origin [email protected]:username/username.github.io.git$ git add .$ git commit -m "blog"$ git push origin master:Hexo-Blog 在本地写好博文后,可以先执行: 123$ git add .$ git commit -m "blog"$ git push origin master:Hexo-Blog]]></content>
<categories>
<category>前端</category>
</categories>
<tags>
<tag>Linux</tag>
<tag>HEXO</tag>
</tags>
</entry>
</search>