第一步先安装elasticsearch,因为爬虫数据量特别大,如果靠着我们手动刷新进入文件无疑非常耗费时间,所以数据用来存储在elasticsearch上面,有这么几点好处
天然支持分布式高并发,随时分布式p2p扩容
全文索引查询毫秒级别
在线统计分析引擎可以动态在线处理数据
这里我就用docker来进行安装elasticsearch了
# 最好加上版本号 不然可能会报错
docker run -d -p 9200:9200 elasticsearch:5.6.9
# 然后查看启动状态
docker ps
看到容器启动成功后就可以通过localhost:9200访问了~
对于爬虫呢 ,其实没那么高大尚 ,我们在浏览器输入一个url,然后就进入我们想要的页面,从http层面来看,我们发起一个request请求后,会有一个response响应,而我们需要的信息都在response body里面,爬虫就是把response body的数据经过正则的筛选然后拿到而已。
先看看一个入门的案例~
func zhai() {
resp, err := http.Get("https://www.zhenai.com/n/message?from=myzhenai")
if err != nil {
panic(err)
}
defer resp.Body.Close()
//utf8Reader := transform.NewReader(resp.Body, simplifiedchinese.GBK.NewDecoder())
if resp.StatusCode == http.StatusOK {
all, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)
}
bytes := printWomen(all)
for _, m := range bytes {
for _, subMatch := range m {
fmt.Printf("%s ", string(subMatch))
}
fmt.Println()
}
fmt.Println("找到 :", len(bytes))
}
}
// 正则解析器
func printWomen(contents []byte) [][][]byte {
re := regexp.MustCompile(`<a target="_blank" href="//(www.zhenai.com/zhenghun/[0-9a-zA-Z]+)".[^>]*>([^<]+)</a> `)
matches := re.FindAllSubmatch(contents, -1)
return matches
}
func main() {
zhai()
}
这就是我们所爬取的信息~ 当然这是通过正则来达到的效果,正则表达式可以自己简单了解下,很简单的~
网站一般都会有反爬机制,像上面这个网站没有,但如果把网址换成豆瓣,大家就可以看到返回的状态吗是418了(俗称茶壶状态码~),不过这种反爬只是通过UA(User-Agent)来验证是否是浏览器访问还是代码访问而已,咱们弄个简单的UA伪装就行。
看上图控制台,那就是UA身份了,浏览器f12打开控制台找到Network的Request Headers就可以看到我们自己的UA了,然后写进代码就行了
这儿就是设置了UA伪装,这个时候就可以正常爬豆瓣了!
单机版爬虫流程图
下面上代码
// 启动函数 main方法
func main() {
engine.Run(engine.Request{
Url: "https://book.douban.com/",
ParseFunc: parse.ParseContent,
})
}
// engine包的type类
type Request struct {
Url string
ParseFunc func([]byte) ParseResult //该函数用于参数解析 正则
}
type ParseResult struct {
Requests []Request
Items []interface{}
}
func NilParse([]byte) ParseResult {
return ParseResult{}
}
// engine包的engine类
func Run(seeds ...Request) {
var requests []Request
for _, e := range seeds {
requests = append(requests, e)
}
for len(requests) > 0 {
r := requests[0]
requests = requests[1:]
log.Printf("fetching url: %s", r.Url)
body, err := fetcher.Fetch(r.Url)
if err != nil {
log.Printf("Fetch Error: %s", r.Url)
continue
}
parseResult := r.ParseFunc(body)
requests = append(requests, parseResult.Requests...)
for _, item := range parseResult.Items {
fmt.Printf("got item: %s\n", item)
}
}
}
// fetcher包的fetch类
func Fetch(url string) ([]byte, error) {
client := &http.Client{}
req, err := http.NewRequest("GET", url, nil)
req.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36")
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
fmt.Printf("Error status code :%d", resp.StatusCode)
}
result, err := ioutil.ReadAll(resp.Body)
return result, err
}
// 正则解析标签 parse包下的parseTag类
const regexpStr = `<a href="([^"]+)" class="tag">([^"]+)</a>`
func ParseContent(content []byte) engine.ParseResult{
res := regexp.MustCompile(regexpStr)
matches := res.FindAllSubmatch(content, -1)
result := engine.ParseResult{}
for _, m := range matches {
result.Items = append(result.Items, m[2])
result.Requests = append(result.Requests, engine.Request{
Url: "https://book.douban.com/" + string(m[1]),
ParseFunc: engine.NilParse,
})
}
return result
}
这就是一个简单的爬虫了,几乎可以访问目前所有的网站了
类似淘宝这种大型网站其反爬机制肯定很难,但只要可以访问,就一定可以爬,做好UA伪装、cookie认证、代理ip、token认证等一堆机制,也不是爬不了,当然爬到的内容都是咱们可以看到的,比如密码这种东西,就不是爬虫可以爬到的了,所以爬虫也不是万能的~
这是爬淘宝页面的数据,并不是程序错误,只是每个人的token都不一样,所以有些需要登陆才能访问的页面就会报错404,带上自己的token就好了~