百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

GO语言版爬虫神器pholcus推荐(go爬虫和python爬虫)

ccwgpt 2024-10-04 13:58 27 浏览 0 评论

前言

爬虫(web crawler),wiki百科给的解析是自动浏览万维网的网络机器人,像Google和百度的搜索引擎。爬虫,不仅仅在于机器自动,更关注信息的检索和收集。万维网,是一个庞大的资料库,所以爬虫一直都是热门话题,备受关注,很多程序员或者学习,都会拿这个练手。我们都知道,爬虫知识第一步,更重要的后面的数据运用。前段时间,马蜂窝的机器评论新闻也闹得挺热闹的。但这一步,也不好走,很多网站有反爬机制,如何骗过对方,也挺费劲的。

关于反爬策略

1. 检测http header中user-agent/referer;

2. 检测cookie,多次访问cookie set次数;

3. 单个IP单位时间内访问次数控制,超过阈值,返回max requests;

4. 验证码;

5. 动态页面,关键数据(如验证码)用ajax请求,甚至加密;

6. 机器行为学习分析;

对于第三点,误伤大,很多公司都不舍得用,除非有很好的算法策略,而且意义不大,现在都找代理买IP分布式爬;

第四,ocr一下,分析些验证码,大学的时候,简单玩过下。现在的验证码多种多样的,比如电话语音验证码,还是挺烦的;

第五点,到现在其实根本不用介意,爬虫会使用phantomjs/selenium模拟浏览器,因为使用一般httpclient肯定被反爬。

最后一点,通过机器分析你的行为,成本高。

框架

目前网上有很多介绍[scrapy](https://doc.scrapy.org/en/latest/intro/overview.html)和[pyspider](http://docs.pyspider.org/en/latest/Quickstart/)的,而且官网有很详细的介绍,之前用scrapy主要写spider和item,用起来挺顺手的,这里就不累述了。那时候python还是2.7, 真正多线程还得用gevent实现,而且对中文很不友好。题外话,程序员要更好地学习什么技术时,最好看官网doc,并仔细研究源码,学习起来才能事半功倍。

本文要介绍的是,另一个分布式爬虫框架pholcus([git传送](https://github.com/henrylee2cn/pholcus.git))。整个框架使用golang写的,源码写的很仔细,很赏心悦目,大家可以研究下。程序员之间交流,show code。看源码真会有惊喜,比如hashmap hashcode中的移位一样(当然JDK里面的源码都是大神精心布置和benchmark的)。同时,作为golang初学者,真心推荐下golang,对比C#、java、pyhon、perl、js, golang个性突出,使用简单。它没有继承、没有泛型、没有析构函数等,

不要求显式初始化和隐式构造。它提供基于CSP并行的轻量级线程goroutine, 可以很轻松实现高并发。平时工作,用Java比较多,当你切换到golang模式,有channel,有lock,有goroutine,而你只需关心struct和interface,最后build生成可执行文件, 很省心。

pholcus,基本可以拿来即用,你只需写好spider放到pholcus_lib下,并注册即可,具体操作指引请看作者doc。而且,你可以一台单机可以随便起几万协程跑数据,当然并不是协程数越高跑的越快。

新增selenium下载器

pholcus有两个下载器,surf和phantomjs(phantomjs已停止更新),用起来发现phantomjs还是有很多请求被反爬。所以,在GitHub找了个[chromedp](https://github.com/chromedp/chromedp)还能用,不过它还是用打开Chrome,很多费劲。而且作者也说了该版本还有待完善,并且很快出来新版本,我们就期待下吧。如果你要使用chromedp, 你可以参考以下代码

 ctx,cancelF := context.WithCancel(context.Background())
cdp,err := chromedp.New(ctx)
if err != nil {
 log.Printf("[E] chromedp init error: %v",err)
}
self.Cdp = cdp
self.ctx = &ctx
self.cacel = cancelF
self.initial = true

记得自己get

> go get -u github.com/chromedp/chromedp

最后采用webdriver,自己新增了个selenium downloader,效果挺好,爆破力极强,[源码传送](https://github.com/onebite/pholcus/blob/master/app/downloader/surfer/sel.go),

具体可以参考如下:

package surfer
import (
 "github.com/tebeka/selenium"
 "net/http"
 "net"
 "sync"
 "os"
 ch "github.com/tebeka/selenium/chrome"
 "fmt"
 "time"
 "strings"
 "io/ioutil"
 "github.com/henrylee2cn/pholcus/config"
 "github.com/henrylee2cn/pholcus/logs"
)
/** problems:
1、 运行久了,会报一下错误,说chromedriver no long running
 The process started from chrome location /opt/google/chrome/google-chrome is no longer running, so ChromeDriver is assuming that Chrome has crashed
 解决:如果你自定义路径下的exe, 需设置Chromedriver.exe路径参数,chrome默认启用的是local setttings里的chromedriver.exe
 */
type Sel struct {
 Service *selenium.Service
 caps selenium.Capabilities
 saveScript string
 port int
 host string
 initial bool
 maxReq chan int //最大请求数,过大会崩溃
 sessionGroup sync.WaitGroup
}
var ms sync.Mutex
func NewSel() Surfer{
 s := &Sel{
 initial: false,
 maxReq: make(chan int, 8),
 }
 return s
}
func (self *Sel)initIE(){
 if self.initial {
 return
 }
 ms.Lock()
 defer ms.Unlock()
 port,_ := pickUnusedPort()
 opts := []selenium.ServiceOption{
 selenium.Output(os.Stderr),
 }
 selenium.SetDebug(false)
 service, err := selenium.NewIEDriverService(config.IEDRIVER,port,opts...)
 if err != nil {
 panic(err)
 }
 caps := selenium.Capabilities{"browserName":"internet explorer"}
 chromeCaps := ch.Capabilities{
 Path: config.IEDRIVER,
 }
 caps.AddChrome(chromeCaps)
 self.Service = service
 self.caps = caps
 self.port = port
 self.host = fmt.Sprintf("http://localhost:%d/wd/hub",port)
 self.saveScript = ""
}
func pickUnusedPort() (int, error){
 addr, err := net.ResolveTCPAddr("tcp","127.0.0.1:0")
 if err != nil {
 return 0,nil
 }
 l,err := net.ListenTCP("tcp",addr)
 if err != nil {
 return 0,err
 }
 port := l.Addr().(*net.TCPAddr).Port
 if err := l.Close(); err != nil {
 return 0,err
 }
 return port, nil
}
func (self *Sel) getRemote2() (selenium.WebDriver,error) {
 mutex.Lock()
 defer mutex.Unlock()
 if self.initial {
 wb, err := selenium.NewRemote(self.caps,self.host)
 if err == nil {
 return wb,nil
 }
 }
 if self.initial && self.Service != nil {
 self.initial = false
 self.sessionGroup.Wait()
 self.Service.Stop()
 }
 port,_ := pickUnusedPort()
 opts := []selenium.ServiceOption{
 selenium.Output(os.Stderr),
 }
 selenium.SetDebug(false)
 service, err := selenium.NewChromeDriverService(config.CHROMEDRIVER,port,opts...)
 if err != nil {
 logs.Log.Critical("[WebDriver Error] start on port:%d %v",port,err)
 self.initial = false
 return nil,err
 }
 logs.Log.Critical("[WebDriver] start on port:%d",port)
 caps := selenium.Capabilities{"browserName":"chrome"}
 chromeCaps := ch.Capabilities{
 Args: []string{
 "--headless",
 "--start-maximized",
 "--no-sandbox",
 "--user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36",
 "--disable-gpu",
 "--disable-impl-side-painting",
 "--disable-gpu-sandbox",
 "--disable-accelerated-2d-canvas",
 "--disable-extensions",
 "--disable-accelerated-jpeg-decoding",
 "--test-type=ui",
 },
 Prefs: map[string]interface{} {
 "browser.download.dir": config.FILE_DIR,
 "download.default_directory": config.FILE_DIR,
 "download.prompt_for_download": false,
 "download.directory_upgrade": true,
 "safebrowsing.enabled": true,
 },
 }
 caps.AddChrome(chromeCaps)
 self.Service = service
 self.caps = caps
 self.port = port
 self.host = fmt.Sprintf("http://localhost:%d/wd/hub",port)
 self.saveScript = ""
 self.initial = true
 return selenium.NewRemote(self.caps,self.host)
}
func (self *Sel) getRemote() (selenium.WebDriver,error){
 //here no need to lock
 if self.initial {
 wb, err := selenium.NewRemote(self.caps,self.host)
 if err == nil {
 return wb,nil
 }
 }
 return self.getRemote2()
}
func (self *Sel) freeOne() {
 <- self.maxReq
}
func (self *Sel) Download(req Request) (resp *http.Response,err error) {
 self.maxReq <- 1
 defer self.freeOne()
 param, err := NewParam(req)
 if err != nil {
 return nil, err
 }
 resp = param.writeback(resp)
 resp.Request.URL = param.url
 self.sessionGroup.Add(1)
 defer self.sessionGroup.Done()
 for i := 0; i < param.tryTimes; i++ {
 if i != 0 {
 time.Sleep(param.retryPause)
 }
 html, err := self.GetPageSource(req)
 if err != nil {
 continue
 }
 resp.StatusCode = http.StatusOK
 resp.Status = http.StatusText(http.StatusOK)
 resp.Body = ioutil.NopCloser(strings.NewReader(html))
 break
 }
 if err != nil {
 resp.StatusCode = http.StatusBadGateway
 resp.Status = err.Error()
 }
 return
}
func (self *Sel) GetPageSource(req Request) (string,error) {
 //session create here not outside as time.sleep make session easy timeout
 wd, err := self.getRemote()
 if err != nil {
 //wait some time
 time.Sleep(10*time.Second)
 wd, err = self.getRemote()
 if err != nil {
 logs.Log.Informational("[Crash]WebDriver crash: %v",err)
 return "", err
 }
 }
 if wd != nil {
 defer wd.Close()
 }
 if req.GetCookieKV() != nil && len(req.GetCookieKV()) > 0 {
 //不能给_blank set cookies,即domain为空时不能set cookies
 //We don't support adding cookies to "about:blank". You need to be on the actual domain
 //you want to add the cookie to.
 wd.Get(req.GetUrl())
 for key,v := range req.GetCookieKV() {
 coo := &selenium.Cookie{
 Name: key,
 Value: v,
 }
 err := wd.AddCookie(coo)
 if err != nil {
 logs.Log.Informational("errrrrrrrrrrrrrrrrr %v %v %v ",key,v,err)
 }
 }
 }
 err = wd.Get(req.GetUrl())
 if err != nil {
 return "", err
 }
 wd.ExecuteScript(" window.scrollTo(0, 999999999);",[]interface{}{})
 html, err := wd.PageSource()
 return html, err
}

贴一下,chromedriver.exe支持的[webdriver命令]

相关推荐

火电厂智能管控新基建:全场景人员定位系统架构解析

在能源生产领域,火电厂以庞大的厂区规模、复杂的作业环境和密集的人机交互著称。从高温高压的锅炉房到精密复杂的电气设备间,从露天煤场到灰渣处理区,传统管理模式下的人员定位盲区,正成为制约安全生产与高效运营...

安全仪表系统(SIS)全生命周期管理:从设计到运维的深度解析

以下是一篇关于安全仪表系统(SIS)的技术解析与实践方法,涵盖系统架构、设计标准、实施流程及行业应用。安全仪表系统(SIS)是工业过程安全的最后一道防线,通过独立于基础控制系统的硬件和逻辑,在工艺失控...

数字化转型架构下的数据安全治理方案

这份PPT文件内容围绕数字化转型架构下的数据安全治理方案展开,主要探讨了数据质量治理、安全治理、全生命周期治理以及治理考核等方面的内容。更多参考及文档获取详见公众号:优享智库数据治理概述定义与目标:数...

安全完整性等级(SIL)分析报告编制与认证实践方法

以下是一篇关于安全完整性等级(SIL)分析报告的文章,涵盖SIL定级方法、验证流程、计算模型及工程实践。安全完整性等级(SIL)是量化安全仪表系统(SIS)性能的核心指标,由IEC61508/615...

项目管理体系框架(项目的管理体系)

Pokemon go下载教程 口袋妖怪Go下载解锁方法

#p#安卓下载#e#Pokemongo怎么下载?口袋妖怪go下载教程讲解。虽然锁区了但是大家还是有办法的,首先是口袋妖怪Go下载问题,很多口袋妖怪go的安卓玩家不知道怎么下载游戏,小编给大家详细解答...

抛弃Windows吧!谷歌推免费Chrome系统,一个U盘就搞定

在目前的个人电脑上,最主流的系统当然是Windows,不过除了Windows之外,我们也可以选择购买苹果的电脑,使用苹果的MacOS系统。不过除了苹果和微软的系统之外,实际上谷歌也有自己用于个人电脑...

谷歌误发ARM版Chrome安装包,致英特尔 /AMD用户无法安装

IT之家3月26日消息,科技媒体WindowsLatest昨日(3月25日)发布博文,报道称由于谷歌误发适用于ARM架构的安装包,导致用户从谷歌官网下载的ChromeSetu...

【Google Gemini极简教程】使用Flask和Gemini API构建一个AI BaaS

BaaS(BackendasaService,后端即服务)BaaS是一种云服务模型,它为开发者提供了一种便捷的方式来构建和管理应用程序的后端服务。BaaS提供了一系列的后端功能,如数据库管理...

第一资讯Windows 10 Mobile已成功安装谷歌Play Store

虽然微软并未正式推出WP可安装APK的功能,但近期有不少玩机爱好者已经在Windows10Mobile平台上用上了Android应用,而且随后还在需要谷歌服务框架(GoogleServices)...

宝可梦TCG Pocket谷歌账号登录,给你提供指南

《宝可梦TCGPocket》作为一款备受欢迎的卡牌对战游戏,为了给玩家提供更加便捷和安全的登录方式,支持使用谷歌账号进行登录。通过谷歌账号登录,您不仅可以快速进入游戏,还能享受账号数据同步、跨设备游...

秒变万能家庭服务器!斐讯N1 armbian安装指南

一直以来,我都想配置一台小型服务器放在家里玩一玩,但是x86架构的主机体积大功耗高,价格也不低。而树莓派的话,价格便宜一点,性能对于轻度使用也基本够用。可是树莓派仍然要两三百块钱,感觉还是有点贵。于是...

如何自己开发一个Google浏览器插件?

相信很多人都好奇,谷歌浏览器那么多的插件是如何开发的,我们如何开发一个自定义的Google浏览器插件,下面我们就来详细的给出一个开发Google浏览器插件的流程。准备环境首先需要有一个文本编辑器工具如...

我的世界手机版谷歌商店安装教程(我的世界谷歌下载)

在我的世界手机版升级到0.11.0版本后,很多玩家发现正式版需要有谷歌商店的验证也就是必须安装Googleplay才能玩。这次搞趣网小编就为大家带来我的世界手机版谷歌商店安装教程。有些手机自带Goo...

部落冲突安卓版谷歌怎么绑定 有无root都可以

部落冲突安卓版谷歌怎么绑定?下面小编为大家带来部落冲突安卓版谷歌绑定攻略详解,希望这篇攻略详解能够对大家有所帮助。首先准备这些东西(必须在网上自己下载,不要相信google应用)还需要下载"谷歌服务框...

取消回复欢迎 发表评论: