russian_post 0.1.0 → 0.1.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/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ - 1.9.3
5
+ - jruby-19mode
data/Gemfile.lock CHANGED
@@ -4,21 +4,40 @@ PATH
4
4
  russian_post (0.1.0)
5
5
  chunky_png (~> 1.2)
6
6
  excon (~> 0.20)
7
+ mechanize (~> 2.6.0)
7
8
  nokogiri (~> 1.5)
8
9
 
9
10
  GEM
10
11
  remote: https://rubygems.org/
11
12
  specs:
12
13
  addressable (2.3.4)
13
- chunky_png (1.2.7)
14
+ chunky_png (1.2.8)
14
15
  crack (0.3.2)
16
+ domain_name (0.5.11)
17
+ unf (>= 0.0.5, < 1.0.0)
15
18
  excon (0.20.1)
19
+ mechanize (2.6.0)
20
+ domain_name (~> 0.5, >= 0.5.1)
21
+ mime-types (~> 1.17, >= 1.17.2)
22
+ net-http-digest_auth (~> 1.1, >= 1.1.1)
23
+ net-http-persistent (~> 2.5, >= 2.5.2)
24
+ nokogiri (~> 1.4)
25
+ ntlm-http (~> 0.1, >= 0.1.1)
26
+ webrobots (>= 0.0.9, < 0.2)
27
+ mime-types (1.23)
28
+ net-http-digest_auth (1.3)
29
+ net-http-persistent (2.8)
16
30
  nokogiri (1.5.9)
31
+ ntlm-http (0.1.1)
17
32
  rake (10.0.3)
33
+ unf (0.1.1)
34
+ unf_ext
35
+ unf_ext (0.0.6)
18
36
  vcr (2.4.0)
19
37
  webmock (1.11.0)
20
38
  addressable (>= 2.2.7)
21
39
  crack (>= 0.3.2)
40
+ webrobots (0.1.1)
22
41
 
23
42
  PLATFORMS
24
43
  ruby
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # Russian Post Tools
2
2
 
3
3
  [![Code Climate](https://codeclimate.com/github/t3hk0d3/russian_post.png)](https://codeclimate.com/github/t3hk0d3/russian_post)
4
+ [![Build Status](https://travis-ci.org/t3hk0d3/russian_post.png?branch=master)](https://travis-ci.org/t3hk0d3/russian_post)
5
+ [![Dependency Status](https://gemnasium.com/t3hk0d3/russian_post.png)](https://gemnasium.com/t3hk0d3/russian_post)
4
6
 
5
7
  ## Installation
6
8
 
@@ -38,7 +38,6 @@ module RussianPost
38
38
  end
39
39
 
40
40
  def recognize!
41
-
42
41
  captcha_image = grayscale(image)
43
42
 
44
43
  results = {}
@@ -63,7 +62,8 @@ module RussianPost
63
62
  end
64
63
 
65
64
  def prepare_text(results)
66
- results.map(&:character).join('')
65
+ captcha_text = results.map(&:character).join('')
66
+ captcha_text.size == 5 ? captcha_text : raise("Unable to recognize captcha")
67
67
  end
68
68
 
69
69
  def grayscale(captcha_image)
@@ -96,4 +96,4 @@ module RussianPost
96
96
 
97
97
  end
98
98
 
99
- end
99
+ end
@@ -1,114 +1,77 @@
1
- require 'excon'
2
- require 'nokogiri'
1
+ require 'mechanize'
3
2
 
4
3
  require 'time'
5
- require 'cgi'
6
4
 
7
5
  module RussianPost
8
6
 
9
7
  class Tracking
10
8
 
11
- TRACKING_PAGE = 'http://www.russianpost.ru/rp/servise/ru/home/postuslug/trackingpo'
9
+ attr_reader :barcode, :agent
12
10
 
11
+ TRACKING_PAGE = 'http://www.russianpost.ru/rp/servise/ru/home/postuslug/trackingpo'
12
+ COLUMNS = [:type, :date, :zip_code, :location, :message, :weight, :declared_cost,
13
+ :delivery_cash, :destination_zip_code, :destination_location]
14
+
13
15
  def initialize(tracking_code)
14
- @code = tracking_code.strip
16
+ @barcode = tracking_code.strip.upcase
17
+ @agent = Mechanize.new
15
18
  end
16
19
 
17
20
  def track
18
- # fetch form
19
- response = fetch(TRACKING_PAGE)
20
-
21
- tracking_form = response.body
22
-
23
- tracking_params = {}
24
-
25
- tracking_form.scan(/\<input ([^\>]+)\>/) do |result|
26
- param = Hash[result.first.scan(/(name|value)=(?:"|')([^\"\']+)(?:"|')/)]
27
-
28
- tracking_params[param['name']] = param['value']
29
- end
30
-
31
- action_path = if tracking_form =~ /\<form .* action=\"([^\"]+)\"/
32
- $1
33
- else
34
- raise "Unable to extract form path"
35
- end
36
-
37
- captcha_url = if tracking_form =~ /<img id='captchaImage' src='([^\']+)'/
38
- $1
39
- else
40
- raise "Unable to extract captcha image url"
41
- end
42
-
43
- captcha = RussianPost::Captcha.for_url(captcha_url)
44
-
45
- raise "Unable to recognize captcha" unless captcha.valid?
46
-
47
- tracking_params['BarCode'] = @code
48
- tracking_params['InputedCaptchaCode'] = captcha.text
49
- tracking_params['searchsign'] = '1'
50
-
51
- cookies = Hash[response.headers['Set-Cookie'].scan(/([^\=\;]+)=([^\;]+)[^\,]*,*/).map { |name, value| [name.strip, value.strip] }]
52
- cookies.delete("path")
53
- cookies = cookies.map { |name, value| "#{name}=#{value}"}.join("; ")
54
-
55
- request_data = encode_params(tracking_params)
56
-
57
- response = Excon.post('http://www.russianpost.ru' + action_path,
58
- :headers => {'Cookie' => cookies,
59
- 'User-Agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22',
60
- 'Referer' => 'http://www.russianpost.ru/resp_engine.aspx?Path=rp/servise/ru/home/postuslug/trackingpo',\
61
- 'Origin' => 'http://www.russianpost.ru',
62
- 'Content-Type' => 'application/x-www-form-urlencoded',
63
- 'Content-Length' => request_data.size
64
- },
65
- :body => request_data)
21
+ initial_page = fetch_initial_page
22
+ tracking_page = fetch_tracking_data(initial_page)
23
+ parse_tracking_table(tracking_table(tracking_page))
24
+ end
66
25
 
67
- if response.body =~ /<table class="pagetext">(.+)<\/table>/
68
- doc = Nokogiri::HTML::Document.parse(response.body)
26
+ private
69
27
 
70
- columns = [:type, :date, :zip_code, :location, :message, :weight, :declared_cost, :delivery_cash, :destination_zip_code, :destination_location]
28
+ def solve_captcha(page)
29
+ RussianPost::Captcha.for_url(get_captcha_url(page)).text
30
+ end
71
31
 
72
- rows = []
73
- doc.css('table.pagetext tr').each do |row|
74
- data = row.css('td').map(&:text).map { |text| !['-', ''].include?(text) ? text : nil }
32
+ def get_captcha_url(page)
33
+ page.images.last.src
34
+ end
75
35
 
76
- next if data.empty?
36
+ def tracking_table(page)
37
+ table = page.search(".pagetext tbody tr")
38
+ table ? table : raise("No tracking table found")
39
+ end
77
40
 
78
- hash = Hash[columns.zip(data)]
79
- hash[:date] = Time.parse(hash[:date])
41
+ def parse_tracking_table(table)
42
+ table.map { |e| parse_row(e) }
43
+ end
80
44
 
81
- rows << hash
82
- end
45
+ def parse_row(row)
46
+ data = get_row_data(row)
47
+ data[1] = Time.parse("#{data[1]} +04:00")
83
48
 
84
- return rows
85
- else
86
- raise "No tracks table in response"
87
- end
49
+ Hash[COLUMNS.zip(data)]
88
50
  end
89
51
 
90
- private
91
-
92
- def encode_params(params)
93
- params.map do |name, value|
94
- "#{CGI.escape(name.to_s)}=#{CGI.escape(value.to_s)}"
95
- end.join('&')
52
+ def get_row_data(row)
53
+ row.css('td').map { |td| td.text unless ['-', ''].include?(td.text) }
96
54
  end
97
55
 
98
- def fetch(url)
99
- response = Excon.get(url)
100
- if response.body =~ /<input id=\"key\" name=\"key\" value=\"([0-9]+)\"\/>/ # tough security huh
101
- response = Excon.post(url, body: "key=#{$1}")
102
- end
56
+ def fetch_initial_page
57
+ page = agent.get(TRACKING_PAGE)
58
+ bypass_security(page) or page
59
+ end
103
60
 
104
- if response.body.include?("window.location.replace(window.location.toString())") # hehe
105
- puts "foo"
106
- response = fetch(url)
61
+ def bypass_security(page)
62
+ if page.form.has_field?("key")
63
+ page.form.submit
64
+ elsif page.body.include?("window.location.replace(window.location.toString())")
65
+ fetch_initial_page
107
66
  end
108
-
109
- response
110
67
  end
111
68
 
69
+ def fetch_tracking_data(page)
70
+ page.form.set_fields(
71
+ 'BarCode' => barcode,
72
+ 'InputedCaptchaCode' => solve_captcha(page),
73
+ 'searchsign' => '1')
74
+ page.form.submit
75
+ end
112
76
  end
113
-
114
- end
77
+ end
@@ -1,3 +1,3 @@
1
1
  module RussianPost
2
- VERSION = "0.1.0"
3
- end
2
+ VERSION = "0.1.1"
3
+ end
data/russian_post.gemspec CHANGED
@@ -21,6 +21,7 @@ Gem::Specification.new do |spec|
21
21
  spec.add_dependency "excon", "~> 0.20"
22
22
  spec.add_dependency "chunky_png", "~> 1.2"
23
23
  spec.add_dependency "nokogiri", "~> 1.5"
24
+ spec.add_dependency "mechanize", "~> 2.6.0"
24
25
 
25
26
  spec.add_development_dependency "bundler", "~> 1.3"
26
27
  spec.add_development_dependency "rake"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: russian_post
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-04-25 00:00:00.000000000 Z
12
+ date: 2013-04-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: excon
@@ -59,6 +59,22 @@ dependencies:
59
59
  - - ~>
60
60
  - !ruby/object:Gem::Version
61
61
  version: '1.5'
62
+ - !ruby/object:Gem::Dependency
63
+ name: mechanize
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: 2.6.0
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: 2.6.0
62
78
  - !ruby/object:Gem::Dependency
63
79
  name: bundler
64
80
  requirement: !ruby/object:Gem::Requirement
@@ -132,6 +148,7 @@ extensions: []
132
148
  extra_rdoc_files: []
133
149
  files:
134
150
  - .gitignore
151
+ - .travis.yml
135
152
  - Gemfile
136
153
  - Gemfile.lock
137
154
  - README.md