royal_mail_scraper 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.travis.yml +8 -0
- data/Gemfile +12 -0
- data/LICENSE.txt +22 -0
- data/README.md +42 -0
- data/Rakefile +6 -0
- data/lib/royal_mail_scraper/tracker/detail.rb +12 -0
- data/lib/royal_mail_scraper/tracker/request.rb +23 -0
- data/lib/royal_mail_scraper/tracker/response.rb +36 -0
- data/lib/royal_mail_scraper/tracker/status_map.rb +27 -0
- data/lib/royal_mail_scraper/tracker.rb +35 -0
- data/lib/royal_mail_scraper/version.rb +3 -0
- data/lib/royal_mail_scraper.rb +16 -0
- data/royal_mail_scraper.gemspec +24 -0
- data/spec/assets/collected.html +633 -0
- data/spec/assets/delivered.html +638 -0
- data/spec/assets/not_found.html +624 -0
- data/spec/assets/on_delivery.html +633 -0
- data/spec/royal_mail_scraper_spec.rb +20 -0
- data/spec/spec_helper.rb +9 -0
- data/spec/tracker_spec.rb +80 -0
- metadata +114 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 4f34da7f0b92b97623f600d4658ed8507f3b67c9
|
4
|
+
data.tar.gz: 0db41cda4ecd1213132d0ceb6611447859275d13
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3ef7758c075bc74a6b7ae8ccaba8138f7ce2c631f37b1f7ef91441494effe5eb2407a48b441130df69acbd694270bcc06a73f806f103446280e91a09a9b6c58f
|
7
|
+
data.tar.gz: a42572c88d4fc72279051e776ff278af118bb1a2f60ebd2b37eda1d90c7f5bcd728f374806c1b17ec814677af23347fd334a417f640c58d3ad236b0d9ba004c9
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Laurynas Butkus
|
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,42 @@
|
|
1
|
+
# RoyalMailScraper
|
2
|
+
|
3
|
+
[![Build Status](https://secure.travis-ci.org/laurynas/royal_mail_scraper.png)](http://travis-ci.org/laurynas/royal_mail_scraper)
|
4
|
+
|
5
|
+
A simple page scraper for Royal Mail Track and Trace.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
gem 'royal_mail_scraper'
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install royal_mail_scraper
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
tracker = RoyalMailScraper::Tracker.fetch('TRACKING_CODE')
|
24
|
+
|
25
|
+
p tracker.status
|
26
|
+
p tracker.message
|
27
|
+
p tracker.details
|
28
|
+
|
29
|
+
## Contributing
|
30
|
+
|
31
|
+
1. Fork it
|
32
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
33
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
34
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
35
|
+
5. Create new Pull Request
|
36
|
+
|
37
|
+
## Credits
|
38
|
+
|
39
|
+
This GEM is originally inspired by
|
40
|
+
[PHP-Royal-Mail-Track-and-Trace](https://github.com/roldershaw/PHP-Royal-Mail-Track-and-Trace) script.
|
41
|
+
|
42
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
module RoyalMailScraper
|
2
|
+
class Tracker::Detail
|
3
|
+
attr_reader :datetime, :message, :location, :status
|
4
|
+
|
5
|
+
def initialize(datetime, message, location)
|
6
|
+
@datetime = datetime
|
7
|
+
@message = message
|
8
|
+
@location = location
|
9
|
+
@status = Tracker::StatusMap.resolve(message)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
module RoyalMailScraper
|
4
|
+
class Tracker::Request < Struct.new(:tracking_number)
|
5
|
+
REQUEST_URI = URI('http://www.royalmail.com/trackdetails')
|
6
|
+
TIMEOUT = 10
|
7
|
+
|
8
|
+
def execute
|
9
|
+
params = { tracking_number: tracking_number }
|
10
|
+
|
11
|
+
req = Net::HTTP::Post.new(REQUEST_URI.request_uri)
|
12
|
+
req.form_data = params
|
13
|
+
|
14
|
+
http = Net::HTTP.new(REQUEST_URI.host, REQUEST_URI.port)
|
15
|
+
http.open_timeout = TIMEOUT
|
16
|
+
http.read_timeout = TIMEOUT
|
17
|
+
|
18
|
+
res = http.request(req)
|
19
|
+
|
20
|
+
Tracker::Response.new(res.body)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
|
3
|
+
module RoyalMailScraper
|
4
|
+
class Tracker::Response
|
5
|
+
attr_reader :html
|
6
|
+
|
7
|
+
DETAILS_PATH = '//*[@id="bt-tracked-track-trace-form"]/div/div/div/div[1]/table/tbody/tr'
|
8
|
+
ERROR_PATH = '//*[@id="bt-tracked-track-trace-form"]/div/div/div/div[1]/div[5]/text()'
|
9
|
+
|
10
|
+
TIME_FORMAT = '%d/%m/%y %H:%M'
|
11
|
+
|
12
|
+
def initialize(body)
|
13
|
+
@html = Nokogiri::HTML(body)
|
14
|
+
end
|
15
|
+
|
16
|
+
def tracker
|
17
|
+
Tracker.new(tracking_number, details.reverse)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def tracking_number
|
23
|
+
el = @html.at('input[@name="tracking_number"]')
|
24
|
+
el ? el.attr(:value).to_s.strip : nil
|
25
|
+
end
|
26
|
+
|
27
|
+
def details
|
28
|
+
html.xpath(DETAILS_PATH).map do |tr|
|
29
|
+
date, time, message, location = tr.css('td').map(&:content).map(&:strip)
|
30
|
+
time = '00:00' unless time =~ /\A\d+:\d+\z/
|
31
|
+
datetime = DateTime.strptime([date, time].join(' '), TIME_FORMAT) rescue DateTime.new
|
32
|
+
Tracker::Detail.new(datetime, message, location)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module RoyalMailScraper
|
2
|
+
class Tracker::StatusMap
|
3
|
+
UNRECOGNISED = 'unrecognised'
|
4
|
+
IN_TRANSIT = 'in_transit'
|
5
|
+
ON_DELIVERY = 'on_delivery'
|
6
|
+
UNDELIVERED = 'undelivered'
|
7
|
+
HELD_AT_ENQUIRY_OFFICE = 'held_at_enquiry_office'
|
8
|
+
DELIVERED = 'delivered'
|
9
|
+
|
10
|
+
def self.resolve(message)
|
11
|
+
case message
|
12
|
+
when /^(ACCEPTED|RECEIVED|DESPATCHABLE|DESPATCHED|COLLECTED|ARRIVED)/
|
13
|
+
IN_TRANSIT
|
14
|
+
when /^ON DELIVERY/
|
15
|
+
ON_DELIVERY
|
16
|
+
when /^UNDELIVERED/
|
17
|
+
UNDELIVERED
|
18
|
+
when /^HELD AT ENQUIRY/
|
19
|
+
HELD_AT_ENQUIRY_OFFICE
|
20
|
+
when /^DELIVERED/
|
21
|
+
DELIVERED
|
22
|
+
else
|
23
|
+
UNRECOGNISED
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module RoyalMailScraper
|
2
|
+
class Tracker < Struct.new(:tracking_number, :details)
|
3
|
+
def self.fetch(tracking_number)
|
4
|
+
request = Request.new(tracking_number)
|
5
|
+
response = request.execute
|
6
|
+
response.tracker
|
7
|
+
end
|
8
|
+
|
9
|
+
def datetime
|
10
|
+
last_detail.datetime if last_detail
|
11
|
+
end
|
12
|
+
|
13
|
+
def status
|
14
|
+
last_detail.status if last_detail
|
15
|
+
end
|
16
|
+
|
17
|
+
def message
|
18
|
+
last_detail.message if last_detail
|
19
|
+
end
|
20
|
+
|
21
|
+
def location
|
22
|
+
last_detail.location if last_detail
|
23
|
+
end
|
24
|
+
|
25
|
+
def recognised_details
|
26
|
+
details.select { |detail| detail.status != StatusMap::UNRECOGNISED }
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def last_detail
|
32
|
+
@last_detail ||= details.last
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "royal_mail_scraper/version"
|
2
|
+
require "royal_mail_scraper/tracker"
|
3
|
+
require "royal_mail_scraper/tracker/request"
|
4
|
+
require "royal_mail_scraper/tracker/response"
|
5
|
+
require "royal_mail_scraper/tracker/detail"
|
6
|
+
require "royal_mail_scraper/tracker/status_map"
|
7
|
+
|
8
|
+
module RoyalMailScraper
|
9
|
+
TRACKING_NUMBER_FORMAT = /\A[A-Z]{2}\d{9}GB\z/i
|
10
|
+
|
11
|
+
class << self
|
12
|
+
def tracking_number?(tracking_number)
|
13
|
+
!!(tracking_number.to_s =~ TRACKING_NUMBER_FORMAT)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'royal_mail_scraper/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "royal_mail_scraper"
|
8
|
+
spec.version = RoyalMailScraper::VERSION
|
9
|
+
spec.authors = ["Laurynas Butkus"]
|
10
|
+
spec.email = ["laurynas.butkus@gmail.com"]
|
11
|
+
spec.description = %q{A simple page scraper for Royal Mail Track and Trace}
|
12
|
+
spec.summary = %q{Fetches tracking information from Royal Mail page}
|
13
|
+
spec.homepage = "https://github.com/laurynas/royal_mail_scraper"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
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_dependency "nokogiri", "~> 1.5"
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
23
|
+
spec.add_development_dependency "rake"
|
24
|
+
end
|