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.
@@ -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
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # require_relative '../config/environment'
4
+
5
+ require 'bundler/setup'
6
+ require 'meetup_scraper'
7
+
8
+ # launch cli app
9
+ MeetupScraper::CommandLineInterface.new.run
@@ -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
@@ -0,0 +1,3 @@
1
+ module MeetupScraper
2
+ VERSION = '0.3.0'
3
+ 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: []