分享 Ruby 的爬虫世界

afly · December 03, 2016 · Last by Vucius replied at October 28, 2022 · 24871 hits
Topic has been selected as the excellent topic by the admin.

引子

人人争说大数据,我先做个小爬虫。

哪家工具强?

人肉搜索

先 google,再翻书,github 里探一探,论坛、知乎 Q 群走一遭

结论:python 风头劲,ruby 少人问。

不服!

http client

要想爬,先上路。

ruby 社区里的 http 牌老司机可真不少,DSL 手法个个好,用了就别想跑

总的来讲,这些库封装了 http 协议的诸多功能,诸如:form parameters, file uploads and custom body entities、gzip、Basic Authentication natively、timeout、redirect、cache etc.

可惜 http client 生来只认 http,不识 html。多用于做 API 的客户端,或者 json 爬虫,譬如:

WEB crawl

不识 html? 不要紧,老司机给你造。

nokogiri 神器在手,百万网页任你爬,不但如此,你还可以在锯子上玩各种花式爬:

开着 http client 上了路,拿出锯子滤信息,美女照片哗哗哗...停!我要和美女打个招呼

web interact automation

要想和美女互动,form 这个码头必须拜

Mechanize automatically stores and sends cookies, follows redirects, and can follow links and submit forms

信息已发送,美女不回复...why?

你可真是老司机,现在是啥年代,开一辆上世纪的老奔驰(服务端渲染)就想泡到妞?现在车上不装个 js 平板(客户端渲染),你也好意思上路?

Web Browser Automation

javascript 是个棘手的问题,因为它不是 html 这类文本(常),而是代码(变)。然而爬虫只吃文本,所以必须先要想法将代码执行,变成文本。好比,你要吃包子,你妈拿给你一包面粉,一块肉,一个菜谱,一口锅,来,自己造。

selenium 1

http://www.seleniumhq.org/

类似的困难在 WEB 界面自动化测试中也存在,selenium 是解决这类问题的一个 test suit,其原理是:"当浏览器启动时,向其中注入 javascript,从而使用这些 js 来驱动浏览器中的 AUT(Application Under Test)..." 嗯,听起来好复杂,而且还要安装一个真实的浏览器! (实质上,就是 selenium 为浏览器提供一个特别扩展或插件,从而允许 selenium 的测试脚本可以对浏览器的内部对象进行操纵)

phantomjs

http://phantomjs.org

除了测试场景,近年来兴起的 spa 应用同样面临这类问题,即 google 等搜索引擎无法收录这类客户端渲染网页。咋办,有老司机提出:开发一个 headless browser,当 google 等来访问时,就将请求重定向给它,由其生成静态页面后,再返还给 google.

headless browser,所谓无头浏览器,就是不要脸:)。就是网页的渲染只在内存中进行,而并不输出到输出设备,譬如屏幕(所以你可以按需换头,譬如输出为 html 文件,屏幕截图等等)。

phantomjs 就是这样一个专供程序员使用的不要脸浏览器,其实质上是基于 WebKit 引擎的一组 JavaScript API 封装,从而方便程序员们去程序化操纵浏览器中的各类对象

web driver

以上的解决方案都是典型的太监方案。不过太监热情太高,终于能感动皇帝。

假如能通过调用浏览器原生 API 以直接驱动浏览器,岂非更好!

WebDriver 正是这样一个项目:它通过原生浏览器支持以直接控制和操纵浏览器,并且可利用操作系统级的调用模拟用户输入。重要的是,它获得了来自浏览器厂商的原生支持(WebDriver 提供 FirefoxDriver、InternetExplorerDriver、OperaDriver、ChromeDriver 等以及 AndroidDriver、IPhoneDriver 等移动应用测试)。

实质上,WebDriver 更类似于一个浏览器无关性 API 集(类似于 ODBC 或 DOM),也不与任何测试框架进行绑定,事实上今天它已成长为一项 w3c 标准 https://w3c.github.io/webdriver/webdriver-spec.html

selenium 2 (web driver)

终于,Selenium 和 WebDriver 两个项目合并了,即 Selenium 2,它既支持 Selenium API,又支持 WebDriver API,集 api、工具、环境于一体。 Selenium 本身虽然是 java 编写,但它提供各种语言绑定,譬如 Selenium-WebDrive for ruby

换句话,老司机们不用换车,也能使用 ruby + selenium2 搞定使用 js 客户端渲染的网页了。

然而,这还不够。

watir

http://watir.github.io/

watir 是和 selenium 类似的工具,它早期使用 IE-only implementation(本质上是一个封装了 MS COM(Component Object Model) 接口的 Ruby 类库,IE 的 COM 接口允许程序访问 IE 浏览器的文档对象模型等)。 随着 WebDriver 的兴起,出现了 Watir-WebDriver 项目,是完全基于 Ruby 语言开发的 WebDriver API 封装(不是 Selenium-WebDrive for ruby binds),最终,2016 年 8 月 Watir 和 Watir-WebDriver 两项目彻底合并,形成了足以对抗 selenium 的另一个完整生态平台。

why watir?去看看 watir 的示例...

老司机最爱 ruby,车慢不要紧,驾车姿势要酷炫!

capybara

https://github.com/teamcapybara/capybara

最后,capybara,一个用户接受度测试框架(Acceptance test framework),同样使用 ruby 开发,rails 应用界面测试的标配,同样必须支持 browser automation。当前它支持如下后台实现:

  • rack::test: 缺省,不支持 js
  • capybara-webkit: 使用 QtWebKit 引擎 (类似于 python 社区的 splash),支持 js,但因为并未整个装入浏览器,故速度显著快过 selenium,然而兼容性方面则不如 webdriver
  • Poltergeist (PhantomJS) 相比于 capybara-webkit,no qt ,no X server
  • selenium-webdriver: 完整的浏览器支持,当然速度....

pincers

提一下这个,似乎也不错,支持 jquery query interface :)

小结

绕了一大圈,我的小爬虫在哪呢?

等我定一个小目标先

附录

烂尾起高楼,待续...

爬虫没有窝正常,居然没有大数据节点!😬

还有并发控制,验证码识别😁

http://productchaseapp.herokuapp.com/ 的爬虫就是 HTTParty + Nokogiri 写的

主要是当时只会 Ruby....

huacnlee mark as excellent topic. 03 Dec 20:31
huacnlee in 如何在爬虫中运行网页中的 JavaScript mention this topic. 03 Dec 20:32

@shiny 小爬虫还没长大,并发控制之类,等等等等... 验证码识别,好大的坑,有没有开放的云服务?付费的也行😑

以前用 watir 做自动化发帖时,也要涉及到验证码识别,写了个对接打验证码平台的 gem, 也就是对接人肉打码的,比机器识别靠谱,https://github.com/seaify/confirmation_code

https://github.com/httprb/http 用过这个写爬虫,遇到两个问题:

  • 貌似没有日志,RestClientFaraday 都有日志功能,可以把实际发送的请求写到日志中,可以检查请求的格式、参数是否正确。
  • 貌似不能自动处理压缩过的响应,比如这个地址 http://www.bilibili.com/index/index-icon.json 返回的就是 gzip 压缩过的响应。最后还是用 net/http 解决的。

不知道有没有遇到类似问题的同学,欢迎分享解决方案。

#6 楼 @afly 验证码识别主要分两类。一类是程序自动识别,一类是召唤人肉云 😁

简单的验证码可以用 tesseract 来 OCR 就可以了。复杂点的需要自己针对专门的验证码做识别算法。另外不知道百度 OCR 之类的云服务咋样,没试过。

人肉的搜「云打码」有好多类似平台。

一直想做一个网站数据爬虫,减去每天手动更新的困扰,这一下突然仿佛所有的秘籍和套路一下摆在面前,真是太幸福感了

#11 楼 @small_fish__ mechanize 遇到纯 js 页面就再见了,而且很多平台现在的反爬技术很强,当你打开页面没有访问页面里的静态资源 没有 js 计算出来的密钥放到 cookie 里的时候 直接判定你是爬虫弹窗输入验证码 不停弹

我来补充一个感觉挺有用的库 parallel

对于代码的并发执行进行封装,可以选择开多个进程 (充分利用多核),多个线程 (可以加速阻塞 IO 多的代码执行), 还能结合 ruby-progressbar 显示预计运行的时间。

# Doing stuff | ETA: 00:00:02 | ====================               | Time: 00:00:10

前几天收集数据需要发 20000 个 HTTP 请求,直接把代码用 parallel 包装一下,结果数据直接交给 ActiveRecord 存数据库,不用考虑并发的各种通信和锁的问题,执行速度粗略估计是顺序执行阻塞的操作的十倍。(代码连 require 不到 20 行)。

虽然 Ruby 性能相比较其它语言差一点,但是大部分应用代码瓶颈还是 IO,CPU 很少满载,合适的并发执行带来的效率提升是惊人的。

做爬虫 Python 相关的库更加丰富,但是对于简单的数据爬取,parallel + Nokogiri,加上 Ruby 语言,简直不能更棒。

可以试一下爬亚马逊商品的价格

python真的好玩吗 

LS 说的都玩过,公司其中一个业务就要用到爬虫,自己的个人项目不少也要用到爬虫。遇到的问题有:动态加载 (分析 JS 代码、Selenium2 大杀器)、IP 限制 (挂各种代理 [免费收费]、甚至树莓派控制 ADSL 路由重启获取动态 IP...)、用户登录 (网页的/ APP API 加密破解),语言用过 Python/Ruby/Nodejs。现在一些简单网页解析爬虫就用 js 写因为可以很快 (cheerio jquery like),复杂一些要做任务调度的就 Python 或 Ruby,团队里也有大牛用 Elixir,膜拜膜拜

验证码的问题,思考了一下,估计可归结为如下三方面:

  1. 静态验证:典型代表即图片验证码。缺陷是,验证码是由算法生成且必须局限于能被人类识别的边界(字母 + 数字),因此,机器自然可以从人类的识别模式出发,再辅之以足够多的样本进行比对和学习,只要计算力足够强大,就能轻松破解。故对图片验证码的反破解思路之一即剔除模式以加大计算边界,譬如 12306 式的看图选择 或者 问答题式的验证。

  2. 动态验证:但对于云打码这类平台,再复杂的看图答题也无济于是。问题出在验证码是以静态的图片、文字或录音等方式存在的,爬虫可以轻松的把它们传送至高效率的人工平台(也许那里有什么超级神器也不定)获得破解结果。基于此,反破解的思路就是将验证过程动态化,譬如 https://world.taobao.com/markets/all/sea/register ,必须要求先做一个手势动作,然后才可获取验证码图片。这是欺负爬虫无法模拟这一动作或事件吗?嗯,这个有待研究...

  3. 物理验证:以上验证变来变去,终究是内存里的战斗。最简单的反爬方式就是引入一个外部物理设备做验证,譬如短信验证,手机扫码,然而据说手机机器人集群也已产业化,无非多养几个手机号,这个,谁来详细爆个料😍 ...

我想,未来,一律实名注册,集中认证,虹膜扫脸,大约可灭此爬虫矣

python 的 scrapy 已经很成熟,且经过无数验证,上手还快

关于并发、并行、分布式等可扩展性问题,其实更多是爬虫之外:

  1. 并发:IO 与 cpu 的同步问题,@oa414 提供了一个不错的库 parallel,够用
  2. 并行:这个涉及到具体的任务分解,但爬虫一般只涉及数据抓取,独立性强,似乎问题不大
  3. 分布式:多台机器之间的调度与管理,不知有没有从 chief puppet 等网管项目中抽取出来的框架,可以即插即用。不过据说 ansible 项目可以无 agent 部署,又是 python 占了上风😾

@reducm "IP 限制 (挂各种代理 [免费收费]" 这个,可否详细的讲一讲

@ghjcumt2008 scrapy is awesome!

@afly IP 限制,比较常见是一段时间内同一 IP 访问次数限制,另外有些资源还会有一些更复杂的登录令牌与 IP 绑定的限制,这个与资源方的风险防范机制有关。理论上,爬虫越能模拟到真实用户行为,越难防范,落实到爬虫的实现,就是各种细节上的调节。如你所说大量的手机号是有必要的,我们的其中一个项目就是开了一堆手机号和买了一堆低配红米,做到了控制短信,还有更新登录信息到服务器,还有在 Android 利用辅助权限上做一些模拟行为操作😅 。另外代理的话就比较好理解了,做成一个代理 IP 池,一个 IP 被封了另一个 IP 再上,本质就是需要很多可用的 IP 代理。免费的话可以爬各大代理网站提供的免费代理:

  1. http://www.xicidaili.com/
  2. http://ip.izmoney.com/
  3. http://www.kuaidaili.com/
  4. http://www.proxy360.cn/
  5. http://www.goubanjia.com/

这里有个好玩的就是他们也有一定的防范机制,鸡生蛋生鸡😂 ,比较奇葩的是 goubanjia 进去是等一会儿才会变出真正的端口...

第二种方法就是购买他们的收费代理。有了一堆 IP 后,我们的做法是搭一个专门的小服务,小服务会提供接口,把代理 IP 拿去 test target,另外也有接口返回一堆可用的 IP。

当然了,如果还是感觉代理质量不太好的话(延迟、大量不可用),土豪的话可以买一堆低配的云 IP 服务器,可以找些切换 IP 比较快的服务(阿里云好像有)。最后我们还想了个方案,就是把家里空余的宽带资源也可以提供出来,用树莓派做个远程控制,IP 被封了就重新上线获取新的 IP,不过这个方案还没用到(上面两个已经够用了)...

还没有测试过性能方面?

使用 restClient+nokogiri+watir+phantomjs ,ruby 多线程顺畅写爬虫 (不需验证码的).😎

任务管理简单点可以用 sidekiq,worker 放在 docker 里面,集群部署不是啥问题~

nightmare (electron) 前来报到

其实简单的数据爬取火车头,集搜客,神箭手,造数 (不是打广告) 之类的第三方平台就可以解决了,不仅用很少的代码或者不写代码就能实现,而且很快就能得到想要的数据,看最近的一些爬虫热潮,有些很简单的根本用不着代码,还非要自己写,而且费时间,有其它平台为什么不使用?怪象,至于大规模的数据爬取需求,分布式,并行……有多少用到的人。先考虑规模再看实现方式。

Reply to YingJie

其实我也想用你上面提到的第三方平台,但是我没找到我需要的,我是想爬中国亚马逊电子书的价格信息

cym2015 in 用 Ruby 写一个没有什么用的爬虫 mention this topic. 07 Jan 17:36
ice_col in Kimurai - 一个 Ruby 写的爬虫框架 mention this topic. 20 Aug 16:22
30 Floor has deleted

救命,你真的是个被代码耽误的段子手

期待 puppeteer-ruby 的表现

You need to Sign in before reply, if you don't have an account, please Sign up first.