使用ruby获取商品信息并且做相应的解析处理

现在比较主流的爬虫应该是用python,但是我觉得ruby也是ok的,我试试看写了一个爬虫的小程序,并作出相应的解析,下载图片,生成excel报表。我是写了一个框架,专门拿来爬取商品信息的。废话不多说,直接搞事情。

第一步:当然是获取商品的信息啦,输入对应的商品的网址,以及你需要爬虫的层数,判断你点击的这个网页是否是商品页面,进行相应的存储,保存源码。

    工具就是用mechanize啦,很好用的爬虫工具哦,无页面的可以减小不少内存的开销呢。(这种情况说的不加载js的情况哦 如果需要js加载的 要用selenium 原理一样的)接下来 写代码 贴上爬虫的部分代码 讲的主要就是爬虫的一个大概思想

  1 require ‘rubygems‘
  2 require "mechanize"
  3 require "json"
  4 require "mysql2"
  5 require ‘fileutils‘
  6 load "./deal_link.rb"
  7 load "./sql_op.rb"  #这边是对当前位置的增删改查  方便从断点开始
  8 load "./sql_table.rb"  #这个是每个平台创建一个数据库表 点过的链接不点 同一个链接 同一层
  9 proxy = get_proxy
 10 puts proxy
 11 agent = Mechanize.new
 12 agent.open_timeout = 15
 13 agent.set_proxy proxy[0],proxy[1]
 14 client = Mysql2::Client.new(:host => "数据库的地址", :username => "用户名",:password=>"密码",:database=>"数据库表")
 15
 16 deep = 0
 17 puts "请输入要遍历的商品信息的主url:"
 18 root_url = gets.chomp
 19 page = agent.get root_url
 20 puts "请输入链接需要点击的层数:"
 21 num = gets.chomp.to_i
 22 host = root_url.scan(/www\.(.*?)\./)[0][0]
 23
 24 ##创建目录
 25 FileUtils.mkdir_p("/samba/xww/me/new/evesaddiction/#{host}")
 26
 27 stack = []
 28 Node = Struct.new :url,:deep
 29 res_select = sql_select(client,root_url)
 30 if res_select[0] == 1 #查到click_url
 31     stack = res_select[1]
 32     puts "当前数据库已经有这条记录啦 直接导出"
 33 elsif res_select[0] == -1 #查到root_url
 34     puts "该网站已经遍历结束 程序退出"
 35     exit
 36 else #什么都没查到
 37     deep = deep + 1
 38     page.links.each do |link|
 39         obj = Node.new(link.href,deep)
 40         stack.push obj
 41     end
 42     stack.uniq!
 43     puts "第一层的链接数长度为#{stack.length}"
 44 end
 45
 46 res_exist_table = host_table_exist(client,host)
 47 if res_exist_table == 0
 48     create_table_host(client,host)
 49 end
 50
 51
 52 puts "======================="
 53 puts "当前需要遍历的url是#{root_url}"
 54 puts "该网站需要遍历的层数是#{num}"
 55 puts "======================="
 56
 57 update_flag = 0
 58
 59 while stack.length !=0
 60
 61     get_url = stack[stack.length-1].url
 62     deep = stack[stack.length-1].deep
 63     stack.pop
 64
 65     puts "----------------------------------"
 66     puts "当前stack的长度为#{stack.length}"
 67     puts "当前的url是#{get_url}"
 68     puts "当前的层数是#{deep}"
 69     puts "----------------------------------"
 70
 71
 72     sql_update(client,stack,root_url)
 73
 74     ##判断这个链接在当前层被点过没 点过就不点
 75     res_select_link_exist = select_host_table(client,host,get_url,deep)
 76     if res_select_link_exist == 1
 77         puts "该链接已经存在啦 不点啦"
 78         next
 79     else
 80         puts "该链接不存在 存进#{host}数据库表"
 81         insert_host_table(client,host,get_url,deep)
 82     end
 83     puts "----------------------------------"
 84
 85     #判断这个链接要不要点
 86     get_check_res = check(get_url,root_url)
 87     if get_check_res == 1
 88         puts "链接中含有pdf 或者 mp4 不点 跳过 或者 facebook twitter 等"
 89         puts "----------------------------------"
 90         next
 91     end
 92     puts "----------------------------------"
 93
 94     #判断一个链接是否可以点击成功
 95     res_click_link = click_link(agent,get_url,root_url)
 96     if res_click_link[0] == 1
 97         new_page = res_click_link[1]
 98         puts "点击该链接成功"
 99     else
100         puts "该链接点击失败 跳过"
101         puts "----------------------------------"
102         next
103     end
104
105     #判断内容是否为0
106     if new_page.body.length <= 0
107         puts "当前页面没有内容 跳过"
108         puts "----------------------------------"
109         next
110     end
111
112     #判断是否是产品页 没达到指定的层数 不跳
113     res = is_product_page(new_page.body,host)
114     if res == 1
115         puts "该页面有完整的产品信息 存进磁盘"
116     end
117
118     if deep < num
119         deep = deep+1
120         puts "当前页面new_page的链接数为#{new_page.links.length}"
121         begin
122             new_page.links.each do |link|
123                 res_include_link = include_link(link.href,stack)
124                 if res_include_link == 0
125                     obj = Node.new(link.href,deep)
126                     stack.push obj
127                 end
128             end
129             stack.uniq!
130         rescue
131             puts "当前页面的链接数为0"
132         end
133     else
134         #查询数据库是否有该字段
135         #没有的话 插入 stack
136         res_select = sql_select(client,root_url)
137         if res_select[0] == 0
138             puts "没有该记录"
139             res_insert = sql_insert(client,stack,root_url)
140             if res_insert == 1
141                 puts "插入成功"
142             end
143         end
144         if res_select[0] == 1
145             puts "更新数据库"
146             res_update = sql_update(client,stack,root_url)
147             if res_update == 1
148                 puts "更新成功"
149             end
150             update_flag = 1
151         end
152     end
153
154 end

第二步:解析数据库的信息啦

    解析的时候用的是nokogiri库

    用的时候直接 gem install nokogiri

  1 Encoding.default_internal = "UTF-8"
  2 require ‘rubygems‘
  3 require ‘mysql2‘
  4 require "mongo"
  5 require "nokogiri"
  6 require "json"
  7
  8 #这边我存mongo
  9 client = Mongo::Client.new(["数据库地址:端口号"],:database=>"数据库名字")
 10
 11 puts "请输入要解析的平台的网站"
 12 u = gets.chomp
 13 dir = u.scan(/www\.(.*?)\./)[0][0]
 14
 15 time = gets.chomp
 16 time.gsub!(":","-")
 17
 18 full_dir = "./#{dir}"
 19
 20
 21 def go_dir(full_dir,agent,client,u,time)
 22     input_url_front = nil
 23     Dir.glob("#{full_dir}/*") do |path|
 24
 25         res = File.directory? path
 26         if res == true
 27             puts "#{path}是一个目录 继续遍历"
 28             puts "------------------------------------------------------"
 29             go_dir(path,agent,client,u,time)
 30             puts "目录的文件读取完毕 目录不用读取跳过"
 31             next
 32         end
 33
 34         s=File.read(path)
 35         doc = Nokogiri::HTML(s)
 36
 37           #提取我需要的字段
 38         begin
 39             title = s.scan(/(?i)meta\s*property="og:title"\s*content="([^"]+)"/)[0][0]  #^>  content里面
 40             description = s.scan(/(?i)[meta\s*property="og:|meta\s*name="]description"\s*content=\s*"([^\"]+)"/)[0][0]
 41             url = s.scan(/(?i)meta\s*property="og:url"\s*content="([^"]+)"/)[0][0]
 42             image = s.scan(/(?i)meta\s*property="og:image"\s*content="([^"]+)"/)[0][0]
 43         rescue
 44             puts "没有匹配到 title  description url image  其中之一的字段 不完整 可能不是商品页"
 45             puts "------------------------------------------------------"
 46             next
 47         end
 48
 49         if url.scan("http").length == 0
 50             url = u + url
 51         end
 52
 53         begin
 54             price = s.scan(/(?i)itemprop=[‘\"]price[‘\"]\s*>?[‘\"]?(\$?\d+(?:\,\d+)?(?:\.\d+)?(?:\s\w+)?)(?=[‘\"<])/)[0][0]
 55             price_label = s.scan(/(?i)itemprop=[‘"]priceCurrency[‘"]\s*content=[‘"]([^[‘"]]+)(?=[‘"])/)[0][0]
 56         rescue
 57             puts "没有匹配到价格 换一个匹配"
 58             begin
 59                 price = s.scan(/meta\s*property="product:price:amount"\s*content="([^"]+)"/)[0][0]
 60                 price_label = s.scan(/(?i)meta\s*property="product:price:currency"\s*content="([^"]+)"/)[0][0]
 61             rescue
 62                 puts "还是没有匹配到价格信息 不完整"
 63                 puts "---------------------------------------------------------"
 64                 next
 65             end
 66         end
 67
 68         begin
 69             classify = doc.css("ul.grid_12 li").text
 70             classify = classify.split("\n")
 71             for i in 0..classify.length-1
 72                 classify[i].strip!
 73             end
 74             for i in 0..classify.length-1
 75                 if classify[i] == ""
 76                     classify.delete(classify[i])
 77                 end
 78             end
 79             3.times{classify.delete_at(0)}
 80             for i in 0..classify.length-1
 81                 classify_name = classify_name.to_s + classify[i].to_s + ">"
 82             end
 83             classify_name.chop!
 84         rescue
 85             classify_name = nil
 86         end
 87
 88         #保留两位小数
 89         price = price.to_f.round(2)
 90
 91         begin
 92             material = s.scan(/Metal<\/dd><dt>(.*?)</)[0][0]
 93         rescue
 94             puts "没有匹配到material"
 95             material = nil
 96         end
 97
 98         begin
 99             item_statue = s.scan(/\"WebTrend\":\"(.*?)\"/)[0][0]
100         rescue
101             puts "没有匹配到item_statue"
102             item_statue = nil
103         end
104
105          ##相应的信息解析好之后存进数据库
106         product_col = client[:product]
107         res = product_col.find({product_detail_url:"#{url}"}).first
108
109         if res == nil
110             puts "这条记录数据库没有 可以插入 新品"
111             new_classify_collection = []
112             if classify_name != nil
113                 new_classify_collection.push classify_name
114             end
115
116             old_price = nil
117             product_update_time = nil
118             price_statue = nil
119
120             product_col.insert_one({product_title:"#{title}",product_description:"#{description}",product_detail_url:"#{url}",product_image_addr:"#{image}",product_price:price,product_price_label:"#{price_label}",product_come_time:"#{time}",product_update_time:"#{product_update_time}",product_shop:"#{u}",classify_name:"#{classify_name}",new_classify_collection:"#{new_classify_collection}",old_price:"#{old_price}",price_statue:"#{price_statue}",item_statue:"#{item_statue}",material:"#{material}"})
121             puts "插入成功"
122             puts "==================================================="
123         else
124             puts "该字段已在数据库中有记录 准备更新数据库"
125             puts res
126             new_classify_collection = []
127             new_classify_collection = JSON.parse(res["new_classify_collection"])
128
129             if (!new_classify_collection.include? classify_name) && (classify_name != nil)
130                 new_classify_collection.push classify_name
131             end
132
133             puts "-------------------------------------------------"
134             if price > res["product_price"].to_f
135                 puts "涨价"
136                 old_price = res["product_price"].to_f
137                 price_statue = "Rise Price"
138                 product_col.update_one( { ‘product_detail_url‘ => "#{url}" }, { ‘$set‘ => { ‘product_price‘ => price.to_f, ‘product_update_time‘ => "#{time}", ‘classify_name‘ => "#{classify_name}",‘new_classify_collection‘ => "#{new_classify_collection}",‘old_price‘:old_price,‘price_statue‘:"#{price_statue}",‘item_statue‘:"#{item_statue}"} } )
139             end
140             if price < res["product_price"].to_f
141                 puts "降价"
142                 old_price = res["product_price"].to_f
143                 price_statue = "Reduced Price"
144                 product_col.update_one( { ‘product_detail_url‘ => "#{url}" }, { ‘$set‘ => { ‘product_price‘ => price.to_f, ‘product_update_time‘ => "#{time}", ‘classify_name‘ => "#{classify_name}",‘new_classify_collection‘ => "#{new_classify_collection}",‘old_price‘:old_price,‘price_statue‘:"#{price_statue}",‘item_statue‘:"#{item_statue}"} } )
145             end
146             puts "更新成功"
147             puts "==================================================="
148         end
149
150     end
151 end
152
153 go_dir(full_dir,agent,client,u,time)

第三步:商品都有图片的,解析完成后,我们下载图片

    下载图片我们用的还是mechanize

    page = agent.get img_url

    page.body就是图片的内容啦 直接保存就好啦

    

    有时候我们下载下来的图片比较大 我们会使用图片压缩

    这里我们用这个库 mini_magick 我就 稍微写一下把

 1 require "mini_magick"
 2
 3 u = "https://www.evesaddiction.com"
 4 up =  u.scan(/www\.(.*?)\./)[0][0] + "Img" #这个是下载好的图片了
 5 host = u.scan(/www\.(.*?)\./)[0][0] + "Ok" #保存要压缩的图片
 6 ##创建目录
 7 FileUtils.mkdir_p("./#{host}")
 8
 9 Dir.glob("./#{up}/*") do |p|
10     s=p
11     s = s.scan(/[^\/]+$/)[0].scan(/(.*?).jpg/)[0][0]
12
13     image = MiniMagick::Image.open(p)
14     image.resize "100x100"
15     image.write "./#{host}/#{s}.png"
16 end

第四步:有时候查数据库那么大的信息量看起来有点麻烦,我们可以生成excel表格,清晰明了。

    我们可以用这个库 axlsx 不仅可以插入文字 也可以插入图片(缩略图) 在你看这份报表的时候 更直观看出是什么商品

    这里就不写代码啦 相应的文档

   

    https://github.com/randym/axlsx/blob/master/examples/example.rb
    https://gist.github.com/randym/2371912

ps:有时候会觉得爬虫的速度特别慢,就是第一步获取商品的源码的时候,可以大家可以用socket的udp通讯多进程来解决这个问题。

服务器负责分发要点击的网址,以及当前网址的层数,客户端负责判断这个链接是否是我需要的商品信息,最后返回结果给服务端,服务端在做相应的数据更近,会增加不少的速度。

ruby的线程是假线程,不推荐使用。

    

原文地址:https://www.cnblogs.com/zhe-hello/p/9197515.html

时间: 2024-11-09 03:16:03

使用ruby获取商品信息并且做相应的解析处理的相关文章

Servlet 获取商品信息作业

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>表单</title> </head> <body> <form action="tijiao" method="post"> 添加商品信息: <br><br> 商品名称: <input typ

扫描条形码获取商品信息(iOS 开发)

一.导入ZBarSDK及其依赖库(这不是本文侧重点) 1.下载地址 https://github.com/bmorton/ZBarSDK 2.导入头文件 #import "ZBarSDK.h" 实现委托事件 <ZBarReaderDelegate> 二.具体方法 1.viewController.m文件 #import "ViewController.h" #import "ZBarSDK.h" #import "AFNet

导入外部proto获取商品信息

Models.proto syntax = "proto3"; package services; //商品模型 message ProdModel { int32 prod_id = 1; string prod_name = 2; float prod_price = 3; } Prod.proto syntax = "proto3"; package services; import "google/api/annotations.proto&quo

python爬虫之:淘宝商品搜索爬虫(收集商品信息/下载详情图)

一.获取商品信息: #!/usr/bin/python3.5 #coding:utf8 import xlsxwriter as wx import re import cgi import requests import os import time import urllib page=1 downsuccess = 0 downfaild = 0 shop = [("店铺名称","商品","商品售价¥","商品购买数",

求大神 &nbsp; 谁做过类似淘宝的sku商品信息组合

求大神   谁做过类似淘宝的sku商品信息组合

淘宝开放平台php-sdk测试 获取淘宝商品信息(转)

今天想使用淘宝开放平台的API获取商品详情,可是以前一直没使用过,看起来有点高深莫测,后然看开发入门,一步一步,还真有点感觉了,然后看示例,还真行了,记下来以后参考.其中遇到问题,后然解决了.因为我已经有APPKEY了所以,我使用的是正式环境,大家可以使用测试换进,设置稍微有点区别: 1.下载PHP SDK,下载地址:http://open.taobao.com/doc/detail.htm?spm=0.0.0.21.e7516f&id=34#s1 2.PHP SDK解压后,lotusphp_r

PHP基础示例:商品信息管理系统v1.1

实现目标:使用php和mysql写一个商品信息管理系统,并带有购物车功能 一.创建数据库和表 1.创建数据库和表:demodb 2.创建表格:goods 字段:商品编号,商品名称,商品类型,商品图片,单价,商品描述,库存量,添加时间 二.创建php文件编写代码(以下为要创建的php文件及其用途) add.php 商品添加页面 edit.php      商品信息编辑表单页 index.php 商品信息浏览页 action.php 执行商品信息添加和修改及删除等操作处理 dbconfig.php

商品信息数据分析及展现系统

基于数据挖掘技术的智能化数据分析系统设计与开发 潍坊物价信息数据分析及展现 背景: 商品价格和人们生活息息相关,比如农产品价格波动不仅会对农民收入和农民生产积极性产生直接影响,更关乎百姓的日常生活和切身利益.经常看新闻看到农民辛苦了一个季度的农作物全都烂在地里,因为价格太低廉,或者没有销路.虽然说物价波动是一种正常的经济现象,但是在一定程度上物价稳,人心才稳,社会才稳.为保持经济平稳健康发展.保障群众生活,稳定物价,信息公开显得尤为重要.价格监测和预测是维持物价稳定的一个重要环节.而对于商品价格

「实例操作」抓取耐克中国官网数据转淘宝数据包-1 获取商品链接

最近接了个单子,要抓耐克中国的数据,把里面的商品转化成淘宝数据包,可以直接上传宝贝 客户提出了3个要求: 1:批量下载全网站商品: 2:定期更新网站新品: 3:批量更新淘宝库存,检查网站数据 这边先确定思路 第一是要抓取这些商品的列表, 第二是抓取单品的信息, 第三是把信息按照淘宝数据包格式输出. 这样就解决了第一个要求, 第二个邀请是抓取新品,这个要求可以这样理解,定期抓取所以链接,并保存下来,如果有的新的链接,那就是新品, 第三个要求更新库存,这个要有淘宝接口,我朋友那边有,借用下即可 ==