爬虫系统的要求

基本要求

  • 遍历链接,并获取网页
  • 网页解析,分析
  • 数据存储
  • 日志: 错误日志, 运行日志

分布式要求

  • 并行爬取: 效率高, 可以设定爬虫的数目
  • 任务管理: 任务队列, 出错了可以重新爬取
  • 代理: 考虑到爬取太多,可能会触发拦截,因此需要通过代理。
  • 策略: 可以灵活的设定策略, 爬取频率, 爬取数量, 使用不同的网管,使用不同的header

爬虫管理

  • 不同的网站,爬虫的规则是不一样的,因此爬虫可以自定义规则
  • 脚本: 有些网站可能需要登录认证。

循序渐进

v0.1 http请求

    baseUrl := "http://www.xxx.cn"
    req,_  := http.NewRequest("GET",baseUrl,nil)
    req.Header.Set("User-Agent", GetRandomUserAgent())
    client := http.DefaultClient
    res, e := client.Do(req)

    if e !=nil {
        fmt.Print(e)
        return
    }

    if res.StatusCode == 200 {
        body := res.Body
        defer body.Close()
        bodyByte,_ := ioutil.ReadAll(body)
        resStr := string(bodyByte)
        print(resStr)
    }

序言

看过很多方面的编码规范,可能每一家公司都有不同的规范,这份编码规范是写给我自己的,同时希望我们公司内部同事也能遵循这个规范来写Go代码。

如果你的代码没有办法找到下面的规范,那么就遵循标准库的规范,多阅读标准库的源码,标准库的代码可以说是我们写代码参考的标杆。
格式化规范

go默认已经有了gofmt工具,但是我们强烈建议使用goimport工具,这个在gofmt的基础上增加了自动删除和引入包.

go get golang.org/x/tools/cmd/goimports

不同的编辑器有不同的配置, sublime的配置教程:http://michaelwhatcott.com/gosublime-goimports/

LiteIDE默认已经支持了goimports,如果你的不支持请点击属性配置->golangfmt->勾选goimports

保存之前自动fmt你的代码。
行长约定

一行最长不超过80个字符,超过的请使用换行展示,尽量保持格式优雅。
go vet

vet工具可以帮我们静态分析我们的源码存在的各种问题,例如多余的代码,提前return的逻辑,struct的tag是否符合标准等。

go get golang.org/x/tools/cmd/vet

使用如下:

go vet .

package名字

保持package的名字和目录保持一致,尽量采取有意义的包名,简短,有意义,尽量和标准库不要冲突。
import 规范

import在多行的情况下,goimports会自动帮你格式化,但是我们这里还是规范一下import的一些规范,如果你在一个文件里面引入了一个package,还是建议采用如下格式:

import (
"fmt"
)

如果你的包引入了三种类型的包,标准库包,程序内部包,第三方包,建议采用如下方式进行组织你的包:

import (
"encoding/json"
"strings"

"myproject/models"
"myproject/controller"
"myproject/utils"

"github.com/astaxie/beego"
"github.com/go-sql-driver/mysql"

)

有顺序的引入包,不同的类型采用空格分离,第一种实标准库,第二是项目包,第三是第三方包。

在项目中不要使用相对路径引入包:

// 这是不好的导入
import “../net”

// 这是正确的做法
import “github.com/repo/proj/src/net”

变量申明

变量名采用驼峰标准,不要使用_来命名变量名,多个变量申明放在一起

var (
Found bool
count int
)

在函数外部申明必须使用var,不要采用:=,容易踩到变量的作用域的问题。
自定义类型的string循环问题

如果自定义的类型定义了String方法,那么在打印的时候会产生隐藏的一些bug

type MyInt int
func (m MyInt) String() string {
return fmt.Sprint(m) //BUG:死循环
}

func(m MyInt) String() string {
return fmt.Sprint(int(m)) //这是安全的,因为我们内部进行了类型转换
}

避免返回命名的参数

如果你的函数很短小,少于10行代码,那么可以使用,不然请直接使用类型,因为如果使用命名变量很
容易引起隐藏的bug

func Foo(a int, b int) (string, ok){

}

当然如果是有多个相同类型的参数返回,那么命名参数可能更清晰:

func (f *Foo) Location() (float64, float64, error)

下面的代码就更清晰了:

// Location returns f's latitude and longitude.
// Negative values mean south and west, respectively.
func (f *Foo) Location() (lat, long float64, err error)

错误处理

错误处理的原则就是不能丢弃任何有返回err的调用,不要采用_丢弃,必须全部处理。接收到错误,要么返回err,要么实在不行就panic,或者使用log记录下来
error 信息

error的信息不要采用大写字母,尽量保持你的错误简短,但是要足够表达你的错误的意思。
长句子打印或者调用,使用参数进行格式化分行

我们在调用fmt.Sprint或者log.Sprint之类的函数时,有时候会遇到很长的句子,我们需要在参数调用处进行多行分割:

下面是错误的方式:

log.Printf(“A long format string: %s %d %d %s”, myStringParameter, len(a),
expected.Size, defrobnicate(“Anotherlongstringparameter”,
expected.Growth.Nanoseconds() /1e6))

应该是如下的方式:

log.Printf(
“A long format string: %s %d %d %s”,
myStringParameter,
len(a),
expected.Size,
defrobnicate(
“Anotherlongstringparameter”,
expected.Growth.Nanoseconds()/1e6,
),

注意闭包的调用

在循环中调用函数或者goroutine方法,一定要采用显示的变量调用,不要再闭包函数里面调用循环的参数

fori:=0;i<limit;i++{
go func(){ DoSomething(i) }() //错误的做法
go func(i int){ DoSomething(i) }(i)//正确的做法
}

http://golang.org/doc/articles/race_detector.html#Race_on_loop_counter
在逻辑处理中禁用panic

在main包中只有当实在不可运行的情况采用panic,例如文件无法打开,数据库无法连接导致程序无法
正常运行,但是对于其他的package对外的接口不能有panic,只能在包内采用。

强烈建议在main包中使用log.Fatal来记录错误,这样就可以由log来结束程序。
注释规范

注释可以帮我们很好的完成文档的工作,写得好的注释可以方便我们以后的维护。详细的如何写注释可以
参考:http://golang.org/doc/effective_go.html#commentary
bug注释

针对代码中出现的bug,可以采用如下教程使用特殊的注释,在godocs可以做到注释高亮:

// BUG(astaxie):This divides by zero.
var i float = 1/0

http://blog.golang.org/2011/03/godoc­documenting­go­code.html
struct规范
struct申明和初始化格式采用多行:

定义如下:

type User struct{
Username string
Email string
}

初始化如下:

u := User{
Username: "astaxie",
Email: "[email protected]",
}

recieved是值类型还是指针类型

到底是采用值类型还是指针类型主要参考如下原则:

func(w Win) Tally(playerPlayer)int //w不会有任何改变
func(w *Win) Tally(playerPlayer)int //w会改变数据

更多的请参考:https://code.google.com/p/go-wiki/wiki/CodeReviewComments#Receiver_Type
带mutex的struct必须是指针receivers

如果你定义的struct中带有mutex,那么你的receivers必须是指针
参考资料

https://code.google.com/p/go-wiki/wiki/CodeReviewComments
http://golang.org/doc/effective_go.html

资源

官网

  • http://golang.org/
  • http://tour.golang.org
  • http://golang.org/doc/

博客

  • http://www.cnblogs.com/zitsing/tag/go/
  • http://www.mikespook.com/learning-go/

书籍

  • go语言编程
  • go web编程
  • go语言学习笔记
  • Effective Go
  • The Go Programming Language

Specification》、go标准库和github上众多开源库

go 学习难点(待整理)

  • http://blog.csdn.net/hittata/article/details/42387297

你想凭着一张现有图片找出它的原始图片,或者是凭着一张小的缩略图找出原始大图吗?

下面的十款搜索引擎可以帮你实现,以图找图,以图搜图,以图片搜索相似的图片。

一:http://tineye.com/

Tineye是典型的以图找图搜索引擎,输入本地硬盘上的图片或者输入图片网址,即可自动帮你搜索相似图片,搜索准确度相对来说还比较令人满意。

TinEye是加拿大Idée公司研发的相似图片搜索引擎,TinEye主要用途有:1、发现图片的来源与相关信息;2、研究追踪图片信息在互联网的传播;3、找到高分辨率版本的图片;4、找到有你照片的网页;5、看看这张图片有哪些不同版本。

二:http://shitu.baidu.com

百度正式上线了其最新的搜索功能——“识图”(shitu.baidu.com)。该功能是百度基于相似图片识别技术,让用户通过上传本地图片或者输入图片的URL地址之后,百度再根据图像特征进行分析,进而从互联网中搜索出与此相似的图片资源及信息内容。但需要注意的是,用户上传本地图片时,图片的文件要小于5M,格式可为JPG、JPEG、GIF、PNG、BMP等图片文件。

三:http://www.gazopa.com/

GazoPa搜索图片时,不依据关键词进行检索,而是通过图片自身的某些特征(例如色彩,形状等信 息)来进行搜索。GazoPa搜索方式有四种:

第一种是传统的通过关键词搜索图片,但在传统图片搜索领域GazoPa与google等搜索引擎无法竞争。

第二种是创新的通过图片搜索图片,但在此领域GazoPa无法与TinEye相竞争。TinEye很容易就能搜索出与原图最接近的一些结果,而GazoPa很多时候的搜索结果则完全无法与原图匹配。

第三种是通过手绘图片搜索图片,这种方式其实没太大用处。GazoPa虽然有这样那样的不足之处,但也算是一个很有独创性的搜索引擎。GazoPa目前还处在内测阶段,想要加入测试的可以在官网上留下你的邮箱地址,收到邀请后你就可以测试使用了。

第四种是通过视频缩略图搜索视频,GazoPa仅凭一张视频缩略图就可找到相关视频。只要有截图,就可以找到截图的视频!

四、http://similar-images.googlelabs.com/

Google实验室的图片搜索:输入一个关键词后,例如“lake”,返回的页面里面点击某个图片的下面的Similar images,运用Google 类似图片搜索功能引擎,即刻为你把类似的图片全部搜索出来,展示给用户以便查看。其准确率、相似率相对比较高。

五、http://www.picitup.com/

Picitup是一个刚开始公测的专业图片搜索引擎,功能非常强大,并支持中文关键字的搜索,是国内图片爱好者的不错选择。Picitup主要支持关键字的搜索,但在它的特色搜索项目——名人匹配搜索(Celebritymatchup)中,你可以通过上传本地照片来进行搜索,不过结果一般让人失望。Picitup可以通过在搜索结果页选择过滤方式来筛选图片,比如可以按颜色、头像(人脸)、风景、产品四种类别来过滤搜索结果。

Picitup最大特点是提供相似图片搜索,即通过关键字找到初始图片,点击初始图片下面的similar pictures按钮,即可搜索与该张图片类似的图片。其实质和Google实验室类似图片搜索是一样的。

六、http://www.tiltomo.com/

Tiltomo是由 Flickr 开发的一个搜索工具,主要用来维护Flickr 自己的图片数据库,其搜索算法主要是基于相似的主题风格或相似的色调和材质。

七、http://cn.bing.com/

Live.com允许你进行一次关键字搜索后再执行相似性的搜索。你可以为Live索引中的任意一张图片寻找相似的图片,但搜索结果看起来并不是很精确。

八、http://www.xcavator.net

Xcavator 和Live.com很相似,你需要先输入一个关键字,然后在搜索结果中挑选一张图片,在根据这张图片的特点来进行搜索。

九、http://www.incogna.com

Incogna的搜索速度非常快,主要是基于色彩和形状上的相似性。

十、http://www.terragalleria.com

Terragalleria主要基于视觉上的相似性,而不考虑图片的内容。

十一、http://labs.ideeinc.com/upload/
Byo image search是根据你上传的图片来搜索相似的图片,算法主要是基于色彩,也包括主题风格。

Node.js is a platform built on Chrome’s JavaScript runtime for easily building fast, scalable network applications. Latest version node.js yum repository is maintaining by its official website. We can add this yum repository to our CentOS/RHEL 7/6/5 Systems and install node.js with few easy commands.

Install latest nodejs
Step 1 – Add Node.js Yum Repository

First we will add node.js yum repository in our system provided by nodejs official website. You also need development tools to build native addons to be installed on your system.

yum install -y gcc-c++ make

curl -sL https://rpm.nodesource.com/setup_6.x | sudo -E bash -

Step 2 – Install Node.js and NPM

After adding yum repository in your system, lets install Nodejs package. NPM will also be installed with node.js. This command will also install many other dependent packages on your system.

yum install nodejs

Step 3 – Check Node.js and NPM Version

After installing node.js verify and check the installed version. You can find more details about current version on node.js official website.

$ node -v

v7.3.0

Also check the version of npm.

$ npm -v

3.10.10

Step 4 – Create Demo Web Server (Optional)

This is an optional step. If you want to test your node.js install. Lets create a web server with “Welcome Node.js” text. Create a file demo_server.js

$ vim demo_server.js

and add following content

var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Welcome Node.js');
}).listen(3001, "127.0.0.1");
console.log('Server running at http://127.0.0.1:3001/');

Now start the web server using below command.

$ node --debug demo_server.js

debugger listening on port 5858
Server running at http://127.0.0.1:3001/

Web server has been started on port 3001. Now access http://127.0.0.1:3001/ url in browser.