meetup-scraper 0.3.0
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/bin/meetup-scraper +9 -0
- data/lib/meetup_scraper.rb +10 -0
- data/lib/meetup_scraper/cli_methods.rb +67 -0
- data/lib/meetup_scraper/command_line_interface.rb +60 -0
- data/lib/meetup_scraper/event.rb +33 -0
- data/lib/meetup_scraper/scraper.rb +56 -0
- data/lib/meetup_scraper/version.rb +3 -0
- metadata +123 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a37c4116353ce45a88a7eea716edea6945ae71a6
|
4
|
+
data.tar.gz: 191296acf767851f93d8653d3d6c5f7817bb2204
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8da3ae74ffd9ca26efb24a5a8fdb886e90777c81f0231a63bd6510c99a29a00261290ac0eecb72e3837e42524aba6653039833fd4975083efe9dfb67e3dc5cd1
|
7
|
+
data.tar.gz: ddae8658a9ba283e8fffebfd61f71b30b196737749cf04dab3d822c1694d811f006954d81e147f460344ad40ec9315f417b726efe09f2482932578c7d4233886
|
data/bin/meetup-scraper
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
#require_relative './../config/environment'
|
2
|
+
|
3
|
+
require 'nokogiri'
|
4
|
+
require 'open-uri'
|
5
|
+
|
6
|
+
require_relative './meetup_scraper/version'
|
7
|
+
require_relative './meetup_scraper/cli_methods'
|
8
|
+
require_relative './meetup_scraper/command_line_interface'
|
9
|
+
require_relative './meetup_scraper/event'
|
10
|
+
require_relative './meetup_scraper/scraper'
|
@@ -0,0 +1,67 @@
|
|
1
|
+
class MeetupScraper::CliMethods
|
2
|
+
|
3
|
+
# capture user input returning search url
|
4
|
+
def get_user_input
|
5
|
+
puts 'Search Meetup.com for events in your local area'
|
6
|
+
puts 'Enter the meetup subject'
|
7
|
+
subject = gets.chomp
|
8
|
+
puts 'Enter your town'
|
9
|
+
town = gets.chomp
|
10
|
+
puts 'How many miles from your town are you willing to travel'
|
11
|
+
miles = gets.chomp.to_i
|
12
|
+
miles = 1 if miles == 0
|
13
|
+
|
14
|
+
base_url = 'https://www.meetup.com/find/events/?allMeetups=false&keywords='
|
15
|
+
"#{base_url}#{subject}&radius=#{miles}&userFreeForm=#{town}"
|
16
|
+
end
|
17
|
+
|
18
|
+
# fetch the meetup events
|
19
|
+
def search_meetup(url)
|
20
|
+
MeetupScraper::Scraper.fetch_meetup_list(url)
|
21
|
+
end
|
22
|
+
|
23
|
+
# create event instances
|
24
|
+
def create_events_from_hashes(event_hashes)
|
25
|
+
MeetupScraper::Event.create_from_collection(event_hashes)
|
26
|
+
end
|
27
|
+
|
28
|
+
# download the event's details
|
29
|
+
def fetch_event_details(url)
|
30
|
+
MeetupScraper::Scraper.fetch_event_details(url)
|
31
|
+
end
|
32
|
+
|
33
|
+
# print event detatils
|
34
|
+
def print_event(event)
|
35
|
+
puts '------------------------------'
|
36
|
+
puts "Title: #{event.title}"
|
37
|
+
puts "Organiser: #{event.organiser}"
|
38
|
+
puts "Date: #{event.date}"
|
39
|
+
puts "Time: #{event.time}"
|
40
|
+
puts "Number attending: #{event.num_attending}"
|
41
|
+
puts "Address: #{event.address}"
|
42
|
+
puts "Description: #{event.description}"
|
43
|
+
puts '------------------------------'
|
44
|
+
end
|
45
|
+
|
46
|
+
def pick_meetup_event
|
47
|
+
puts 'Enter the number of the event to view more details'
|
48
|
+
puts "Enter '0' to search again"
|
49
|
+
puts "To quit, enter 'exit'"
|
50
|
+
puts 'What would you like to do?'
|
51
|
+
gets.chomp
|
52
|
+
end
|
53
|
+
|
54
|
+
def print_events
|
55
|
+
MeetupScraper::Event.all.each_with_index do |event, i|
|
56
|
+
puts "------------------------------"
|
57
|
+
puts "#{i + 1}. #{event.title}"
|
58
|
+
puts "Organiser: #{event.organiser}"
|
59
|
+
puts "Date: #{event.date.slice(0, 10)}"
|
60
|
+
puts "Time: #{event.time}"
|
61
|
+
puts "Number attending: #{event.num_attending}"
|
62
|
+
puts "Url: #{event.url}"
|
63
|
+
puts "------------------------------"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
class MeetupScraper::CommandLineInterface
|
2
|
+
attr_reader :climethods
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@climethods = MeetupScraper::CliMethods.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def run
|
9
|
+
url = self.climethods.get_user_input
|
10
|
+
event_hashes = climethods.search_meetup(url)
|
11
|
+
climethods.create_events_from_hashes(event_hashes)
|
12
|
+
self.print_meetup_events
|
13
|
+
end
|
14
|
+
|
15
|
+
def print_meetup_events
|
16
|
+
events = MeetupScraper::Event.all
|
17
|
+
while events.size < 1
|
18
|
+
puts "Sorry, no matches found, try again."
|
19
|
+
puts '------------------------------------'
|
20
|
+
self.run
|
21
|
+
end
|
22
|
+
self.climethods.print_events
|
23
|
+
self.print_meetup_event
|
24
|
+
#self.run
|
25
|
+
end
|
26
|
+
|
27
|
+
def print_meetup_event
|
28
|
+
input = self.climethods.pick_meetup_event
|
29
|
+
if (input.to_i >= 1 && input.to_i <= MeetupScraper::Event.all.size)
|
30
|
+
event = MeetupScraper::Event.all[input.to_i - 1]
|
31
|
+
url = event.url
|
32
|
+
# down load event's details, update event attributes & print event
|
33
|
+
updated_details = self.climethods.fetch_event_details(url)
|
34
|
+
updated_event = event.update_event_attributes(updated_details)
|
35
|
+
self.climethods.print_event(updated_event)
|
36
|
+
self.run_again
|
37
|
+
elsif input == '0'
|
38
|
+
self.run
|
39
|
+
elsif input == 'exit'
|
40
|
+
puts 'Good bye!'
|
41
|
+
else
|
42
|
+
puts 'Selection not recognised, try again'
|
43
|
+
print_meetup_event
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def run_again
|
48
|
+
puts "Enter '1' to view listing again or '0' to search again"
|
49
|
+
input = gets.chomp
|
50
|
+
if input.to_i == 1
|
51
|
+
self.print_meetup_events
|
52
|
+
elsif input == '0'
|
53
|
+
self.run
|
54
|
+
else
|
55
|
+
puts 'Selection not recognised, try again'
|
56
|
+
run_again
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class MeetupScraper::Event
|
2
|
+
attr_accessor :title, :date, :time, :url, :num_attending, :organiser, :address, :description
|
3
|
+
@@all = []
|
4
|
+
|
5
|
+
def create_from_hash(event_hash)
|
6
|
+
event_hash.each do |k, v|
|
7
|
+
self.send("#{k}=", v)
|
8
|
+
end
|
9
|
+
save
|
10
|
+
self
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.create_from_collection(event_hashes)
|
14
|
+
self.all.clear
|
15
|
+
event_hashes.collect {|event_hash| self.new.create_from_hash(event_hash)}
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.all
|
19
|
+
@@all
|
20
|
+
end
|
21
|
+
|
22
|
+
def save
|
23
|
+
self.class.all << self
|
24
|
+
end
|
25
|
+
|
26
|
+
def update_event_attributes(event_hash)
|
27
|
+
event_hash.each do |k, v|
|
28
|
+
self.send("#{k}=", v)
|
29
|
+
end
|
30
|
+
self
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
=begin
|
2
|
+
url: 'https://www.meetup.com/find/events/?allMeetups=false&keywords=javascript&radius=2&userFreeform=London%2C+United+Kingdom'
|
3
|
+
=end
|
4
|
+
|
5
|
+
class MeetupScraper::Scraper
|
6
|
+
|
7
|
+
def self.fetch_meetup_list(url)
|
8
|
+
doc = Nokogiri::HTML(open(url))
|
9
|
+
items = doc.css('.searchResults .event-listing-container .event-listing')
|
10
|
+
|
11
|
+
items.collect do |item|
|
12
|
+
event = {}
|
13
|
+
title = item.css('.chunk a.event span').inner_text
|
14
|
+
if title != ''
|
15
|
+
event[:title] = title
|
16
|
+
event[:organiser] = item.css('.chunk .text--labelSecondary a span').inner_text
|
17
|
+
event[:url] = item.css('a').first.attr('href')
|
18
|
+
num_attending = item.css('.text--secondary .attendee-count').inner_text
|
19
|
+
event[:num_attending] = num_attending.strip.slice(0, 4).gsub(/[^\d]/, '')
|
20
|
+
end
|
21
|
+
time = item.css('.text--secondary time').text
|
22
|
+
if time != ''
|
23
|
+
event[:time] = time
|
24
|
+
event[:date] = item.css('time').attr('datetime').value
|
25
|
+
end
|
26
|
+
# event[:location] = item.css('.row-item')[1].css('.text--secondary a').text.strip
|
27
|
+
event
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.fetch_event_details(url)
|
32
|
+
doc = Nokogiri::HTML(open(url))
|
33
|
+
items = doc.css('#event-content')
|
34
|
+
event = {}
|
35
|
+
items.each do |item|
|
36
|
+
event[:date] = item.css('#event-when-display h3').text
|
37
|
+
event_start_time = item.css('#event-start-time span').text
|
38
|
+
event_end_time = item.css('#event-end-time span').text
|
39
|
+
if (event_end_time != nil && event_end_time != '') && (event_start_time != nil && event_start_time != '')
|
40
|
+
event[:time] = "#{event_start_time} to #{event_end_time}"
|
41
|
+
else
|
42
|
+
time = item.css('#event-when-display p').text
|
43
|
+
event[:time] = time if time != '' || time != nil
|
44
|
+
end
|
45
|
+
address = item.css('#event-where-display .event-where-address').text.gsub(/\(map\)/, '').strip
|
46
|
+
address = 'Signup to view address' if address == nil || address == ''
|
47
|
+
event[:address] = address
|
48
|
+
description_text = ''
|
49
|
+
paragraphs = item.css('#event-description-wrap p')
|
50
|
+
paragraphs.each {|p| description_text += p.text.gsub(/â\u0080¢/, '') + "\n"}
|
51
|
+
event[:description] = description_text.strip
|
52
|
+
end
|
53
|
+
event
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
metadata
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: meetup-scraper
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Bill Fero
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-08-06 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.15'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.15'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pry
|
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: 1.6.6.2
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 1.6.6.2
|
83
|
+
description: Search Meetup.com and scape the details of the latest meetups in your
|
84
|
+
area.
|
85
|
+
email:
|
86
|
+
- billfero@gmail.com
|
87
|
+
executables:
|
88
|
+
- meetup-scraper
|
89
|
+
extensions: []
|
90
|
+
extra_rdoc_files: []
|
91
|
+
files:
|
92
|
+
- bin/meetup-scraper
|
93
|
+
- lib/meetup_scraper.rb
|
94
|
+
- lib/meetup_scraper/cli_methods.rb
|
95
|
+
- lib/meetup_scraper/command_line_interface.rb
|
96
|
+
- lib/meetup_scraper/event.rb
|
97
|
+
- lib/meetup_scraper/scraper.rb
|
98
|
+
- lib/meetup_scraper/version.rb
|
99
|
+
homepage: https://github.com/theBoyMo/ruby-web-scraping-cli-app
|
100
|
+
licenses:
|
101
|
+
- MIT
|
102
|
+
metadata: {}
|
103
|
+
post_install_message:
|
104
|
+
rdoc_options: []
|
105
|
+
require_paths:
|
106
|
+
- lib
|
107
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0'
|
117
|
+
requirements: []
|
118
|
+
rubyforge_project:
|
119
|
+
rubygems_version: 2.4.8
|
120
|
+
signing_key:
|
121
|
+
specification_version: 4
|
122
|
+
summary: Scrape Meetup.com site.
|
123
|
+
test_files: []
|