`
Saito
  • 浏览: 42870 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

用hpricot/nokogiri做各种欢乐的事. .

阅读更多
  话说之前某运营MM在某大型商城做反盗版活动.活动的要求还蛮简单的. 需求总结如下:

  1.抓取某商家的所有item
  2.与博库.当当.亚马逊三家去做比对.如果没有这本书就说明是盗版(好吧.我承认这个方法.. ...)
  3.输出所有的情况.

  嗯. boss给她们手动各种抓.. 这个肯定不能行啊. 好吧.我就各种接下活来.

  拿到需求怎么办. 尤其是拿到mm的各种需求怎么办. 肾上腺素一上来你就知道该怎么办了.

  各种hpricot/nokogiri下. 好吧. 首先你需要的是什么. 嗯 .是各种搜索页面.

  这里各种收集了下:

 
dang_url = "http://search.dangdang.com/search.php?key="
amzn_url = "http://www.amazon.cn/s/ref=nb_sb_noss?url=search-alias%3Daps&field-keywords="
boku_url = "http://www.bookuu.com/search/book_search.jsp?category=sm&keyword="

ltyx_url = "http://ltyx.mall.taobao.com/?search=y&pageNum="
  


  好吧. 以上网址均来自互联网. 切勿跨省追捕.

 
require 'hpricot'
require 'open-uri'
require 'iconv'
require 'cgi'

inner_ltyx_items = []

#pagenum 1..2  :)
for i in 1..2 do
  #sleep for g_w..you know.
  sleep rand(3)
  Hpricot(open(ltyx_url + i.to_s))./('//a[@class="permalink"]').each do |item|
    #puts item.inner_text
    inner_ltyx_items << item.inner_text
  end
end

inner_ltyx_items.each do |item|
  dang_doc = Hpricot(open(dang_url + CGI.escape(item)))
  boku_doc = Hpricot(open(boku_url + CGI.escape(item)))
  amzn_doc = Hpricot(open(amzn_url + CGI.escape(item)))
  sleep rand(3)

  puts "#{item}"
  {:"当当" =>[dang_doc,'//div[@class="allsearch_right_list_sorry"]'],
    :"博库" =>[boku_doc,'//div[@id="no-pages-box"]'],
    :"卓越" => [amzn_doc,'//h1[@id="noResultsTitle"]']}.each do |name,map|
    begin
      puts "--#{name}检索失败!" if map[0]./(map[1]).first.inner_text
    rescue 
      puts "#{name}检索到您的商品."
    end
  end
end


  好吧 .上面的代码在真正检索商品的时候利用了三大书城的搜索失败tag. 这里算是小hack. 当博库没有搜索到结果的时候会出现"no-pages-box".当当卓越类似.当然在我代码最后rescue的时候就会出现  异常竟然为检索的商品的乱象也就不奇怪了..
  当中的sleep rand(i) 应该就不用再解释一遍了.然后开头hack了页面的num.当然你也可以从hpricot/nokogiri里面取.不麻烦的.
  当然.最好的搭档工具莫过于firebug. 要不然哪里来那么多selector.

  上面的代码运行是没有问题的 当然有缺陷.

  1. 当这个某商家的 item 命名不规范时. 在三大书城是很难搜索到相同的物品的.这里我不知道该说他们的搜索做的差.还是我这边其实应该做分词.
  2. bot is evil.

  当然就这样收手我是不干的.. 各种顺便做个比价吧..

  比价是怎么回事. 好吧. 你应该懂的.

  想比价. 先拿item .这里你自己找去吧. 在下面我对比了某mall跟当当的价钱.

 
# eg. %D6%DC%B1%CA%B3%A9 
doc = Nokogiri::HTML(open('http://search.dangdang.com/search.php?key=%D6%DC%B1%CA%B3%A9'))

doc = Nokogiri::HTML(open('http://list.mall.taobao.com/search_product.htm?q=%D6%DC%B1%CA%B3%A9'))


{:mall =>'//div[@class="now-price"]', :dangdang =>'//span[@class="red"]'}.each do |name,selector|
  begin
    puts name.to_s+doc.xpath(selector).first.content.to_s
  rescue 
    puts name.to_s+" : it matchs none!"
  end
end


  当然比价跟上面的查盗版会遇到相同的item命名问题.嗯.其实这个还真是有点问题.不过同时抓amazon 跟 当当的话. 就会好很多.因为命名会比较规范.

  其次. bot is evil.

  嗯. 各种evil. 结果在某日的某日. 又有身在国外在玩具厂打学工的mm说自己接到一个$500的活.某厂boss给他一份各种Primary.College.School的名单.然后她的工作就是找到这些学校的email. 然后整理成册. 用途就是用作发各种垃圾邮件.. 好吧. . 嗯. 国外的钱真的比较好挣. 这时候联想到 时薪75~120的澳洲freelancer哥. 算了一下..这时候我应该超越他了.可惜我只是帮忙.没有报酬.当然超越这种事也只是YY而已.
 
  分析了一下 boss给MM 的学校名册. 她的内容格式类似下面这样. 然后分为四个文件.

 
Art Coordinator
St Mary's School
97 Railway Street
Altona, VIC 3018

Art Coordinator
St Paul's Primary
716 Fourteenth Street
Mildura, VIC 3500

Art Coordinator
St Peter's College
Cranbourne-Frankston Rd
Cranbourne, VIC 3977


  嗯. 学校只分这三种. college primary 跟school . 废话不多说.拿出我们有用的学校名字就够了. .其余的位置什么的是用不到的. 这回我们用google干点$500的事.

 
["private school NSW.txt","private school SA.txt","private school VIC.txt","private school WA.txt"].each do |name|
	File.open("FIX_#{name}",'w').puts(File.open(name).readlines.grep(/School|Primary|College/))
end


  修理下四个文件.然后加上Fix头.  直接grep出这三种就好. 嗯. 效果很好.

 
Carey Baptist Grammar School
Christian College Geelong
ELTHAM College of Education


  然后利用强大到墙外的google .. 我们需要的是 google出我们的 各种school. 然后在后面加上 email 关键字. 然后在结果里面淘出我们的结果.

  事先我先试了一下. 发现效果尚可. 大概5中3的样子. 这生意可以做.而且澳洲的学校都比较乖.不会用 #  AT 或者 pic 来代替 email中字符的情况出现.

  用firebug划拨了几个要点.就要开始超越freelancer哥的旅程了. 加上各种分析文件什么的大概两小时吧.(嗯.这时间实在是有点长. 不过算是超越了).得到了下面的东西.

 
require 'rubygems'
require 'nokogiri'
require 'open-uri'
require 'cgi'

google_url = "http://www.google.com/search?q="
["FIX_private school NSW.txt","FIX_private school SA.txt","FIX_private school VIC.txt","FIX_private school WA.txt"].each do |name|
	File.open(name).readlines.each do |line|
		flag = ""
		s = CGI.escape(line+" email")
		sleep 8+rand(3)
		begin
			doc = Nokogiri::HTML(open(google_url+s))			
			doc.xpath('//li/div[@class="s"]').each do |link|
				email = link.content.gsub(/<\/?em>/,"")[/[a-z0-9!#\$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#\$%&'*+\/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+(?:[A-Z]{2}|com|org|net|edu|gov|mil|biz|info|mobi|name|aero|asia|jobs|museum)/]
				if email
					puts "#{name}_RESULT :   "+email
					File.open("#{name}".gsub("FIX","RESULT"),'w+') {|f| f.puts(email)}
					break
				end
				flag = email
			end
		rescue
			puts "has error occur!"
		end
		if !flag
			puts "#{name}_NOT FOUND :   "+line
			File.open("#{name}".gsub("FIX","NOT_FOUND"),'w+') {|f| f.puts(line) }
		end
		STDOUT.flush
	end
end


  好吧.我承认中间那段验证email的regex是抄的. 得冒(霓虹语来着). it works. .
 
  由于google有关键字加红的问题. 所以在取到content之后先需要gsub掉<em></em>标签.然后调用email的正则. 嗯. 就大概得到了结果.

  当然在最后我们需要记录没有被找到的学校名称.

  当然 .Google大神的话我们sleep的时间要比较长. 我选择了 8 + rand 3的方式. 嗯.比较保守.当然. 你也可以选择被大神强制输captcha .或者直接ban掉.  事实证明.我还是有极少的部分超时了. 打出了简易error log.嗯.不过已经非常出色了.

  嗯. 成果类似下面.

 
FIX_private school NSW.txt_NOT FOUND :   Australian Technical College
FIX_private school NSW.txt_RESULT :   admin@avondaleschool.nsw.edu
FIX_private school NSW.txt_RESULT :   registrar@bankstowngrammar.nsw.edu


  $500.你值得拥有.

  hpricot/nokogiri 是可以做到简单的抓取重要数据.但是如果有强大的ban未知爬虫的能力的站话.就要换用mechanize了.

  mechanize的能力就是模拟各种浏览器.携带cookie什么的. =>传送门<=

  主要我还不是那么高端的人. 暂时还用不到. 据说要爬本站(也就是Javaeye)的话.是会付出惨重代价的. 尤其你还用这么低端的爬虫.

  发挥想象力.是有很多东西可以玩的.而且写爬虫会上瘾的.



  Don't remember ! bot is evil . evil   . evi. .e ..

 

 
分享到:
评论
7 楼 Enn 2010-08-23  
这种爬虫抓结构良好 符合规范的网站还是很不错的。
我曾经用nokogiri写过一个  目标网站的结构阿 CSS规范什么的 完全是乱七八糟。还包含各种意外情况 到最后 程序里充斥着 各种异常情况的判断   发上来绝对能恶心到人……
6 楼 mathgl 2010-08-16  
orcl_zhang 写道
下一站,火星 写道
1 不喜欢楼主疯癫的文笔,难道是chinaonrails那哥们教出来的?

2 搞不懂这个贴子精华在什么地方 =/=

我想投一般贴,可惜je没有这个.精华确实很勉强


不能是良好??
5 楼 icefishc 2010-08-13  
下一站,火星 写道
1 不喜欢楼主疯癫的文笔,难道是chinaonrails那哥们教出来的?

2 搞不懂这个贴子精华在什么地方 =/=

因为这偏文章还算有东西。 至少算是个对hpricot/nokogiri的介绍

比较下满屏的水贴,笔记贴已经算是不错了。
4 楼 orcl_zhang 2010-08-13  
下一站,火星 写道
1 不喜欢楼主疯癫的文笔,难道是chinaonrails那哥们教出来的?

2 搞不懂这个贴子精华在什么地方 =/=

我想投一般贴,可惜je没有这个.精华确实很勉强
3 楼 下一站,火星 2010-08-13  
1 不喜欢楼主疯癫的文笔,难道是chinaonrails那哥们教出来的?

2 搞不懂这个贴子精华在什么地方 =/=
2 楼 orcl_zhang 2010-08-13  
引用
另外一种写法:  用DSL对页面建模:

http://github.com/dazuiba/autoweb

dazuiba (author).
恩,很不错.好东西.
我一直认为nokogiri最大的作用就是从起点上抓小说,排版,然后导入到手机,还有就是发垃圾邮件..

另,发现je的seo做的非常好.我刚用google搜hpricot nokogiri,第一页就看到了这个帖子.
1 楼 dazuiba 2010-08-13  
另外一种写法:  用DSL对页面建模:

http://github.com/dazuiba/autoweb

相关推荐

Global site tag (gtag.js) - Google Analytics