altflights 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.
- data/README.rdoc +12 -0
- data/Rakefile +0 -0
- data/lib/altflights.rb +36 -0
- data/lib/altflights/booking.rb +15 -0
- data/lib/altflights/flight.rb +13 -0
- data/lib/altflights/kayak_wrapper.rb +131 -0
- metadata +70 -0
data/README.rdoc
ADDED
data/Rakefile
ADDED
File without changes
|
data/lib/altflights.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'libxml'
|
2
|
+
require 'net/https'
|
3
|
+
|
4
|
+
module AltFlights
|
5
|
+
|
6
|
+
class << self
|
7
|
+
|
8
|
+
def get_flights(origin, destination, date_string) # date_string format => '%m/%d/%y'
|
9
|
+
kayak = AltFlights::KayakWrapper.new
|
10
|
+
sid = kayak.get_session()
|
11
|
+
searchid = kayak.start_flight_search(sid, 'y', origin, destination, date_string, 'a', nil, 'a', '1', 'e')
|
12
|
+
sleep(2)
|
13
|
+
|
14
|
+
more = kayak.poll_results(sid, searchid, nil)
|
15
|
+
while more == 'true' do
|
16
|
+
more = kayak.poll_results(sid, searchid, nil)
|
17
|
+
sleep(3)
|
18
|
+
end
|
19
|
+
|
20
|
+
if kayak.last_count.to_i > 50
|
21
|
+
kayak.last_count = 50
|
22
|
+
end
|
23
|
+
|
24
|
+
results = kayak.poll_results(sid, searchid, kayak.last_count)
|
25
|
+
|
26
|
+
return results
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
require 'altflights/booking'
|
34
|
+
require 'altflights/flight'
|
35
|
+
|
36
|
+
require 'altflights/kayak_wrapper'
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class AltFlights::Booking
|
2
|
+
|
3
|
+
@flights
|
4
|
+
|
5
|
+
attr_accessor :price_url, :price, :airline, :airline_display, :origin, :destination, :departure_time, :arrival_time, :stops, :duration, :cabin
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@flights = Array.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def flights
|
12
|
+
@flights
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class AltFlights::Flight
|
2
|
+
|
3
|
+
attr_accessor :airline, :flight, :duration, :equipment, :miles, :departure_time, :origin, :arrival_time, :destination, :cabin
|
4
|
+
attr_accessor :flightcaster_id, :prediction_status, :less_than_twenty, :less_than_sixty, :more_than_sixty
|
5
|
+
|
6
|
+
def add_prediction(status, on_time, less_than_60, more_than_60)
|
7
|
+
self.prediction_status = status
|
8
|
+
self.less_than_twenty = on_time
|
9
|
+
self.less_than_sixty = less_than_60
|
10
|
+
self.more_than_sixty = more_than_60
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
class AltFlights::KayakWrapper
|
2
|
+
HOSTNAME = 'api.kayak.com'
|
3
|
+
PORT = 80
|
4
|
+
|
5
|
+
attr_accessor :last_count
|
6
|
+
|
7
|
+
def api_key
|
8
|
+
KAYAK_API_KEY
|
9
|
+
end
|
10
|
+
|
11
|
+
def get_session
|
12
|
+
sid = nil
|
13
|
+
Net::HTTP.start(HOSTNAME, PORT) do |http|
|
14
|
+
response = http.get("/k/ident/apisession?token=#{api_key}")
|
15
|
+
Rails.logger.info "http://#{HOSTNAME}/k/ident/apisession?token=#{api_key}"
|
16
|
+
body = response.body
|
17
|
+
parser = LibXML::XML::Parser.string(body)
|
18
|
+
doc = parser.parse
|
19
|
+
sid = doc.find('//sid').first.inner_xml
|
20
|
+
end
|
21
|
+
sid
|
22
|
+
end
|
23
|
+
|
24
|
+
def start_flight_search(sid,
|
25
|
+
oneway, # y or n
|
26
|
+
origin,
|
27
|
+
destination,
|
28
|
+
dep_date,
|
29
|
+
dep_time, # Values:"a" = any time; "r"=early morning; "m"=morning; "12"=noon; "n"=afternoon; "e"=evening; "l"=night
|
30
|
+
ret_date,
|
31
|
+
ret_time,
|
32
|
+
travelers,
|
33
|
+
cabin) # f, b, or e
|
34
|
+
url = "/s/apisearch?basicmode=true&oneway=#{oneway}&origin=#{origin}&destination=#{destination}&destcode=&depart_date=#{dep_date}&depart_time=#{dep_time}&return_date=#{ret_date}&return_time=#{ret_time}&travelers=#{travelers}&cabin=#{cabin}&action=doflights&apimode=1&_sid_=#{sid}"
|
35
|
+
return start_search(url)
|
36
|
+
end
|
37
|
+
|
38
|
+
def start_search(url)
|
39
|
+
searchid = nil
|
40
|
+
Net::HTTP.start(HOSTNAME, PORT) do |http|
|
41
|
+
response = http.get(url)
|
42
|
+
Rails.logger.info "http://#{HOSTNAME}#{url}"
|
43
|
+
body = response.body
|
44
|
+
parser = LibXML::XML::Parser.string(body)
|
45
|
+
doc = parser.parse
|
46
|
+
Rails.logger.info searchid = doc.find('//searchid')
|
47
|
+
if searchid.first != nil
|
48
|
+
searchid = searchid.first.inner_xml
|
49
|
+
else
|
50
|
+
Rails.logger.info "search error:"
|
51
|
+
Rails.logger.info body
|
52
|
+
return nil
|
53
|
+
end
|
54
|
+
end
|
55
|
+
return searchid
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
def poll_results(sid, searchid, count)
|
60
|
+
url = "/s/apibasic/flight?searchid=#{searchid}&apimode=1&_sid_=#{sid}"
|
61
|
+
more = nil
|
62
|
+
Net::HTTP.start(HOSTNAME, PORT) do |http|
|
63
|
+
if count
|
64
|
+
url += "&c=#{count}"
|
65
|
+
end
|
66
|
+
response = http.get(url)
|
67
|
+
Rails.logger.info "http://#{HOSTNAME}#{url}"
|
68
|
+
body = response.body
|
69
|
+
if count
|
70
|
+
return handle_results(body)
|
71
|
+
else
|
72
|
+
return check_results(body)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Load the xml feed from kayak.com and return the value of the more attribute
|
78
|
+
# which indicates whether kayak is still processing the request.
|
79
|
+
def check_results(body)
|
80
|
+
parser = LibXML::XML::Parser.string(body)
|
81
|
+
doc = parser.parse
|
82
|
+
more = doc.find('/searchresult/morepending')
|
83
|
+
|
84
|
+
Rails.logger.info "count: #{self.last_count = doc.find('/searchresult/count').first.inner_xml}"
|
85
|
+
if more
|
86
|
+
more = more.first.inner_xml
|
87
|
+
end
|
88
|
+
|
89
|
+
return more
|
90
|
+
end
|
91
|
+
|
92
|
+
def handle_results(body)
|
93
|
+
parser = LibXML::XML::Parser.string(body)
|
94
|
+
doc = parser.parse
|
95
|
+
|
96
|
+
Rails.logger.info "alternate flight count: #{doc.find('/searchresult/count').first.inner_xml}"
|
97
|
+
|
98
|
+
results = []
|
99
|
+
doc.find("/searchresult/trips/trip").each do |t|
|
100
|
+
results << AltFlights::Booking.new
|
101
|
+
results.last.price_url = t.find('price').first.attributes['url']
|
102
|
+
results.last.price = t.find('price').first.inner_xml
|
103
|
+
t.find('legs/leg').each do |l|
|
104
|
+
results.last.airline = l.find('airline').first.inner_xml
|
105
|
+
results.last.airline_display = l.find('airline_display').first.inner_xml
|
106
|
+
results.last.origin = l.find("orig").first.inner_xml
|
107
|
+
results.last.destination = l.find("dest").first.inner_xml
|
108
|
+
results.last.departure_time = DateTime.strptime(l.find("depart").first.inner_xml, "%Y/%m/%d %H:%M")
|
109
|
+
results.last.arrival_time = DateTime.strptime(l.find("arrive").first.inner_xml, "%Y/%m/%d %H:%M")
|
110
|
+
results.last.stops = l.find("stops").first.inner_xml
|
111
|
+
results.last.duration = l.find("duration_minutes").first.inner_xml
|
112
|
+
results.last.cabin = l.find("cabin").first.inner_xml
|
113
|
+
l.find('segment').each do |s|
|
114
|
+
results.last.flights << AltFlights::Flight.new
|
115
|
+
results.last.flights.last.airline = s.find("airline").first.inner_xml
|
116
|
+
results.last.flights.last.flight = s.find("flight").first.inner_xml
|
117
|
+
results.last.flights.last.duration = s.find("duration_minutes").first.inner_xml
|
118
|
+
results.last.flights.last.equipment = s.find("equip").first.inner_xml
|
119
|
+
results.last.flights.last.miles = s.find("miles").first.inner_xml
|
120
|
+
results.last.flights.last.departure_time = DateTime.strptime(s.find("dt").first.inner_xml, "%Y/%m/%d %H:%M")
|
121
|
+
results.last.flights.last.origin = s.find("o").first.inner_xml
|
122
|
+
results.last.flights.last.arrival_time = DateTime.strptime(s.find("at").first.inner_xml, "%Y/%m/%d %H:%M")
|
123
|
+
results.last.flights.last.destination = s.find("d").first.inner_xml
|
124
|
+
results.last.flights.last.cabin = s.find("cabin").first.inner_xml
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
return results
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
metadata
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: altflights
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- FlightCaster
|
8
|
+
- Jon Chase
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2009-12-15 00:00:00 -08:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: libxml-ruby
|
18
|
+
type: :runtime
|
19
|
+
version_requirement:
|
20
|
+
version_requirements: !ruby/object:Gem::Requirement
|
21
|
+
requirements:
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 1.1.3
|
25
|
+
version:
|
26
|
+
description:
|
27
|
+
email: dev@flightcaster.com
|
28
|
+
executables: []
|
29
|
+
|
30
|
+
extensions: []
|
31
|
+
|
32
|
+
extra_rdoc_files: []
|
33
|
+
|
34
|
+
files:
|
35
|
+
- Rakefile
|
36
|
+
- README.rdoc
|
37
|
+
- lib/altflights/booking.rb
|
38
|
+
- lib/altflights/flight.rb
|
39
|
+
- lib/altflights/kayak_wrapper.rb
|
40
|
+
- lib/altflights.rb
|
41
|
+
has_rdoc: true
|
42
|
+
homepage: http://flightcaster.com/
|
43
|
+
licenses: []
|
44
|
+
|
45
|
+
post_install_message:
|
46
|
+
rdoc_options: []
|
47
|
+
|
48
|
+
require_paths:
|
49
|
+
- lib
|
50
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: "0"
|
55
|
+
version:
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: "0"
|
61
|
+
version:
|
62
|
+
requirements: []
|
63
|
+
|
64
|
+
rubyforge_project:
|
65
|
+
rubygems_version: 1.3.5
|
66
|
+
signing_key:
|
67
|
+
specification_version: 3
|
68
|
+
summary: Kayak alternative flights wrapper
|
69
|
+
test_files: []
|
70
|
+
|