wigle_api 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.rvmrc ADDED
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # This is an RVM Project .rvmrc file, used to automatically load the ruby
4
+ # development environment upon cd'ing into the directory
5
+
6
+ # First we specify our desired <ruby>[@<gemset>], the @gemset name is optional,
7
+ # Only full ruby name is supported here, for short names use:
8
+ # echo "rvm use 1.9.3" > .rvmrc
9
+ environment_id="ruby-1.9.3-p125@wigle-api"
10
+
11
+ # Uncomment the following lines if you want to verify rvm version per project
12
+ # rvmrc_rvm_version="1.11.3" # 1.10.1 seams as a safe start
13
+ # eval "$(echo ${rvm_version}.${rvmrc_rvm_version} | awk -F. '{print "[[ "$1*65536+$2*256+$3" -ge "$4*65536+$5*256+$6" ]]"}' )" || {
14
+ # echo "This .rvmrc file requires at least RVM ${rvmrc_rvm_version}, aborting loading."
15
+ # return 1
16
+ # }
17
+
18
+ # First we attempt to load the desired environment directly from the environment
19
+ # file. This is very fast and efficient compared to running through the entire
20
+ # CLI and selector. If you want feedback on which environment was used then
21
+ # insert the word 'use' after --create as this triggers verbose mode.
22
+ if [[ -d "${rvm_path:-$HOME/.rvm}/environments"
23
+ && -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]]
24
+ then
25
+ \. "${rvm_path:-$HOME/.rvm}/environments/$environment_id"
26
+ [[ -s "${rvm_path:-$HOME/.rvm}/hooks/after_use" ]] &&
27
+ \. "${rvm_path:-$HOME/.rvm}/hooks/after_use" || true
28
+ else
29
+ # If the environment file has not yet been created, use the RVM CLI to select.
30
+ rvm --create "$environment_id" || {
31
+ echo "Failed to create RVM environment '${environment_id}'."
32
+ return 1
33
+ }
34
+ fi
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source :rubygems
2
+
3
+ gemspec
@@ -0,0 +1,28 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ coderay (1.0.7)
5
+ diff-lcs (1.1.3)
6
+ method_source (0.8)
7
+ nokogiri (1.5.5)
8
+ pry (0.9.10)
9
+ coderay (~> 1.0.5)
10
+ method_source (~> 0.8)
11
+ slop (~> 3.3.1)
12
+ rspec (2.11.0)
13
+ rspec-core (~> 2.11.0)
14
+ rspec-expectations (~> 2.11.0)
15
+ rspec-mocks (~> 2.11.0)
16
+ rspec-core (2.11.1)
17
+ rspec-expectations (2.11.2)
18
+ diff-lcs (~> 1.1.3)
19
+ rspec-mocks (2.11.2)
20
+ slop (3.3.2)
21
+
22
+ PLATFORMS
23
+ ruby
24
+
25
+ DEPENDENCIES
26
+ nokogiri
27
+ pry
28
+ rspec
data/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ Copyright (c) 2012 Sam Stelfox
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.
23
+
@@ -0,0 +1,48 @@
1
+ # WiGLE API
2
+ This gem was written to make use of WiGLE.net's wireless access point data. Currently WiGLE doen't provide and official API so this gem may break if they change their interface. This was written to make use of the data for a single small scale project for a public display and is no longer actively used and I have no intention of maintaining it (though it's fairly simple).
3
+
4
+ ## Usage
5
+ To make use of this you'll need to create an account on wigle.net (<http://wigle.net/gps/gps/main/register>). The following code example shows how to authenticate against the API and perform a simple search.
6
+
7
+ require "wigle\_api"
8
+
9
+ WigleApi.login("your-username", "your-password")
10
+ WigleApi.where(ssid: "linksys").each do |ap|
11
+ puts ap[:ssid] + ap[:statecode]
12
+ end
13
+
14
+ WigleApi.where(ssid: "linksys").offset(200).results
15
+
16
+ Results are returned as an array of hashes with symbols for keys. Each hash has all of the available fields that WiGLE returns in their search view. Only 100 results will be returned at a time though you can use the "pagestart" search value or the .offset(num) chained methods to iterate through more results. There unfortunately isn't a way to count the total number of results from a query at this time.
17
+
18
+ ## Available Search Parameters
19
+
20
+ * addresscode - Street address, max length 30
21
+ * statecode - Two character state code
22
+ * zipcode - Five character integer zip code, maxlength 5
23
+ * variance - The latitude/longitude variance in degrees, values available in the form: 0.001, 0.002, 0.005, 0.010 (default), 0.020, 0.050, 0.100, 0.200
24
+ * latrange1 - Begin latitude range, max length 14
25
+ * latrange2 - End latitude range, max length 14
26
+ * longrange1 - Begin longitude range, max length 14
27
+ * longrange2 - End longitude range, max length 14
28
+ * lastupdt - A timestamp used to filter based on the last time the access point database was updated in the format of 20010925174546
29
+ * netid - BSSID / AP Max Address, expects either just the colon delimited vendor code or a full MAC such as either 0A:2C:EF or 0A:2C:EF:3D:25:1B, max length 14
30
+ * ssid - SSID / Network Name, max length 50
31
+ * freenet - Must be a freenet (Not sure what that means), set the value to on to filter with this, should be excluded completely otherwise
32
+ * paynet - Must be a Commercial Pay Net (Not sure what that means either...), same deal with on to filter with this
33
+ * dhcp - Must have DHCP enabled, on again to filter with this...
34
+ * onlymine - Only search on the networks that the authenticated user has found
35
+ * pagestart - The search result offset
36
+
37
+ ## Personal Notes on WiGLE
38
+ While writing this Gem I got the distinct feeling that the operators of WiGLE.net aren't particularily friendly people. How they've managed to convince so many people to provide them with all this data is beyond me as they don't seem willing to return the favor of actually making the data available to their users.
39
+
40
+ From the many forum posts requesting an API it seem's like the owners of WiGLE don't want an official way to access the data in their database for one of the reasons below:
41
+
42
+ * They want to keep the data for themselves (possibly for commercial reasons)
43
+ * They don't want to spend the time/energy coding an actual API
44
+ * They are worried about bandwidth (and are not open to the idea of mirrors)
45
+ * They are simply (insert insult here)
46
+
47
+ Usually requests for making use of the data on the site are turned down rudely, and usually with various references to cats.
48
+
@@ -0,0 +1,38 @@
1
+ # encoding: utf-8
2
+
3
+ # Gem requirements
4
+ require "net/https"
5
+ require "nokogiri"
6
+ require "rubygems"
7
+ require "uri"
8
+
9
+ # Misc pieces of this gem
10
+ require "wigle_api/connection"
11
+ require "wigle_api/exceptions"
12
+ require "wigle_api/version"
13
+
14
+ # Web scraper portions
15
+ require "wigle_api/scraper/parser"
16
+ require "wigle_api/scraper/search"
17
+
18
+ # Web API portions
19
+
20
+ module WigleApi
21
+ WIGLE_URI = URI.parse("https://wigle.net/")
22
+ WIGLE_LOGIN_URL = "/gps/gps/main/login"
23
+ WIGLE_QUERY_URL = "/gps/gps/main/confirmquery/"
24
+
25
+ def self.login(username, password)
26
+ @connection ||= WigleApi::Connection.new
27
+ @connection.login(username, password)
28
+ end
29
+
30
+ def self.where(args)
31
+ WigleApi::Scraper::Search.new(args)
32
+ end
33
+ end
34
+
35
+ # How to use the web scraper (will only return 100 results):
36
+ # WigleApi.login("myusername", "mypassword")
37
+ # @results = WigleApi.where(ssid: "linksys").results
38
+
@@ -0,0 +1,60 @@
1
+ # encoding: utf-8
2
+
3
+ module WigleApi
4
+ class Connection
5
+ def self.new(*args)
6
+ @@instance ||= super
7
+ end
8
+
9
+ def initialize
10
+ @connection = Net::HTTP.new(WIGLE_URI.host, WIGLE_URI.port)
11
+ @connection.ca_file = "/etc/pki/tls/certs/ca-bundle.crt"
12
+ @connection.use_ssl = true
13
+ @connection.verify_mode = OpenSSL::SSL::VERIFY_PEER
14
+
15
+ @logged_in = false
16
+ end
17
+
18
+ def login(username, password)
19
+ return true if @logged_in
20
+
21
+ login_form_data = {
22
+ "credential_0" => username,
23
+ "credential_1" => password,
24
+ "destination" => "/gps/gps/main",
25
+ "noexpire" => "on",
26
+ }
27
+
28
+ response = post(WIGLE_LOGIN_URL, login_form_data)
29
+
30
+ if response["Set-Cookie"].nil?
31
+ return false
32
+ end
33
+
34
+ @auth_cookie = response["Set-Cookie"]
35
+ @logged_in = true
36
+ end
37
+
38
+ def search(data)
39
+ raise NotLoggedIn unless @logged_in
40
+
41
+ response = post(WIGLE_QUERY_URL, data)
42
+ end
43
+
44
+ private
45
+
46
+ def post(path, data)
47
+ request = Net::HTTP::Post.new(path)
48
+ request.initialize_http_header({
49
+ "User-Agent" => "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.57 Safari/537.1"
50
+ })
51
+ request.set_form_data(data)
52
+ request.add_field("Cookie", @auth_cookie) if @auth_cookie
53
+
54
+ @connection.start do |http|
55
+ http.request(request)
56
+ end
57
+ end
58
+ end
59
+ end
60
+
@@ -0,0 +1,7 @@
1
+ # encoding: utf-8
2
+
3
+ module WigleApi
4
+ class NotLoggedIn < Exception
5
+ end
6
+ end
7
+
@@ -0,0 +1,42 @@
1
+ # encoding: utf-8
2
+
3
+ module WigleApi
4
+ module Scraper
5
+ class Parser
6
+ def self.new(*args)
7
+ p = super
8
+ p.output
9
+ end
10
+
11
+ def initialize(html_body)
12
+ @parser = Nokogiri::HTML(html_body)
13
+
14
+ headers = parse_headers
15
+ results = parse_results
16
+
17
+ @output = results.map! { |r| Hash[headers.zip(r)] }
18
+ end
19
+
20
+ def output
21
+ @output
22
+ end
23
+
24
+ private
25
+
26
+ def parse_headers
27
+ @parser.css("th[@class='searchhead']").map do |node|
28
+ node.text.strip
29
+ end
30
+ end
31
+
32
+ def parse_results
33
+ @parser.css("tr[@class='search']").map do |sr|
34
+ sr.css("td").map do |v|
35
+ v.text.strip
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+
@@ -0,0 +1,102 @@
1
+ # encoding: utf-8
2
+
3
+ =begin
4
+ Descriptions of all the valid search options and information about them:
5
+
6
+ addresscode - Street address, max length 30
7
+ statecode - Two character state code
8
+ zipcode - Five character integer zip code, maxlength 5
9
+ variance - The latitude/longitude variance in degrees, values available in the form: 0.001, 0.002, 0.005, 0.010 (default), 0.020, 0.050, 0.100, 0.200
10
+ latrange1 - Begin latitude range, max length 14
11
+ latrange2 - End latitude range, max length 14
12
+ longrange1 - Begin longitude range, max length 14
13
+ longrange2 - End longitude range, max length 14
14
+ lastupdt - A timestamp used to filter based on the last time the access point database was updated in the format of 20010925174546
15
+ netid - BSSID / AP Max Address, expects either just the colon delimited vendor code or a full MAC such as either 0A:2C:EF or 0A:2C:EF:3D:25:1B, max length 14
16
+ ssid - SSID / Network Name, max length 50
17
+ freenet - Must be a freenet (Not sure what that means), set the value to on to filter with this, should be excluded completely otherwise
18
+ paynet - Must be a Commercial Pay Net (Not sure what that means either...), same deal with on to filter with this
19
+ dhcp - Must have DHCP enable, on again to filter with this...
20
+ onlymine - Only search on the networks that the authenticated user has found
21
+ pagestart - The search result offset
22
+ Query - This is the submit button...
23
+ =end
24
+
25
+ module WigleApi
26
+ module Scraper
27
+ class Search
28
+ def initialize(args)
29
+ @search_arguments = {
30
+ "variance" => "0.010",
31
+ "Query" => "Query"
32
+ }
33
+
34
+ @search_arguments.merge!(clean(args))
35
+ end
36
+
37
+ def offset(num)
38
+ @search_arguments.merge!(clean({pagestart: num}))
39
+ self
40
+ end
41
+
42
+ def where(args)
43
+ @search_arguments.merge!(clean(args))
44
+ self
45
+ end
46
+
47
+ def results
48
+ conn = WigleApi::Connection.new
49
+ response = conn.search(@search_arguments)
50
+
51
+ unless [200, 301, 302, 303].include?(response.code.to_i)
52
+ return nil
53
+ end
54
+
55
+ # Parse the response, then turn the keys into symbols
56
+ WigleApi::Scraper::Parser.new(response.body).map do |row|
57
+ row.inject({}) do |results, (key, value)|
58
+ results[key.to_sym] = value.to_s
59
+ results
60
+ end
61
+ end
62
+ end
63
+
64
+ def each
65
+ results.each { |r| yield(r) }
66
+ end
67
+
68
+ private
69
+
70
+ def clean(options)
71
+ options = options.inject({}) do |opt, (key, value)|
72
+ opt[key.to_s] = value.to_s
73
+ opt
74
+ end
75
+
76
+ options.delete_if { |k,v| !valid_keys.include?(k) }
77
+ end
78
+
79
+ def valid_keys
80
+ [
81
+ "addresscode",
82
+ "statecode",
83
+ "zipcode",
84
+ "variance",
85
+ "latrange1",
86
+ "latrange2",
87
+ "longrange1",
88
+ "longrange2",
89
+ "lastupdt",
90
+ "netid",
91
+ "ssid",
92
+ "freenet",
93
+ "paynet",
94
+ "dhcp",
95
+ "onlymine",
96
+ "pagestart",
97
+ ]
98
+ end
99
+ end
100
+ end
101
+ end
102
+
@@ -0,0 +1,6 @@
1
+ # encoding: utf-8
2
+
3
+ module WigleApi
4
+ VERSION = "1.0.0"
5
+ end
6
+
@@ -0,0 +1,5 @@
1
+ #!/bin/bash
2
+
3
+ # Run the console with all the code loaded
4
+ pry -I "./lib" -r "./lib/wigle_api"
5
+
@@ -0,0 +1,8 @@
1
+ # encoding: utf-8
2
+
3
+ require "rubygems"
4
+ require "../lib/wigle_api"
5
+
6
+ RSpec.configure do |config|
7
+ end
8
+
@@ -0,0 +1,29 @@
1
+ # encoding: utf-8
2
+
3
+ $:.push(File.expand_path(File.dirname(__FILE__) + '/lib'))
4
+ require "wigle_api/version"
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "wigle_api"
8
+ gem.version = WigleApi::VERSION
9
+ gem.authors = ["Sam Stelfox"]
10
+ gem.email = ["sstelfox+rubygems@bedroomprogrammers.net"]
11
+ gem.homepage = "https://github.com/sstelfox/wigle_api"
12
+ gem.license = "MIT"
13
+
14
+ gem.summary = "An 'API' for WiGLE.net"
15
+ gem.description = "Provides an easy way to scrape WiGLE.net for small amounts of data."
16
+
17
+ gem.rubyforge_project = "wigle_api"
18
+
19
+ gem.files = `git ls-files`.split($\)
20
+ gem.test_files = gem.files.grep(%r{^spec/})
21
+ gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
22
+ gem.require_paths = ["lib"]
23
+
24
+ gem.add_runtime_dependency "nokogiri"
25
+ gem.add_development_dependency "rspec"
26
+
27
+ gem.required_ruby_version = '>= 1.9.2'
28
+ end
29
+
metadata ADDED
@@ -0,0 +1,93 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: wigle_api
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Sam Stelfox
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-08-30 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: nokogiri
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rspec
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ description: Provides an easy way to scrape WiGLE.net for small amounts of data.
47
+ email:
48
+ - sstelfox+rubygems@bedroomprogrammers.net
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - .rvmrc
54
+ - Gemfile
55
+ - Gemfile.lock
56
+ - LICENSE
57
+ - README.md
58
+ - lib/wigle_api.rb
59
+ - lib/wigle_api/connection.rb
60
+ - lib/wigle_api/exceptions.rb
61
+ - lib/wigle_api/scraper/parser.rb
62
+ - lib/wigle_api/scraper/search.rb
63
+ - lib/wigle_api/version.rb
64
+ - ruby-console
65
+ - spec/spec_helper.rb
66
+ - wigle_api.gemspec
67
+ homepage: https://github.com/sstelfox/wigle_api
68
+ licenses:
69
+ - MIT
70
+ post_install_message:
71
+ rdoc_options: []
72
+ require_paths:
73
+ - lib
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - ! '>='
78
+ - !ruby/object:Gem::Version
79
+ version: 1.9.2
80
+ required_rubygems_version: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ requirements: []
87
+ rubyforge_project: wigle_api
88
+ rubygems_version: 1.8.21
89
+ signing_key:
90
+ specification_version: 3
91
+ summary: An 'API' for WiGLE.net
92
+ test_files:
93
+ - spec/spec_helper.rb