crowd_finder 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 +7 -0
- data/crowd_finder..gemspec +27 -0
- data/lib/abstract_interface.rb +26 -0
- data/lib/base_finder.rb +80 -0
- data/lib/crowd_finder.rb +17 -0
- data/lib/finders_factory.rb +17 -0
- data/lib/headstart_finder.rb +49 -0
- data/lib/kickstarter_finder.rb +48 -0
- data/lib/sites_module.rb +34 -0
- data/test/test.rb +2 -0
- metadata +138 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 70826c47d3675b7abbc6e1c0cf6ad55cba6c2d94
|
4
|
+
data.tar.gz: b6a01b53df7d5c1bebe4b85142da1f5c14d9b229
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: bddb08a1602e106b7976aa20026ea098612af030c37fdd1cb29525a3a9435894a8efb976b1e7db5940219e8cabe5aff2cd8b3b636f40f881c888a370d3f28157
|
7
|
+
data.tar.gz: 4be035ccbd91d26a145d2128c488c54258b488c2140e71fcf42ad7395df2015911afe45dcb8fe006654c364a2a215385244247ca0c3de797ef583e2633855c7e
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "crowd_finder"
|
7
|
+
spec.version = "0.0.1"
|
8
|
+
spec.authors = ["Daniel Ziv"]
|
9
|
+
spec.email = ["Daniel@shake.cards"]
|
10
|
+
spec.description = %q{Get all the data you need from crowdfunding campaigns}
|
11
|
+
spec.summary = %q{Crowd funding sites scraper}
|
12
|
+
spec.homepage = "https://github.com/DanielRasta/crowd_finder"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files`.split($/)
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_development_dependency 'json'
|
21
|
+
spec.add_development_dependency 'time'
|
22
|
+
spec.add_development_dependency 'open-uri'
|
23
|
+
spec.add_development_dependency 'open_uri_redirections'
|
24
|
+
spec.add_development_dependency 'nokogiri'
|
25
|
+
spec.add_development_dependency 'uri'
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
###
|
2
|
+
# Influenced by this great tutorial
|
3
|
+
# http://metabates.com/2011/02/07/building-interfaces-and-abstract-classes-in-ruby/
|
4
|
+
###
|
5
|
+
|
6
|
+
module AbstractInterface
|
7
|
+
|
8
|
+
class InterfaceNotImplementedError < NoMethodError
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.included(klass)
|
12
|
+
klass.send(:include, AbstractInterface::Methods)
|
13
|
+
klass.send(:extend, AbstractInterface::Methods)
|
14
|
+
end
|
15
|
+
|
16
|
+
module Methods
|
17
|
+
|
18
|
+
def api_not_implemented(klass)
|
19
|
+
caller.first.match(/in \`(.+)\'/)
|
20
|
+
method_name = $1
|
21
|
+
raise AbstractInterface::InterfaceNotImplementedError.new("#{klass.class.name} needs to implement '#{method_name}' for interface #{self.name}!")
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
data/lib/base_finder.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
require "abstract_interface"
|
2
|
+
require "sites_module"
|
3
|
+
require 'json'
|
4
|
+
require 'time'
|
5
|
+
|
6
|
+
class BaseFinder
|
7
|
+
include AbstractInterface
|
8
|
+
|
9
|
+
# Members
|
10
|
+
|
11
|
+
@url = ""
|
12
|
+
@body = ""
|
13
|
+
|
14
|
+
# Base
|
15
|
+
|
16
|
+
def set(new_value)
|
17
|
+
@url = new_value
|
18
|
+
@body = Sites::get_html(new_value)
|
19
|
+
end
|
20
|
+
|
21
|
+
def reload
|
22
|
+
@body = Sites::get_html(@url)
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_json
|
26
|
+
my_hash = {:name => project_name,
|
27
|
+
:precentage => precentage,
|
28
|
+
:deadline => deadline,
|
29
|
+
:days_to_go => days_to_go,
|
30
|
+
:backers_count => num_of_backers,
|
31
|
+
:twitter_link => twitter_link,
|
32
|
+
:pledged => pledged,
|
33
|
+
:goal => goal}
|
34
|
+
return JSON.generate(my_hash)
|
35
|
+
rescue => e
|
36
|
+
""
|
37
|
+
end
|
38
|
+
|
39
|
+
# Calculated
|
40
|
+
|
41
|
+
def precentage
|
42
|
+
p = pledged.gsub!(/[^0-9A-Za-z]/, '').to_f
|
43
|
+
g = goal.gsub!(/[^0-9A-Za-z]/, '').to_f
|
44
|
+
((p/g)*100).round
|
45
|
+
rescue => e
|
46
|
+
""
|
47
|
+
end
|
48
|
+
|
49
|
+
def days_to_go
|
50
|
+
((deadline - Time.new)/(60*60*24)).floor
|
51
|
+
rescue => e
|
52
|
+
""
|
53
|
+
end
|
54
|
+
|
55
|
+
# Implementation
|
56
|
+
|
57
|
+
def project_name
|
58
|
+
BaseFinder.api_not_implemented(self)
|
59
|
+
end
|
60
|
+
|
61
|
+
def num_of_backers
|
62
|
+
BaseFinder.api_not_implemented(self)
|
63
|
+
end
|
64
|
+
|
65
|
+
def twitter_link
|
66
|
+
BaseFinder.api_not_implemented(self)
|
67
|
+
end
|
68
|
+
|
69
|
+
def pledged
|
70
|
+
BaseFinder.api_not_implemented(self)
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_print
|
74
|
+
BaseFinder.api_not_implemented(self)
|
75
|
+
end
|
76
|
+
|
77
|
+
def goal
|
78
|
+
BaseFinder.api_not_implemented(self)
|
79
|
+
end
|
80
|
+
end
|
data/lib/crowd_finder.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# CrowdFinder.new('http://www.headstart.co.il/project.aspx?id=18568')
|
2
|
+
|
3
|
+
|
4
|
+
require "finders_factory"
|
5
|
+
require "sites_module"
|
6
|
+
|
7
|
+
|
8
|
+
module CrowdFinder
|
9
|
+
def self.new(url)
|
10
|
+
unless Sites::valid?(url)
|
11
|
+
raise "#{url} is invalid URL"
|
12
|
+
else
|
13
|
+
site_name = Sites::get_site_name(url)
|
14
|
+
findr = FindersFactory.build(site_name.to_sym,url)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require "kickstarter_finder"
|
2
|
+
require "headstart_finder"
|
3
|
+
|
4
|
+
class FindersFactory
|
5
|
+
|
6
|
+
def self.build(p_shape,p_url)
|
7
|
+
case p_shape
|
8
|
+
when :kickstarter
|
9
|
+
ret_class = KickstarterFinder.new
|
10
|
+
when :headstart
|
11
|
+
ret_class = HeadstartFinder.new
|
12
|
+
end
|
13
|
+
|
14
|
+
ret_class.set(p_url)
|
15
|
+
return ret_class
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'base_finder'
|
2
|
+
|
3
|
+
class HeadstartFinder < BaseFinder
|
4
|
+
|
5
|
+
def test_print
|
6
|
+
"I'm #{self.class.name} and my url is #{@url}"
|
7
|
+
rescue => e
|
8
|
+
""
|
9
|
+
end
|
10
|
+
|
11
|
+
def project_name
|
12
|
+
@body.css('.leftpanel')[0].css('h1').text.gsub("\n", ' ').squeeze(' ')
|
13
|
+
rescue => e
|
14
|
+
""
|
15
|
+
end
|
16
|
+
|
17
|
+
def days_to_go
|
18
|
+
@body.css('.projectstatus').css('.bb').css('.l').css('div')[0].text.gsub("\n", ' ').gsub("\r", ' ').squeeze(' ')
|
19
|
+
rescue => e
|
20
|
+
""
|
21
|
+
end
|
22
|
+
|
23
|
+
def deadline
|
24
|
+
"N/A"
|
25
|
+
end
|
26
|
+
|
27
|
+
def num_of_backers
|
28
|
+
@body.css('.projectstatus').css('.bb').css('.r').css('.t1').text.gsub("\n", ' ').gsub("\r", ' ').squeeze(' ')
|
29
|
+
rescue => e
|
30
|
+
""
|
31
|
+
end
|
32
|
+
|
33
|
+
def twitter_link
|
34
|
+
""
|
35
|
+
end
|
36
|
+
|
37
|
+
def pledged
|
38
|
+
@body.css('.projectstatus').css('.cu').text.gsub('\n', '').gsub("\n", ' ').gsub("\r", ' ').squeeze(' ')
|
39
|
+
rescue => e
|
40
|
+
""
|
41
|
+
end
|
42
|
+
|
43
|
+
def goal
|
44
|
+
@body.css('.projectstatus').css('.pl').text.gsub('\n', '').gsub("\n", ' ').gsub("\r", ' ').squeeze(' ')
|
45
|
+
rescue => e
|
46
|
+
""
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'base_finder'
|
2
|
+
|
3
|
+
class KickstarterFinder < BaseFinder
|
4
|
+
|
5
|
+
def test_print
|
6
|
+
"I'm #{self.class.name} and my url is #{@url}"
|
7
|
+
rescue => e
|
8
|
+
""
|
9
|
+
end
|
10
|
+
|
11
|
+
def project_name
|
12
|
+
@body.css('title')[0].text
|
13
|
+
rescue => e
|
14
|
+
""
|
15
|
+
end
|
16
|
+
|
17
|
+
def num_of_backers
|
18
|
+
@body.css('div#backers_count').text.to_i
|
19
|
+
rescue => e
|
20
|
+
""
|
21
|
+
end
|
22
|
+
|
23
|
+
def twitter_link
|
24
|
+
@body.css('.js-twitter-share')[0]['href']
|
25
|
+
rescue => e
|
26
|
+
""
|
27
|
+
end
|
28
|
+
|
29
|
+
def pledged
|
30
|
+
@body.css('.stat-item')[1].css('data').text
|
31
|
+
rescue => e
|
32
|
+
""
|
33
|
+
end
|
34
|
+
|
35
|
+
def goal
|
36
|
+
@body.css('.stat-item')[1].css('.money').text
|
37
|
+
rescue => e
|
38
|
+
""
|
39
|
+
end
|
40
|
+
|
41
|
+
# Override
|
42
|
+
|
43
|
+
def deadline
|
44
|
+
Time.parse(@body.css('.ksr_page_timer')[0]["data-end_time"])
|
45
|
+
rescue => e
|
46
|
+
""
|
47
|
+
end
|
48
|
+
end
|
data/lib/sites_module.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
###
|
2
|
+
# Good guide
|
3
|
+
# http://ruby.bastardsbook.com/chapters/html-parsing/
|
4
|
+
###
|
5
|
+
|
6
|
+
require 'open-uri'
|
7
|
+
require 'open_uri_redirections'
|
8
|
+
require 'nokogiri'
|
9
|
+
require 'uri'
|
10
|
+
|
11
|
+
|
12
|
+
module Sites
|
13
|
+
def self.get_html(p_url)
|
14
|
+
if valid?(p_url)
|
15
|
+
source = open(p_url, :allow_redirections => :safe){|f|f.read}
|
16
|
+
page = Nokogiri::HTML(source)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.valid?(url)
|
21
|
+
uri = URI.parse(url)
|
22
|
+
uri.kind_of?(URI::HTTP)
|
23
|
+
rescue URI::InvalidURIError
|
24
|
+
false
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.get_site_name(url)
|
28
|
+
full_url = URI.parse(url).host.downcase
|
29
|
+
full_url.split(".")[1].downcase
|
30
|
+
rescue URI::InvalidURIError
|
31
|
+
""
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
data/test/test.rb
ADDED
metadata
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: crowd_finder
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Daniel Ziv
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-04-20 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: json
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: time
|
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
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: open-uri
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: open_uri_redirections
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: nokogiri
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: uri
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
description: Get all the data you need from crowdfunding campaigns
|
98
|
+
email:
|
99
|
+
- Daniel@shake.cards
|
100
|
+
executables: []
|
101
|
+
extensions: []
|
102
|
+
extra_rdoc_files: []
|
103
|
+
files:
|
104
|
+
- crowd_finder..gemspec
|
105
|
+
- lib/abstract_interface.rb
|
106
|
+
- lib/base_finder.rb
|
107
|
+
- lib/crowd_finder.rb
|
108
|
+
- lib/finders_factory.rb
|
109
|
+
- lib/headstart_finder.rb
|
110
|
+
- lib/kickstarter_finder.rb
|
111
|
+
- lib/sites_module.rb
|
112
|
+
- test/test.rb
|
113
|
+
homepage: https://github.com/DanielRasta/crowd_finder
|
114
|
+
licenses:
|
115
|
+
- MIT
|
116
|
+
metadata: {}
|
117
|
+
post_install_message:
|
118
|
+
rdoc_options: []
|
119
|
+
require_paths:
|
120
|
+
- lib
|
121
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - '>='
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0'
|
131
|
+
requirements: []
|
132
|
+
rubyforge_project:
|
133
|
+
rubygems_version: 2.0.14
|
134
|
+
signing_key:
|
135
|
+
specification_version: 4
|
136
|
+
summary: Crowd funding sites scraper
|
137
|
+
test_files:
|
138
|
+
- test/test.rb
|