qunar 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: abb1c8b487e496de74a3d1aba1011297d09ec936
4
+ data.tar.gz: c31420590fc4344ff961faa8cf5a74c57dd66b49
5
+ SHA512:
6
+ metadata.gz: 7595b89f23e5424c60c5f4d640d51bdc9b31da7a27802390ee2716df5b3909ffccf5d48b4f164cdad164d5d99a04e43ffac0d4abf05c912258b822f96ff66052
7
+ data.tar.gz: c0805458111c8147aff0a921abf7f58b1d9f28fc755f7311e00cbe574f8197af1062945db20e55222cb2daa798cef0acef16ec0fa4ee2289715f1eabe4d007b9
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in qunar.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 charles
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Qunar
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'qunar'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install qunar
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it ( https://github.com/[my-github-username]/qunar/fork )
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,212 @@
1
+ require 'nokogiri'
2
+ require 'httparty'
3
+ module Qunar
4
+ class Hotel
5
+ BASEURI = "http://hotel.qunar.com"
6
+ def initialize(hotelId)
7
+ #super
8
+ raise "id should be string" if !hotelId.instance_of?(String)
9
+ @HotelSEQ = hotelId #hotelId is "cityurl_hotelcode"
10
+ @cityurl = hotelId[0..hotelId.rindex("_",-1)-1]
11
+ @hotelcode = hotelId[hotelId.rindex("_",-1)+1..hotelId.length]
12
+ uri = URI(File.join(BASEURI, 'city', @cityurl, "dt-#{@hotelcode}"))
13
+ page = HTTParty.get(uri.to_s)
14
+ @hotel = Nokogiri::HTML page
15
+ end
16
+
17
+ def parse_mixkey #get some kind of code unkown
18
+ uri = URI(File.join(BASEURI, 'city', @cityurl, "dt-#{@hotelcode}"))
19
+ http_res = HTTParty.get uri.to_s
20
+ res = Nokogiri::HTML http_res
21
+ node = res.search('//span[@id="eyKxim"]').first
22
+ return nil if node.nil?
23
+ return node.text
24
+ end
25
+
26
+ def name #get the name of the hotel
27
+ @hotel.search("//div[@class='htl-info fr']//span").first.text.strip
28
+ # name_tag = @hotel.search("//div[@class='htl-info fr']/h2/span").first
29
+ # return nil if name_tag.nil?
30
+ # name_tag.text[0..name_tag.text.index("\n",1)].strip
31
+ end
32
+
33
+ def star #get the level of the hotel
34
+ #name_tag = @hotel.search('//div[@class="eriefinfo"]//dt').first
35
+ name_tag = @hotel.search('//div[@class="htl-info fr"]//em[@class="dangci"]').first
36
+ return 0 if name_tag.nil?
37
+ if name_tag.text.include?'经济型'
38
+ 1
39
+ elsif name_tag.text.include?'舒适型'
40
+ 3
41
+ elsif name_tag.text.include?'高档型'
42
+ 4
43
+ elsif name_tag.text.include?'豪华型'
44
+ 5
45
+ elsif name_tag.text.include?'star20'
46
+ 2
47
+ elsif name_tag.text.include?'star50'
48
+ 5
49
+ else
50
+ 0
51
+ end
52
+ end
53
+
54
+ def citynameEn
55
+ @cityurl.sub('_city','')
56
+ end
57
+
58
+ def citynameCn
59
+ match_data = @hotel.to_s.match(/var\s*cityName\s*=\s*\'\p{Han}+\'/u)
60
+ return "" if match_data.nil?
61
+ match_data = match_data[0].match(/\p{Han}+/u)
62
+ return "" if match_data.nil?
63
+ match_data[0].strip
64
+ end
65
+
66
+ def id
67
+ @hotelcode = @hotelcode
68
+ end
69
+
70
+ def address
71
+ @hotel.search("//p[@class='adress']/span").first['title'].strip
72
+ #return "" if address.nil?
73
+ #return address['title'].strip
74
+ end
75
+
76
+ def phone
77
+ #phone ||= @hotel.search("//li[contains(text(),'电话:')]").text.sub('电话:','').strip
78
+ @hotel.search("//dl[@class='inform-list']//cite").first.text.sub('电话','').strip
79
+ end
80
+
81
+ #the description of the hotel
82
+ def desc
83
+ #desc = @hotel.search("p[@class='summery less_summery']").text
84
+ #desc = @hotel.search("p[@class='summery expan_summery']").text if desc.empty?
85
+ #desc.gsub(/[[:space:]]/, '')
86
+ @hotel.search("div[@class='introduce']/p").text
87
+ end
88
+
89
+ #开业时间
90
+ def opentime
91
+ #date ||= @hotel.search("p[@class='insttime']/cite").text.sub("开业时间:","")
92
+ #date.strip
93
+ @hotel.search("dl[@class='inform-list']//cite")[-2].text.sub("年开业",'')
94
+ end
95
+ =begin
96
+ #简略描述
97
+ def abstract_desc
98
+ abstract_desc = @hotel.search("p[@class='h_desc']").first
99
+ return "" if abstract_desc.nil?
100
+ return abstract_desc.text.sub('描述:','').strip
101
+ end
102
+
103
+ def brand
104
+ brand ||= @hotel.search("//li[contains(text(),'所属品牌:')]").text.sub('所属品牌:','').strip
105
+ brand.strip
106
+ end
107
+ =end
108
+ def reference_price
109
+ match_data = @hotel.to_s.match(/var\s*miniRetailPrice\s*=\s*\'\d+\';/)
110
+ return 0 if match_data.nil?
111
+ match_data = match_data[0].match(/[\d]+/)
112
+ return 0 if match_data.nil?
113
+ match_data[0].strip
114
+ end
115
+
116
+ def coordinate
117
+ xy = @hotel.to_s.match(/hotelPoint=\[(\d+\.\d+),(\d+\.\d+)\];/)
118
+ puts xy
119
+ if xy.nil?
120
+ return [0.0,0.0]
121
+ else
122
+ return [xy[1],xy[2]]
123
+ end
124
+ end
125
+ #设施
126
+ def facilities
127
+ facility = @hotel.search("//div[@class=\"roundmilieu htintroborder\"]").first
128
+ facilities = Array.new()
129
+ unless facility.nil?
130
+ facility.search("dl").each do |dl|
131
+ ele = Hash.new
132
+ facility_cata = dl.search("dt").first.text.delete(':')
133
+ ele1 = Array.new
134
+ dl.search("dd/ul/li").each do |facility_type|
135
+ ele1 << facility_type.text
136
+ end
137
+ ele['name'] = facility_cata
138
+ ele['info'] = ele1
139
+ facilities << ele
140
+ end
141
+ end
142
+ facilities
143
+ end
144
+
145
+ #交通信息 not runable
146
+ =begin
147
+ def traffic
148
+ traffic = "http://hotel.qunar.com/detail/detailMapData.jsp?seq=#{@hotelcode}&type=traffic,canguan,jingdian,ent"
149
+ traffic = HTTParty.get traffic
150
+ traffic_data = Array.new()
151
+ if traffic['ret'] == true
152
+ traffic['data']['ent'].each do |line|
153
+ ele = Hash.new
154
+ ele['name'] = line['name']
155
+ ele['distance'] = line['distance']
156
+ traffic_data << ele
157
+ end
158
+ end
159
+ end
160
+
161
+ def decorate_date #not found
162
+ match_data = @hotel.to_s.match(/最后装修时间:\d+年/)
163
+ return "" if match_data.nil?
164
+ match_data[0].strip
165
+ end
166
+
167
+
168
+ def comments
169
+ url = "http://review.qunar.com/api/h/#{@hotelcode}/detail/rank/v1/page/1"
170
+ comments = HTTParty.get url
171
+ comments = JSON.parse comments
172
+ comments['data']['list'].map{|comment| JSON.parse(comment['content'])['feedContent'] }
173
+ end
174
+
175
+ #评论总数
176
+ def total_comment
177
+ url = "http://review.qunar.com/api/h/#{@hotelcode}/detail/rank/page/1?rate=all"
178
+ body = HTTParty.get url
179
+ match_data = body.match(/"count":\d+/)
180
+ return "0" if match_data.nil?
181
+ match_data[0].sub(/\"count\":/,"").strip
182
+ end
183
+ #好评
184
+ def good_comment
185
+ url = "http://review.qunar.com/api/h/#{@hotelcode}/detail/rank/page/1?rate=positive"
186
+ body = HTTParty.get url
187
+ match_data = body.match(/"count":\d+/)
188
+ return "0" if match_data.nil?
189
+ match_data[0].sub(/\"count\":/,"")
190
+ end
191
+
192
+
193
+ def images
194
+ url = "http://hotel.qunar.com/render/hotelDetailAllImage.jsp?hotelseq=#{@hotelcode}"
195
+ body = HTTParty.get url
196
+ body = JSON.parse(body)
197
+ return body['data']["all"] if(body['ret'])
198
+ end
199
+
200
+ def score
201
+ url = "http://review.qunar.com/api/h/#{@hotelcode}/detail"
202
+ body = HTTParty.get url
203
+ begin
204
+ body = JSON.parse body
205
+ return body["data"]["score"].strip
206
+ rescue Exception => e
207
+ return "0.0"
208
+ end
209
+ end
210
+ =end
211
+ end
212
+ end
data/lib/qunar/rank.rb ADDED
@@ -0,0 +1,173 @@
1
+ #require 'rubygems'
2
+ require 'capybara'
3
+ #require 'selenium-webdriver'
4
+ require 'nokogiri'
5
+ require 'capybara-webkit'
6
+
7
+ #headless = Headless.new
8
+ #headless.start
9
+ Capybara.current_driver = :webkit
10
+ Capybara.default_selector = :xpath
11
+ Capybara.app_host = 'http://hotel.qunar.com'
12
+
13
+
14
+ module Qunar
15
+ class Rank
16
+ include Capybara::DSL
17
+
18
+ def initialize(hotelId)
19
+ raise "id should be string" if !hotelId.instance_of?(String)
20
+ @HotelSEQ = hotelId #hotelId is "cityurl_hotelcode"
21
+ @cityurl = hotelId[0..hotelId.rindex("_",-1)-1]
22
+ @hotelcode = hotelId[hotelId.rindex("_",-1)+1..hotelId.length]
23
+ @uri = URI(File.join('/city', @cityurl, "dt-#{@hotelcode}"))
24
+ visit @uri
25
+ all('//*[text()="展开报价"]').each do |btn|
26
+ btn.click
27
+ end
28
+ #@page = Capybara.current_session.driver.browser.page_source #use when choose capybara driver selenium
29
+ @page = Capybara.current_session.driver.browser.body #use when choose capybara driver webkit
30
+ @hotel = Nokogiri::HTML @page
31
+ File.open("test1.html","w") do |file|
32
+ file.puts @page
33
+ end
34
+ end
35
+ =begin
36
+ File.open("test1.html","w") do |file|
37
+ file.puts @page
38
+ end
39
+ =end
40
+
41
+ def room
42
+ room = {}
43
+ @hotel.search("//ul[@class='htl-type-list clrfix']/li").each do |li|
44
+ type = li.search("span[@class='type-name']").first.text.strip
45
+
46
+ li.search("div[@class='similar-type-agent-list']/div/div").each do |row|
47
+ ota_pic = row.search("div[@class='agent-pic']/img").first['src'].strip
48
+
49
+ bookable = row.search("a[@class='btn-book']/span").first.text.strip
50
+
51
+ insurance = row.search("p[@class='dbt-ct']").first
52
+ if insurance == nil
53
+ insurance = false
54
+ else
55
+ insurance = true
56
+ end
57
+
58
+ coupon = row.search("span[@class='fan']/em[@class='pr'] |span[@class='fan laps']/em[@class='pr']").first
59
+ if coupon == nil
60
+ coupon = '0'
61
+ else
62
+ coupon = coupon.text.sub(/¥/,'').strip
63
+ end
64
+
65
+ prepay = row.search("span[@title='需要预先支付房款']").first
66
+ if prepay == nil
67
+ prepay = false
68
+ else
69
+ prepay = true
70
+ end
71
+
72
+ price = row.search("p[@class='final-price ']/b").first.text.strip
73
+ neat_price = row.search("p[@class='count_pr']").first.text
74
+
75
+ puts "#{type} #{ota_pic} #{price} #{neat_price} #{coupon} #{prepay} #{insurance} #{bookable}"
76
+ end
77
+
78
+ end
79
+
80
+ return 0
81
+ end
82
+
83
+
84
+ end
85
+ end
86
+
87
+
88
+
89
+ =begin
90
+ require 'nokogiri'
91
+ require 'headless'
92
+ require 'capybara'
93
+ require 'capybara/dsl'
94
+ module Qunar
95
+ class Rank
96
+ include Capybara::DSL
97
+ BASEURI = "http://hotel.qunar.com"
98
+ def initialize(hotelId)
99
+ raise "id should be string" if !hotelId.instance_of?(String) #ckeck the whether hotelId is a string
100
+ @HotelSEQ = hotelId #hotelId is "cityurl_hotelcode"
101
+ @cityurl = hotelId[0..hotelId.rindex("_",-1)-1]
102
+ @hotelcode = hotelId[hotelId.rindex("_",-1)+1..hotelId.length]
103
+ end
104
+
105
+ def parse_mixkey
106
+ uri = URI(File.join(BASEURI, 'city', @cityurl, "dt-#{@hotelcode}")) #ex:http://hotel.qunar.com/city/beijing_city/dt-2933/
107
+ http_res = HTTParty.get uri.to_s
108
+ res = Nokogiri::HTML http_res
109
+ node = res.search('//span[@id="eyKxim"]').first
110
+ return nil if node.nil?
111
+ return node.text
112
+ end
113
+
114
+ def set_cookies
115
+ headless = Headless.new
116
+ headless.start
117
+ Capybara.current_driver = :selenium
118
+ Capybara.app_host = BASEURI
119
+ Capybara.default_wait_time = 10
120
+ begin
121
+ visit "/city/#{@cityurl}/dt-#{@hotelcode}/"
122
+ rescue Errno::ECONNREFUSED => e
123
+ raise
124
+ end
125
+ @cookies = {}
126
+ Capybara.current_session.driver.browser.manage.all_cookies.each { |cookie| @cookies[cookie[:name]] = cookie[:value] }
127
+ end
128
+
129
+ def load_price_ajax
130
+ mixKey = parse_mixkey
131
+ set_cookies
132
+ raise QunarMixKeyParsedException if mixKey.nil?
133
+ uri = URI(File.join(BASEURI, 'render', 'detailV2.jsp'))
134
+ params = {:fromDate=>Date.today+2, :toDate=>Date.today+3, :cityurl=>@cityurl, :HotelSEQ=>@HotelSEQ, :mixKey=>mixKey}
135
+ headers = Hash.new
136
+ headers['User-Agent'] = 'Mozilla/5.0 (Windows NT 5.1; rv:26.0) Gecko/20100101 Firefox/26.0'
137
+ headers['Connection'] = 'keep-alive'
138
+ headers['Accept-Encoding'] = 'gzip, deflate'
139
+ headers['Cookie'] = @cookies.map{|k, v| k+'='+v}.join('; ')
140
+ uri.query = URI.encode_www_form(params)
141
+ res = HTTParty.get(uri.to_s, :headers=>headers)
142
+ File.open("test1.html","w") do |file|
143
+ puts res
144
+ end
145
+
146
+ json_ajax = parse_json_from_response_body(res.body)
147
+ if !json_ajax['errcode'].nil? and json_ajax['errcode'].eql?110
148
+ raise QunarIpBlockException,json_ajax
149
+ end
150
+ raise QunarIpBlockException,json_ajax if !json_ajax['errcode'].nil? and json_ajax['errcode'].eql?110
151
+ @ranks = json_ajax['result'].values
152
+ end
153
+
154
+ def rank(ota, room)
155
+ @ranks.each { |rank| return rank[15]+1 if rank[3].eql?room and rank[6].eql?ota and rank[9].eql?1 }
156
+ return nil
157
+ end
158
+
159
+ def rooms
160
+ @rooms ||= @ranks.map { |e| e[3] }.uniq
161
+ end
162
+
163
+ def otas
164
+ @otas ||= @ranks.map{|e| e[6] }.uniq
165
+ end
166
+
167
+ def parse_json_from_response_body(res)
168
+ JSON.parse(res.gsub(/[()]/,""))
169
+ end
170
+
171
+ end
172
+ end
173
+ =end
@@ -0,0 +1,3 @@
1
+ module Qunar
2
+ VERSION = "0.0.1"
3
+ end
data/lib/qunar.rb ADDED
@@ -0,0 +1,7 @@
1
+ require_relative 'qunar/version'
2
+ require_relative 'qunar/hotel'
3
+ require_relative 'qunar/rank'
4
+
5
+ module Qunar
6
+ # Your code goes here...
7
+ end
data/qunar.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'qunar/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "qunar"
8
+ spec.version = Qunar::VERSION
9
+ spec.authors = ["JusticeChow"]
10
+ spec.email = ["zhengyi.zhou@corp.elong.com"]
11
+ spec.summary = %q{去哪酒店数据明细}
12
+ spec.description = %q{包含去哪酒店基本信息以及各ota报价信息}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.6"
22
+ spec.add_development_dependency "rake"
23
+ end
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: qunar
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - JusticeChow
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-07-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: 包含去哪酒店基本信息以及各ota报价信息
42
+ email:
43
+ - zhengyi.zhou@corp.elong.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - .gitignore
49
+ - Gemfile
50
+ - LICENSE.txt
51
+ - README.md
52
+ - Rakefile
53
+ - lib/qunar.rb
54
+ - lib/qunar/hotel.rb
55
+ - lib/qunar/rank.rb
56
+ - lib/qunar/version.rb
57
+ - qunar.gemspec
58
+ homepage: ''
59
+ licenses:
60
+ - MIT
61
+ metadata: {}
62
+ post_install_message:
63
+ rdoc_options: []
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - '>='
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ requirements: []
77
+ rubyforge_project:
78
+ rubygems_version: 2.3.0
79
+ signing_key:
80
+ specification_version: 4
81
+ summary: 去哪酒店数据明细
82
+ test_files: []