zoukankan      html  css  js  c++  java
  • 爬虫总结_java

    基于webmagic的爬虫项目经验小结

    大概在1个月前,利用webmagic做了一个爬虫项目,下面是该项目的一些个人心得,贴在这里备份:

    一、为什么选择webmagic?

    说实话,开源的爬虫框架已经很多了,有各种语言(比如:python、java)实现的,有单机的,还有大型分布式的,多达上百种,详情可见:

    http://www.oschina.net/project/tag/64/spider?lang=0&os=0&sort=view&

    github上随手搜索一下spider之类的关键字,也不计其数,如何选择呢?

    我的标准其实很简单:

    a) 要有一定量的使用群体(即:用的人越多越好),有人实际在用的项目,才会有生命力

    b) 文档要全(没有文档或文档不全的项目,学起来太费劲)

    c) 使用起来要简单,越傻瓜越好(否则,如果要先安装这,安装那,弄一堆依赖的东西,太花时间了)

    d) 爬虫的主要功能要有,比如:支持多线程,url自动去重复,html解析方便(至少要能支持css选择器,xpath选择器,正则表达式等常见的解析方式

    e) 架构不要太庞大,越轻巧越好,简单的设计,意味着扩展起来比较容易,有些功能如果要自行扩展,直接继承一个类就完事了

    把这些因素考虑进去后,综合下来,选择了webmagic,作者很用心,有一个很完整的教科书式的在线文档:http://webmagic.io/docs/zh/ 基本上花半天时间看完,就明白爬虫是怎么回事了。

    目标网站的内容变了,如何设计自 己的更新爬取策略,这也是要认真考虑的。

    通常最终保存内容的db小型项目中只会有一个,尽管爬虫支持多线程并发爬取,可以分布式的高效狂爬,但是db是一个慢速的IO瓶颈,如果把 "爬取->解析->入库"全放在一个模块中按顺序同步处理,最后的结果相当于前面有几个水管收集水源,但是最后进入水库的总管道不给力,整体 的蓄水效率还是很慢。

    分开之后,爬取模块可以同时部署多个,然后将得到的html集中存储在1个目录下,再按子目录存储(比如:一个大型网站,会有很多分站,可以实例A 爬上海站,实例B爬北京站...),这样可以尽可能快的把内容先捞回来。然后由解析模块,再到这个目录下将文件取出来慢慢解析入库,解析成功后将原始文件 删除(或移到其它目录备份,这个看情况而定),如果代码有问题,比如解析规则有bug,导致某些页面解析失败,因为原始html文件已经在本机存储,修正 解析的bug后,可以再试重新解析失败的文件,而不需要重新爬取。

    至于爬取模块完成后,如何通知解析模块去开始解析入库,有很多办法,比如消息队列,zookeeper订阅节点状态变化,或者在某个目录下放置一个标记文件 之类的都可以。

    三、如何更有效的更新爬取

    通常爬取时,会先从一个所谓的"种子URL"层层引导,直到发现最终的目标url,首次爬取时,可以将最终页面的url及http的返回码 (404,500,200之类)记录下来,下次更新爬取时,直接重新爬取这些http状态为200的最终页面即可,这样省去了再次从seed页面层层分析 的过程。(当然,这个要看自身项目的特点,如果seed页的内容本身会周期性的变化,那就省不了从seed页重新爬取的过程)

    四、其它一些可能会遇到的问题

    a) xpath的问题

    webmagic提供的xpath解析工具,不支持xpath2.0的一些高级特性,比如:查找父节点之类,解析时可以考虑引入其它一些第三方开源 库,比如dom4j来处理,反正html内容已经保存到硬盘上了,想咋解析都行(但是dom4j也有一个缺点,返回的html必须是严格符合xml规范 的,有些网页的html源代码,标签没有正常结束,会导致dom4j出错)

    b) ajax的问题

    有些数据是通过ajax动态请求得到的,在目标网站上并未以a链接的方式明显给出,这种情况可以根据用一些浏览器的开发者工具,观察最终发出去的 ajax请求,如果ajax请求的url是有规律的,可以直接在webmagic中用类似 page.addTargetRequests("xxx") 的方式手动添加。

    c) post的问题

    webmagic目前的版本,不支持post方式的url爬取,据说以后的版本会考虑,这个暂时可以手动写httpclient来发起post请求,最终拿到数据 

    d)如何对应有防爬机制的网站

    这个没有一劳永逸的办法,具体情况具体分析,

     -- 有些网站会限制url访问的频率(比如:同1个ip1分钟内只能访问某个页面N次),这种需要手动在代码里控制下节奏,比如每次http请求后,加入sleep(5000)之类的,

     -- 有些网站会根据http请求header中的User-Agent来判断是否是同一款浏览器在恶意刷,这种可以在代码中手动弄一个User-Agent列 表,把市面上的所有User-Agent全加进去,每次请求前,随机从列表中取一个User-Agent,这样看起来,貌似有很多不同的浏览器在访问,显 得真实一点。但是有一点要注意,目前很多大型网站都提供了pc版与移动版的页面,如果在pc浏览器上访问,对方会返回pc版的网页,如果用手机访问,会返 回移动版的页面,很多就是根据User-Agent来判断的(因为PC浏览器与手机浏览器对应的User-Agent信息不同),如果你希望每次爬虫访问 的都是PC版的页面,用代码设置User-Agent时,要小心别弄错了。

     -- 有些网站会限制IP,甚至有IP黑名单机制,对于这种出狠招的网站,我们也只能放大招:花点钱,找一群代理服务器,在爬虫代码里,随机切换代理服务器。

     
     

    Selenium是一款自动化测试工具。它能实现操纵浏览器,包括字符填充、鼠标点击、获取元素、页面切换等一系列操作。总之,凡是浏览器能做的事,Selenium都能够做到。

    这里列出在给定城市列表后,使用selenium来动态抓取qunar的票价信息的代码。

    参考项目:网络爬虫之Selenium使用代理登陆:爬取去哪儿网站


    对于网站有验证码的情况,我们有三种办法:

    • 使用代理,更新IP。
    • 使用cookie登陆。
    • 验证码识别。
     
    java多线程多进程对比: http://www.lining0806.com/%E5%85%B3%E4%BA%8Epython%E5%92%8Cjava%E7%9A%84%E5%A4%9A%E8%BF%9B%E7%A8%8B%E5%A4%9A%E7%BA%BF%E7%A8%8B%E8%AE%A1%E7%AE%97%E6%96%B9%E6%B3%95%E5%AF%B9%E6%AF%94/
    scrapy爬虫: http://www.lining0806.com/%E5%9F%BA%E4%BA%8Escrapy%E7%BD%91%E7%BB%9C%E7%88%AC%E8%99%AB%E7%9A%84%E6%90%AD%E5%BB%BA/
    网易新闻排行榜抓取回顾: http://www.lining0806.com/%E7%BD%91%E6%98%93%E6%96%B0%E9%97%BB%E6%8E%92%E8%A1%8C%E6%A6%9C%E6%8A%93%E5%8F%96%E5%9B%9E%E9%A1%BE/
    验证码登录: http://www.lining0806.com/6-%E7%BD%91%E7%BB%9C%E7%88%AC%E8%99%AB-%E9%AA%8C%E8%AF%81%E7%A0%81%E7%99%BB%E9%99%86/
     使用Scrapy或Requests递归抓取微信搜索结果  https://github.com/lining0806/WechatSearchProjects
     网络爬虫之用户名密码及验证码登陆:爬取知乎网站 https://github.com/lining0806/ZhihuSpider
     
     
    • IP代理
      • 对于IP代理,各个语言的Native Request API都提供的IP代理响应的API, 需要解决的主要就是IP源的问题了.
      • 网络上有廉价的代理IP(1元4000个左右), 我做过简单的测试, 100个IP中, 平均可用的在40-60左右, 访问延迟均在200以上.
      • 网络有高质量的代理IP出售, 前提是你有渠道.
      • 因为使用IP代理后, 延迟加大, 失败率提高, 所以可以将爬虫框架中将请求设计为异步, 将请求任务加入请求队列(RabbitMQ,Kafka,Redis), 调用成功后再进行回调处理, 失败则重新加入队列. 每次请求都从IP池中取IP, 如果请求失败则从IP池中删除该失效的IP.


    大批量爬取目标网站的内容后, 难免碰到红线触发对方的反爬虫机制. 所以适当的告警提示爬虫失效是很有必有的.

    一般被反爬虫后, 请求返回的HttpCode为403的失败页面, 有些网站还会返回输入验证码(如豆瓣), 所以检测到403调用失败, 就发送报警, 可以结合一些监控框架, 如Metrics等, 设置短时间内, 告警到达一定阀值后, 给你发邮件,短信等.

    当然, 单纯的检测403错误并不能解决所有情况. 有一些网站比较奇葩, 反爬虫后返回的页面仍然是200的(如去哪儿), 这时候往往爬虫任务会进入解析阶段, 解析失败是必然的. 应对这些办法, 也只能在解析失败的时候, 发送报警, 当告警短时间到达一定阀值, 再触发通知事件.
    当然这个解决部分并不完美, 因为有时候, 因为网站结构改变, 而导致解析失败, 同样回触发告警. 而你并不能很简单地区分, 告警是由于哪个原因引起的.


    高速存储:</b>爬虫系统的速度瓶颈主要就在存储和带宽上,至于存储,选用Hbase而不是MySQL,实测过,导出300+GB的数据,Hbase几分钟搞定,MySQL好几个小时。</li>
    <li>PhantomJS、cURL等API,验证码识别。</li>
    <li>登陆功能:要爬取微博这种需要登陆才能浏览内容的网站,肯定需要写一个登陆功能的,这里就需要注册很多的僵尸账号了,而且还需要维护僵尸账号的cookie池,很麻烦。</li>
    <li><b>采用非人力的方法写爬虫:</b>针对一个网站写爬虫太累了。。来一个任务写一个爬虫,用java写真心累啊。。所以还是想想怎么把爬虫的所有工具和API封装一下吧,用简单的配置和操作就可以完成对当前任务的快速爬取。</li></ol>嗯,以上。
     对于验证码的情况,只能进行识别咯...安全界好像对于识别率超过0.1%的验证码识别算法,就称其为有效的,我们学校通院的老师最近好像发了篇 paper关于验证码识别的,好像有70%的正确率...方法还特别简单,在每个 方向上做滤波(具体好像是直接做微分吧),把英文和数字字符的每个边检测出来,再拼起来,具体没试过,不过好像很有效。
    不过到了让你输入验证码的情况,你肯定被反爬程序检测到了咯,方法还是用代理吧...代理+流控。
     
     在快代理买的SVIP会员,三百一个月,质量还可以,不过丢包现象还是很严重的。。还是需要维护一个代理池以及针对丢包要做一个容错
     
     要不断的测试每一个ip的可用性。ip大概几分钟就无效了,要重新去快代理的接口取一次ip 由于我用的storm这个框架容纳了爬虫,只要在爬取的过程中出现了丢包或者超时等错误,就会换代理重新爬一遍
     直接在爬取的过程中判断ip可用性,如果发现错误了那就把这个ip从ip池里扔掉,通过访问特定网站的策略不一定好,会占用带宽,这部分带宽本来可用来爬取
     
     MSRA微软亚洲研究院
     
    我有个反爬虫的想法,在页面放一个链接,但是display属性设置为none或者颜色等于background-color或者链接被其他的div挡住或者链接位置超出屏幕,正常用户是不可能访问这个页面的,如果有人访问了我就认为他是爬虫,封ip。
     
     
     
     
     
     
     
     图形爬虫: 
    lamda表达式, memcached分析,redis源码,haproxy,cachecloud,zookeeper,kafka,mycat,mysql,
    用集合做一个任务库, ,任务type(名称+type), 任务名称(公司名), 任务自动编号, 写一个界面. 第一级解析(规则,key)和进入下一级的入口, 第二级解析(规则,key), 多级处理
    cookie,header使用二维数组统一管理
    正则多个日期格式一起匹配,api, 年月日,---, ...,月日.

    xpath机制研究

     


    二、如何设计自己的项目架构

    选定好一款爬虫开源框架后,就要考虑自己的业务特点,设计自己的项目架构了,大多数用爬虫的人,基本需求其实是类似的:

    a) 将目标网站的页面尽可能快速的扒下来

    b) 然后解析出有用的内容

    c) 落地存储到db中

    但凡稍微成熟一些的爬虫的开源框架,步骤a)所需的技术细节,基本上都已经实现了(比如:如何发起http请求,如何进行多线程控制等等),直接拿来用即可,但是解析哪些内容,用什么规则解析,这是每个项目的业务来决定的,需要自己处理,解析完了以后,如何落地,以及目标网站的内容变了,如何设计自己的更新爬取策略,这也是要认真考虑的。

    我的个人经验:

    项目分成3个模块:

    ---- 1)spider(爬取模块) ,

    ---- 2)parser(解析及db入库模块) ,

    ---- 3)schdule(更新爬取计划任务模块)

    模块1)与3)可以打包在同一个jar中集中部署,模块2)单独部署,之所以这样设计,出于以下考虑:

    通常最终保存内容的db小型项目中只会有一个,尽管爬虫支持多线程并发爬取,可以分布式的高效狂爬,但是db是一个慢速的IO瓶颈,如果把 "爬取->解析->入库"全放在一个模块中按顺序同步处理,最后的结果相当于前面有几个水管收集水源,但是最后进入水库的总管道不给力,整体的蓄水效率还是很慢。

    分开之后,爬取模块可以同时部署多个,然后将得到的html集中存储在1个目录下,再按子目录存储(比如:一个大型网站,会有很多分站,可以实例A爬上海站,实例B爬北京站...),这样可以尽可能快的把内容先捞回来。然后由解析模块,再到这个目录下将文件取出来慢慢解析入库,解析成功后将原始文件删除(或移到其它目录备份,这个看情况而定),如果代码有问题,比如解析规则有bug,导致某些页面解析失败,因为原始html文件已经在本机存储,修正解析的bug后,可以再试重新解析失败的文件,而不需要重新爬取。

    至于爬取模块完成后,如何通知解析模块去开始解析入库,有很多办法,比如消息队列,zookeeper订阅节点状态变化,或者在某个目录下放置一个标记文件 之类的都可以。

    三、如何更有效的更新爬取

    通常爬取时,会先从一个所谓的"种子URL"层层引导,直到发现最终的目标url,首次爬取时,可以将最终页面的url及http的返回码(404,500,200之类)记录下来,下次更新爬取时,直接重新爬取这些http状态为200的最终页面即可,这样省去了再次从seed页面层层分析的过程。(当然,这个要看自身项目的特点,如果seed页的内容本身会周期性的变化,那就省不了从seed页重新爬取的过程)

    四、其它一些可能会遇到的问题

    a) xpath的问题

    webmagic提供的xpath解析工具,不支持xpath2.0的一些高级特性,比如:查找父节点之类,解析时可以考虑引入其它一些第三方开源库,比如dom4j来处理,反正html内容已经保存到硬盘上了,想咋解析都行(但是dom4j也有一个缺点,返回的html必须是严格符合xml规范的,有些网页的html源代码,标签没有正常结束,会导致dom4j出错)

    b) ajax的问题

    有些数据是通过ajax动态请求得到的,在目标网站上并未以a链接的方式明显给出,这种情况可以根据用一些浏览器的开发者工具,观察最终发出去的ajax请求,如果ajax请求的url是有规律的,可以直接在webmagic中用类似 page.addTargetRequests("xxx")的方式手动添加。

    c) post的问题

    webmagic目前的版本,不支持post方式的url爬取,据说以后的版本会考虑,这个暂时可以手动写httpclient来发起post请求,最终拿到数据 

    d)如何对应有防爬机制的网站

    这个没有一劳永逸的办法,具体情况具体分析,

     -- 有些网站会限制url访问的频率(比如:同1个ip1分钟内只能访问某个页面N次),这种需要手动在代码里控制下节奏,比如每次http请求后,加入sleep(5000)之类的,

     -- 有些网站会根据http请求header中的User-Agent来判断是否是同一款浏览器在恶意刷,这种可以在代码中手动弄一个User-Agent列表,把市面上的所有User-Agent全加进去,每次请求前,随机从列表中取一个User-Agent,这样看起来,貌似有很多不同的浏览器在访问,显得真实一点。但是有一点要注意,目前很多大型网站都提供了pc版与移动版的页面,如果在pc浏览器上访问,对方会返回pc版的网页,如果用手机访问,会返回移动版的页面,很多就是根据User-Agent来判断的(因为PC浏览器与手机浏览器对应的User-Agent信息不同),如果你希望每次爬虫访问的都是PC版的页面,用代码设置User-Agent时,要小心别弄错了。

     -- 有些网站会限制IP,甚至有IP黑名单机制,对于这种出狠招的网站,我们也只能放大招:花点钱,找一群代理服务器,在爬虫代码里,随机切换代理服务器。

  • 相关阅读:
    开放API接口及其安全性
    suoyin
    正常关闭tomcat
    学生选课系统
    chrome浏览器Network面板请求Timing分析
    页面请求速度慢,TTFB时间长的问题分析
    javascript正则表达式
    Yahoo!团队经验:网站性能优化的34条黄金法则
    angular.js中提供的基础方法
    前端构建之--gulp
  • 原文地址:https://www.cnblogs.com/timssd/p/5345147.html
Copyright © 2011-2022 走看看