将Centos的yum源更换为国内的阿里云源

有的时候yum安装一些软件,直接404或者timeout,此时可以更改为国内的源。
阿里云Linux安装软件镜像源
阿里云是最近新出的一个镜像源。得益与阿里云的高速发展,这么大的需求,肯定会推出自己的镜像源。
阿里云Linux安装镜像源地址:http://mirrors.aliyun.com/
CentOS系统更换软件安装源
第一步:备份你的原镜像文件,以免出错后可以恢复。
mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup

第二步:下载新的CentOS-Base.repo 到/etc/yum.repos.d/
CentOS 6
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-6.repo
CentOS 7
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
第三步:运行yum makecache生成缓存
yum clean all
yum makecache

Elasticsearch学习(一)

对于全文检索,只是在刚毕业时研究过sphinx的皮毛,当时项目中选用了sphinx的中文版coreseek,感觉真心强大。而在后来的工作中,也没有再去深入的研究过,而之后看到的文章中,提到最多的只有Solr、Lucene、Elasticsearch这三个基于java的全文检索库,今天工作之余,好好研究一番。

先做了下术语调查,发现Solr与Lucene现在都是Apache基金在维护,Lucene只是一个java框架,如果想使用的话必须要使用java,在程序中集成,了解其原理,所以要求相对较高了。而Solr是最流行的企业级搜索引擎,Solr4 还增加了NoSQL支持,它成熟稳定,还支持html、pdf、doc、xls、json、xml、csv等多种格式的索引。但其缺点也相对明显,数据量增大、搜索效率会降低,实时搜索会阻塞io,效率不高。
Elasticsearch是一个建立在全文搜索引擎 Apache Lucene™ 基础上的搜索引擎,可以说Lucene是当今最先进,最高效的全功能开源搜索引擎框架,使用它做全文搜索时,只需要使用统一开发好的API即可,而不需要了解其背后复杂的Lucene的运行原理。它在全文搜索、实时搜索、分布式搜索、无缝扩展机器处理pb级别数据等方面都非常出色。因此,这里我选择研究Elasticsearch,并记录下自己的所有理解。

  1. 安装
    首先从官网下载安装包:https://www.elastic.co/downloads/elasticsearch,这里我下载的是zip包,版本5.5.1。
    接下来解压文件
    unzip elasticsearch-5.5.1.zip

    接下来安装marvel插件,marvel一个管理和监控的工具,是个插件:

    1
    2
    cd elasticsearch-5.5.1
    ./bin/plugin -i elasticsearch/marvel/latest

    此时,如果想关闭监控,则可以使用以下命令:
    echo 'marvel.agent.enabled: false' >> ./config/elasticsearch.yml

  2. 运行
    ./bin/elasticsearch
    此时如果只有本地访问,则可以修改配置文件 elasticsearch.yml中network.host(注意配置文件格式不是以#开头的要空一格,:后要空一格) 为network.host: 0.0.0.0
    如果想在后台以守护进程模式运行,添加-d参数。

  3. 测试
    执行下面的测试命令即可以看到结果
    curl 'http://localhost:9200/?pretty'
    也可以使用下面命令来关闭它:
    curl -XPOST 'http://localhost:9200/_shutdown'

  4. 查看marvel和sense
    如果你安装了Marvel(作为管理和监控的工具),就可以在浏览器里通过以下地址访问它:
    http://localhost:9200/_plugin/marvel/
    你可以在Marvel中通过点击dashboards,在下拉菜单中访问Sense开发者控制台,或者直接访问以下地址:
    http://localhost:9200/_plugin/marvel/sense/
  5. 端口及通信
    java客户端分为节点客户端(只加入集群、无数据存储)、传输客户端(不加入集群,只请求至节点客户端),两种客户端与集群的交互端口均为9300,假设不开此端口,则不会组 成集群,9200端口则是其他语言通过restful api的形式与Elasticsearch进行通信。

使用

Elasticsearch以json结构的文档存储。Elasticsearch集群可以包含多个索引(indices)(数据库),每一个索引可以包含多个类型(types)(表),每一个类型包含多个文档(documents)(行),然后每个文档包含多个字段(Fields)(列)。倒排索引 传统数据库为特定列增加一个索引,例如B-Tree索引来加速检索。Elasticsearch和Lucene使用一种叫做倒排索引(inverted index)的数据结构来达到相同目的。
与传统关系型数据库的类比图

1
2
Relational DB -> Databases -> Tables -> Rows -> Columns
Elasticsearch -> Indices -> Types -> Documents -> Fields

简单例子如下:

1
2
3
4
5
6
7
8
PUT /megacorp/employee/1
{
"first_name" : "John",
"last_name" : "Smith",
"age" : 25,
"about" : "I love to go rock climbing",
"interests": [ "sports", "music" ]
}

其中megacorp:索引名,employee:类型名;1:这个员工的ID。(另外,再put一次,则更新此文档)

检索

获取的一条数据,保存在_source节点里
GET /megacorp/employee/1

简单搜索,默认搜索结果10条,结果保存在hits数组节点里。
GET /megacorp/employee/_search

查询搜索,结果也在hits数组节点里
GET /megacorp/employee/_search?q=last_name:Smith

使用DSL(Domain Specific Language特定领域语言)语句查询

1
2
3
4
5
6
7
8
GET /megacorp/employee/_search
{
"query" : {
"match" : {
"last_name" : "Smith"
}
}
}

带过滤器的搜索

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
GET /megacorp/employee/_search
{
"query" : {
"filtered" : {
"filter" : {
"range" : {
"age" : { "gt" : 30 } <1>
}
},
"query" : {
"match" : {
"last_name" : "smith" <2>
}
}
}
}
}

搜索短语:如果match_phrase改为match,则会搜索出包含rock或者climbing的结果

1
2
3
4
5
6
7
8
GET /megacorp/employee/_search
{
"query" : {
"match_phrase" : {
"about" : "rock climbing"
}
}
}

搜索结果高亮:

1
2
3
4
5
6
7
8
9
10
11
12
13
GET /megacorp/employee/_search
{
"query" : {
"match_phrase" : {
"about" : "rock climbing"
}
},
"highlight": {
"fields" : {
"about" : {}
}
}
}

聚合,就是完成数据的统计分析,类似于sql的group by
1
2
3
4
5
6
7
8
GET /megacorp/employee/_search
{
"aggs": {
"all_interests": {
"terms": { "field": "interests" }
}
}
}

返回结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
...
"hits": { ... },
"aggregations": {
"all_interests": {
"buckets": [
{
"key": "music",
"doc_count":
},
{
"key": "forestry",
"doc_count": 1
},
{
"key": "sports",
"doc_count": 1
}
]
}
}
}

加上搜索语句的聚合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
GET /megacorp/employee/_search
{
"query": {
"match": {
"last_name": "smith"
}
},
"aggs": {
"all_interests": {
"terms": {
"field": "interests"
}
}
}
}

返回结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
...
"all_interests": {
"buckets": [
{
"key": "music",
"doc_count": 2
},
{
"key": "sports",
"doc_count": 1
}
]
}

聚合也允许分级汇总。例如,让我们统计每种兴趣下职员的平均年龄:

1
2
3
4
5
6
7
8
9
10
11
12
13
GET /megacorp/employee/_search
{
"aggs" : {
"all_interests" : {
"terms" : { "field" : "interests" },
"aggs" : {
"avg_age" : {
"avg" : { "field" : "age" }
}
}
}
}
}

返回结果如下:

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
...
"all_interests": {
"buckets": [
{
"key": "music",
"doc_count": 2,
"avg_age": {
"value": 28.5
}
},
{
"key": "forestry",
"doc_count": 1,
"avg_age": {
"value": 35
}
},
{
"key": "sports",
"doc_count": 1,
"avg_age": {
"value": 25
}
}
]
}

selenium+phantomjs抓取动态网页数据

接到fang88的技术考核题,要求如下:

  1. 使用python3
  2. 只写一个crawl.py文件,传递url参数

    url示例
    https://www.lennar.com/new-homes/washington/seattle
    https://www.lennar.com/new-homes/texas/houston

  3. 爬取后的数据ajax抛给指定的接口。

因为经常会爬一些数据,所以大体看了一下,就一个网址,感觉应该挺简单的。
考虑到平时都用py2的scrapy来做爬虫,今天正好再熟悉下py3,也没有用bs4,因为最近发现lxml的xpath解析挺爽的
直接代码开撸,嘿嘿!

首先,根据要求,需要拿到参数,命令行如下:
python3 crawl.py https://www.lennar.com/new-homes/washington/seattle

1
2
3
4
if len(argv) != 2:
print('参数格式错误')
else:
print(argv[1])

开始分析网址、抓取数据,分析网页内容,发现都是动态数据,因此选择用selenium和phantomjs来抓取

1
2
3
4
5
6
7
8
9
10
driver = webdriver.PhantomJS(executable_path='/Users/apple/Downloads/phantomjs-2.1.1-macosx/bin/phantomjs')
driver.get(url)
selector = etree.HTML(driver.page_source.encode('utf-8'))
items = selector.xpath('//div[@class="comm-item clearfix"]')
for item in items:
temp = item.xpath('./h1/a/text()')
name = temp[0] if len(temp) > 0 else ''
temp = item.xpath('./h2/a/text()')
name = name + ' ' + (temp[0] if len(temp) > 0 else '')
print(name)

通过上述代码,很快就抓到首页要的内容,接下来准备抓分页,发现是#标签,然后用chrome来network检查元素,查看post的接口,找到相关的,但post的参数太多,所以想用之前做模拟登陆时的模拟点击来实现,代码如下:

1
driver.find_element_by_xpath('//div[@class="sptop"]//a[@class="ir next"]').click()

运行调试,报错了:
ElementNotVisibleException
通过报错,然后按以往的经验,加上延时,发现仍然无效,不明所以之后,尝试其他链接的模拟点击,发现可以。最后选择最原始也是最有效的调用js方法来解决。(如果有哪位高人知道原因,可以告诉我,非常感谢)

1
2
with open('test.html', 'w+') as f:
f.write(driver.page_source)

保存下网页,去查看相关的js及变量的内容。通过检查发现调用了两个接口,先做第一个接口,分析参数为页面里js的变量,于是通过js来得到:

1
2
acetParams = driver.execute_script("return facetContextJSON.params")
pageState = driver.execute_script("return pageState")

接着通过postman来抓取的header,复制进去,并通过xpath抓取到总页数,通过requests来获取json数据

1
2
3
4
5
def get_otherpage(page, facetParams, pageState, headers):
pageState['pn'] = page
payload = json.dumps({'searchState':facetParams, 'pageState': pageState})
url = 'https://cn.lennar.com/Services/REST/Facets.svc/GetFacetResults'
response = requests.request("POST", url, data=payload, headers=headers)

发现成功获取json结果,接着分析第二个接口,参数是第一个接口的返回部分数据,执行代码如下:

1
2
3
4
5
6
7
8
9
url = "https://cn.lennar.com/Services/Rest/SearchMethods.svc/GetCommunityDetails"
pageState.update({"pt":"C","ic":19,"ss":0,"attr":"No ne","ius":False})
payload = json.dumps({'facetResults': response.json()['fr'], 'pageState':pageState})
response = requests.request("POST", url, data=payload, headers=headers)
for item in response.json():
name = item['cnm']
if item['mcm']:
name += item['mcm']
print(name)

到此,所有需求的数据都可以得到了。因为只是测试,所以没有封装成类,也直接使用了postman抓到的cookie.
测试代码在github

mac系统下,用excel打开csv文件,中文乱码问题

csv中文乱码问题

今天要导出在mongo的数据,直接输入命令
mongoexport -d test -c testitem --type=csv -f name,phone,tel,address -o ./test.csv

导出后直接用excel打开,发现中文全是乱码。于是google,发现用excel导入文本的方式也出错(可能是我的文件里本身数据有一些格式问题)、使用sublime另存utf-8格式也是不行。很是纠结,正准备自己写个脚本来完成的时候,找到了问题的解决方法:
命令行输入:
iconv -f UTF8 -t GB18030 test.csv >test_new.csv
发现好使。

另外一种方式:直接将mac电脑上导出的test.csv发到windows上,用wps打开也是正常的,另存为xls格式,再发回mac上,用excel打开也是正常的了。

特做此备忘遇坑问题记录!!!

|