├── lib ├── .gitkeep ├── fetch_messages.rb ├── fetch_content.rb ├── user_messages.rb ├── fetch_movie.rb └── scraper.rb ├── .rspec ├── images ├── scraper1.png ├── scraper2.png └── scraper3.png ├── Gemfile ├── bin └── main.rb ├── .github └── workflows │ └── linters.yml ├── spec ├── fetch_movie_spec.rb ├── fetch_content_spec.rb └── spec_helper.rb ├── Gemfile.lock ├── .rubocop.yml └── README.md /lib/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --require spec_helper 2 | -------------------------------------------------------------------------------- /images/scraper1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RNtaate/Web_Scraper/HEAD/images/scraper1.png -------------------------------------------------------------------------------- /images/scraper2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RNtaate/Web_Scraper/HEAD/images/scraper2.png -------------------------------------------------------------------------------- /images/scraper3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RNtaate/Web_Scraper/HEAD/images/scraper3.png -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'nokogiri' 4 | gem 'rubocop', '~>0.81.0' 5 | -------------------------------------------------------------------------------- /bin/main.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require_relative '../lib/scraper.rb' 3 | 4 | sm = Scraper.new 5 | 6 | sm.run 7 | -------------------------------------------------------------------------------- /lib/fetch_messages.rb: -------------------------------------------------------------------------------- 1 | module FetchMessages 2 | MAIN_LINK = 'https://www.netflix.com/ug/browse/genre/34399'.freeze 3 | CATEGORY_NAME = 'h2.nm-collections-row-name'.freeze 4 | CATEGORY_SECTION = 'ul.nm-content-horizontal-row-item-container'.freeze 5 | MOVIE_TITLE = 'h1.title-title'.freeze 6 | MOVIE_OVERVIEW = 'div.title-info-synopsis'.freeze 7 | MOVIE_STARS = 'span.title-data-info-item-list'.freeze 8 | MOVIE_DURATION = 'span.duration'.freeze 9 | MOVIE_YEAR = 'span.item-year'.freeze 10 | MOVIE_GENRE = 'a.item-genre'.freeze 11 | MOVIE_AGE = 'span.maturity-number'.freeze 12 | end 13 | -------------------------------------------------------------------------------- /lib/fetch_content.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'nokogiri' 3 | require 'open-uri' 4 | require_relative 'fetch_messages.rb' 5 | 6 | class FetchContent 7 | def self.get_content(main_link, *selectors) 8 | doc = Nokogiri::HTML(URI.open(main_link)) 9 | list = doc.css(*selectors) 10 | list 11 | end 12 | 13 | def self.get_inner_content(list, number, selector) 14 | another_list = list[number].css(selector) 15 | another_list 16 | end 17 | 18 | def self.validate_input(list, number) 19 | return true if (1..list.length).include? number 20 | 21 | false 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /.github/workflows/linters.yml: -------------------------------------------------------------------------------- 1 | name: Linters 2 | 3 | on: pull_request 4 | 5 | jobs: 6 | rubocop: 7 | name: Rubocop 8 | runs-on: ubuntu-18.04 9 | steps: 10 | - uses: actions/checkout@v2 11 | - uses: actions/setup-ruby@v1 12 | with: 13 | ruby-version: 2.6.x 14 | - name: Setup Rubocop 15 | run: | 16 | gem install --no-document rubocop:'~>0.81.0' # https://docs.rubocop.org/en/stable/installation/ 17 | [ -f .rubocop.yml ] || wget https://raw.githubusercontent.com/microverseinc/linters-config/master/ruby/.rubocop.yml 18 | - name: Rubocop Report 19 | run: rubocop --color -------------------------------------------------------------------------------- /spec/fetch_movie_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rspec' 2 | require './lib/fetch_movie.rb' 3 | require 'nokogiri' 4 | require 'open-uri' 5 | 6 | describe Movie do 7 | let(:web_link) do 8 | 'https://rawcdn.githack.com/RNtaate/Sound-Electronics-store/ccadeae6e3e1eda77681a48f5f835e974dddcbd5/index.html' 9 | end 10 | 11 | describe '#display_movie_content' do 12 | context 'When given a webpage link string as an argument' do 13 | it 'Returns a string containing contents of elements from various NodeSets' do 14 | movie = Movie.new 15 | expect(movie.display_movie_content(web_link)).to be_a String 16 | end 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | ast (2.4.1) 5 | jaro_winkler (1.5.4) 6 | mini_portile2 (2.4.0) 7 | nokogiri (1.10.10) 8 | mini_portile2 (~> 2.4.0) 9 | parallel (1.19.2) 10 | parser (2.7.1.4) 11 | ast (~> 2.4.1) 12 | rainbow (3.0.0) 13 | rexml (3.2.4) 14 | rubocop (0.81.0) 15 | jaro_winkler (~> 1.5.1) 16 | parallel (~> 1.10) 17 | parser (>= 2.7.0.1) 18 | rainbow (>= 2.2.2, < 4.0) 19 | rexml 20 | ruby-progressbar (~> 1.7) 21 | unicode-display_width (>= 1.4.0, < 2.0) 22 | ruby-progressbar (1.10.1) 23 | unicode-display_width (1.7.0) 24 | 25 | PLATFORMS 26 | ruby 27 | 28 | DEPENDENCIES 29 | nokogiri 30 | rubocop (~> 0.81.0) 31 | 32 | BUNDLED WITH 33 | 2.1.4 34 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | AllCops: 2 | Exclude: 3 | - "Guardfile" 4 | - "Rakefile" 5 | 6 | DisplayCopNames: true 7 | 8 | Layout/LineLength: 9 | Max: 120 10 | Metrics/MethodLength: 11 | Max: 20 12 | Metrics/AbcSize: 13 | Max: 50 14 | Metrics/ClassLength: 15 | Max: 150 16 | Metrics/BlockLength: 17 | ExcludedMethods: ['describe'] 18 | Max: 30 19 | 20 | 21 | Style/Documentation: 22 | Enabled: false 23 | Style/ClassAndModuleChildren: 24 | Enabled: false 25 | Style/EachForSimpleLoop: 26 | Enabled: false 27 | Style/AndOr: 28 | Enabled: false 29 | Style/DefWithParentheses: 30 | Enabled: false 31 | Style/FrozenStringLiteralComment: 32 | EnforcedStyle: never 33 | 34 | Layout/HashAlignment: 35 | EnforcedColonStyle: key 36 | Layout/ExtraSpacing: 37 | AllowForAlignment: false 38 | Layout/MultilineMethodCallIndentation: 39 | Enabled: true 40 | EnforcedStyle: indented 41 | Lint/RaiseException: 42 | Enabled: false 43 | Lint/StructNewOverride: 44 | Enabled: false 45 | Style/HashEachMethods: 46 | Enabled: false 47 | Style/HashTransformKeys: 48 | Enabled: false 49 | Style/HashTransformValues: 50 | Enabled: false -------------------------------------------------------------------------------- /lib/user_messages.rb: -------------------------------------------------------------------------------- 1 | module UserMessages 2 | WELCOME_MESSAGE = ' 3 | Welcome to NORP MOVIE LIBRARY 4 | ************************************* 5 | A place of information about the available NETFLIX movies 6 | 7 | Simply select a category from the category list, choose a movie 8 | from the provided list of that category and 9 | receive information about it 10 | ========================================================================= 11 | '.freeze 12 | VALIDATE_MESSAGE = ' 13 | Invalid input, input entered is either not a number or is out of list range. 14 | Enter a valid above list number : '.freeze 15 | FETCHING_CONTENT_MESSAGE = ' 16 | Fetching content ...'.freeze 17 | CATEGORY_LIST_MESSAGE = ' 18 | The following are the Categories available on NETFLIX. 19 | 20 | Please select a number of your choice to view the movies in that category.'.freeze 21 | CATEGORY_CHOICE = ' 22 | Enter your choice of category here : '.freeze 23 | MOVIE_CHOICE = ' 24 | Enter your choice of movie here : '.freeze 25 | FETCHING_MOVIE_MESSAGE = ' 26 | Fetching movie content ...'.freeze 27 | end 28 | -------------------------------------------------------------------------------- /lib/fetch_movie.rb: -------------------------------------------------------------------------------- 1 | require 'nokogiri' 2 | require 'open-uri' 3 | require_relative 'fetch_messages.rb' 4 | 5 | class Movie 6 | def initialize(link_string = nil) 7 | @doc = link_string.nil? ? '' : Nokogiri::HTML(URI.open(link_string)) 8 | @string = '' 9 | end 10 | 11 | private 12 | 13 | def get_movie_content(*selector) 14 | string = '' 15 | @doc.css(*selector).each do |item| 16 | string += item.content 17 | end 18 | string 19 | end 20 | 21 | public 22 | 23 | def display_movie_content(link) 24 | @doc = Nokogiri::HTML(URI.open(link)) 25 | " 26 | ----------Movie Information----------- 27 | 28 | #{get_movie_content(FetchMessages::MOVIE_TITLE).upcase} 29 | 30 | Overview : 31 | #{get_movie_content(FetchMessages::MOVIE_OVERVIEW)} 32 | 33 | 34 | Strarring : #{get_movie_content(FetchMessages::MOVIE_STARS)} 35 | 36 | Duration : #{get_movie_content(FetchMessages::MOVIE_DURATION)} 37 | Release Year: #{get_movie_content(FetchMessages::MOVIE_YEAR)} 38 | Genre : #{get_movie_content(FetchMessages::MOVIE_GENRE)} 39 | Age Limit : #{get_movie_content(FetchMessages::MOVIE_AGE)} 40 | 41 | ------------Information End------------- 42 | " 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /spec/fetch_content_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rspec' 2 | require 'nokogiri' 3 | require 'open-uri' 4 | require './lib/fetch_content.rb' 5 | 6 | describe FetchContent do 7 | let(:web_link) do 8 | 'https://rawcdn.githack.com/RNtaate/Sound-Electronics-store/ccadeae6e3e1eda77681a48f5f835e974dddcbd5/index.html' 9 | end 10 | 11 | let(:array) { [1, 2, 3, 4] } 12 | 13 | describe '.get_content' do 14 | context 'Given a webpage link string and css selector string as arguments' do 15 | it 'Returns a NodeSet' do 16 | expect(FetchContent.get_content(web_link, 'h1')[0].content).to eql('NORP ELECTRONICS') 17 | end 18 | end 19 | end 20 | 21 | describe '.get_inner_content' do 22 | context 'Given a NodeSet, number and css selector string as arguments' do 23 | it 'Returns a new NodeSet' do 24 | doc = Nokogiri::HTML(URI.open(web_link)) 25 | list = doc.css('div.section-heading-div') 26 | expect(FetchContent.get_inner_content(list, 0, 'h6')[0].content).to eql('Home Sytems') 27 | end 28 | end 29 | end 30 | 31 | describe '.validate_input' do 32 | context "Second argument included in range of 1 to first argument's length" do 33 | it { expect(FetchContent.validate_input(array, 2)).to be true } 34 | end 35 | 36 | context "Second argument not included in range of 1 to first argument's length" do 37 | it { expect(FetchContent.validate_input(array, 5)).to be false } 38 | end 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /lib/scraper.rb: -------------------------------------------------------------------------------- 1 | require 'nokogiri' 2 | require 'open-uri' 3 | require_relative 'fetch_content.rb' 4 | require_relative 'fetch_messages.rb' 5 | require_relative 'fetch_movie.rb' 6 | require_relative 'user_messages.rb' 7 | 8 | class Scraper 9 | def initialize 10 | @category_names = '' 11 | @categories = '' 12 | @movies_list = '' 13 | @movie = '' 14 | @choice = '' 15 | @number = 0 16 | @movie_information = Movie.new 17 | end 18 | 19 | private 20 | 21 | def welcome 22 | puts UserMessages::WELCOME_MESSAGE 23 | end 24 | 25 | def proceed_choice 26 | puts ' ' 27 | print 'Enter "y" or "yes" if you wish to continue, and any other key otherwise. : ' 28 | @choice = gets.chomp 29 | end 30 | 31 | def fetch_category_content 32 | @category_names = FetchContent.get_content(FetchMessages::MAIN_LINK, FetchMessages::CATEGORY_NAME) 33 | 34 | @categories = FetchContent.get_content(FetchMessages::MAIN_LINK, 35 | FetchMessages::CATEGORY_SECTION) 36 | end 37 | 38 | def display_list(node_set_array) 39 | node_set_array.length.times do |i| 40 | word = '' + node_set_array[i].content 41 | word.gsub!('Explore more', '') 42 | word = "#{i + 1}.)\t" + word 43 | puts word 44 | end 45 | end 46 | 47 | def check_input(list, value) 48 | number = value 49 | 50 | until FetchContent.validate_input(list, number) 51 | print UserMessages::VALIDATE_MESSAGE 52 | number = gets.chomp.to_i 53 | end 54 | 55 | number 56 | end 57 | 58 | def specify_category_name(list, number) 59 | cat_name = '' + list[number].content + ' category : ' 60 | cat_name.gsub!('Explore more', '') 61 | cat_name = " 62 | #{cat_name} 63 | " 64 | cat_name 65 | end 66 | 67 | def run_received_content 68 | while @choice.downcase == 'y' or @choice.downcase == 'yes' 69 | puts UserMessages::CATEGORY_LIST_MESSAGE 70 | display_list(@category_names) 71 | 72 | print UserMessages::CATEGORY_CHOICE 73 | @number = gets.chomp.to_i 74 | 75 | @number = check_input(@category_names, @number) 76 | 77 | @number -= 1 78 | @movies_list = FetchContent.get_inner_content(@categories, @number, 'a') 79 | 80 | puts specify_category_name(@category_names, @number) 81 | display_list(@movies_list) 82 | 83 | print UserMessages::MOVIE_CHOICE 84 | @number = gets.chomp.to_i 85 | 86 | @number = check_input(@movies_list, @number) 87 | 88 | @number -= 1 89 | @movie = @movies_list[@number]['href'] 90 | puts UserMessages::FETCHING_MOVIE_MESSAGE 91 | 92 | puts @movie_information.display_movie_content(@movie) 93 | 94 | proceed_choice 95 | end 96 | end 97 | 98 | public 99 | 100 | def run 101 | welcome 102 | proceed_choice 103 | return unless @choice.downcase == 'y' or @choice.downcase == 'yes' 104 | 105 | puts UserMessages::FETCHING_CONTENT_MESSAGE 106 | fetch_category_content 107 | 108 | run_received_content 109 | 110 | puts ' ' 111 | puts 'Thank you for visiting us! **GOOD BYE**' 112 | end 113 | end 114 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # This file was generated by the `rspec --init` command. Conventionally, all 2 | # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. 3 | # The generated `.rspec` file contains `--require spec_helper` which will cause 4 | # this file to always be loaded, without a need to explicitly require it in any 5 | # files. 6 | # 7 | # Given that it is always loaded, you are encouraged to keep this file as 8 | # light-weight as possible. Requiring heavyweight dependencies from this file 9 | # will add to the boot time of your test suite on EVERY test run, even for an 10 | # individual file that may not need all of that loaded. Instead, consider making 11 | # a separate helper file that requires the additional dependencies and performs 12 | # the additional setup, and require it from the spec files that actually need 13 | # it. 14 | # 15 | # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration 16 | RSpec.configure do |config| 17 | # rspec-expectations config goes here. You can use an alternate 18 | # assertion/expectation library such as wrong or the stdlib/minitest 19 | # assertions if you prefer. 20 | config.expect_with :rspec do |expectations| 21 | # This option will default to `true` in RSpec 4. It makes the `description` 22 | # and `failure_message` of custom matchers include text for helper methods 23 | # defined using `chain`, e.g.: 24 | # be_bigger_than(2).and_smaller_than(4).description 25 | # # => "be bigger than 2 and smaller than 4" 26 | # ...rather than: 27 | # # => "be bigger than 2" 28 | expectations.include_chain_clauses_in_custom_matcher_descriptions = true 29 | end 30 | 31 | # rspec-mocks config goes here. You can use an alternate test double 32 | # library (such as bogus or mocha) by changing the `mock_with` option here. 33 | config.mock_with :rspec do |mocks| 34 | # Prevents you from mocking or stubbing a method that does not exist on 35 | # a real object. This is generally recommended, and will default to 36 | # `true` in RSpec 4. 37 | mocks.verify_partial_doubles = true 38 | end 39 | 40 | # This option will default to `:apply_to_host_groups` in RSpec 4 (and will 41 | # have no way to turn it off -- the option exists only for backwards 42 | # compatibility in RSpec 3). It causes shared context metadata to be 43 | # inherited by the metadata hash of host groups and examples, rather than 44 | # triggering implicit auto-inclusion in groups with matching metadata. 45 | config.shared_context_metadata_behavior = :apply_to_host_groups 46 | 47 | # The settings below are suggested to provide a good initial experience 48 | # with RSpec, but feel free to customize to your heart's content. 49 | # # This allows you to limit a spec run to individual examples or groups 50 | # # you care about by tagging them with `:focus` metadata. When nothing 51 | # # is tagged with `:focus`, all examples get run. RSpec also provides 52 | # # aliases for `it`, `describe`, and `context` that include `:focus` 53 | # # metadata: `fit`, `fdescribe` and `fcontext`, respectively. 54 | # config.filter_run_when_matching :focus 55 | # 56 | # # Allows RSpec to persist some state between runs in order to support 57 | # # the `--only-failures` and `--next-failure` CLI options. We recommend 58 | # # you configure your source control system to ignore this file. 59 | # config.example_status_persistence_file_path = "spec/examples.txt" 60 | # 61 | # # Limits the available syntax to the non-monkey patched syntax that is 62 | # # recommended. For more details, see: 63 | # # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ 64 | # # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ 65 | # # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode 66 | # config.disable_monkey_patching! 67 | # 68 | # # This setting enables warnings. It's recommended, but in some cases may 69 | # # be too noisy due to issues in dependencies. 70 | # config.warnings = true 71 | # 72 | # # Many RSpec users commonly either run the entire suite or an individual 73 | # # file, and it's useful to allow more verbose output when running an 74 | # # individual spec file. 75 | # if config.files_to_run.one? 76 | # # Use the documentation formatter for detailed output, 77 | # # unless a formatter has already been configured 78 | # # (e.g. via a command-line flag). 79 | # config.default_formatter = "doc" 80 | # end 81 | # 82 | # # Print the 10 slowest examples and example groups at the 83 | # # end of the spec run, to help surface which specs are running 84 | # # particularly slow. 85 | # config.profile_examples = 10 86 | # 87 | # # Run specs in random order to surface order dependencies. If you find an 88 | # # order dependency and want to debug it, you can fix the order by providing 89 | # # the seed, which is printed after each run. 90 | # # --seed 1234 91 | # config.order = :random 92 | # 93 | # # Seed global randomization in this process using the `--seed` CLI option. 94 | # # Setting this allows you to use `--seed` to deterministically reproduce 95 | # # test failures related to randomization by passing the same `--seed` value 96 | # # as the one that triggered the failure. 97 | # Kernel.srand config.seed 98 | end 99 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Web_Scraper 2 | 3 | ![Linters](https://github.com/RNtaate/Web_Scraper/workflows/Linters/badge.svg) 4 | 5 | > This project is a ruby capstone project from the [Microverse](https://www.microverse.org/) technical curriculum 6 | 7 | ## Contents 8 | - [Description](#description) 9 | 10 | - [Built With](#built-with) 11 | 12 | - [How to deploy this scraper](#how-to-deploy-this-scraper) 13 | 14 | - [How to use this Web scraper](#how-to-use-this-web-scraper) 15 | 16 | - [Contributions](#contributions) 17 | 18 | - [Authors](#authors) 19 | 20 | ## Description 21 | 22 | **Web scraping**, also known as **web data extraction**, is the process of retrieving or “scraping” data from a website. Unlike the mundane, mind-numbing process of manually extracting data, web scraping uses intelligent automation to retrieve hundreds, millions, or even billions of data points from the internet’s seemingly endless frontier. [Read more at scrapinghub...](https://www.scrapinghub.com/what-is-web-scraping/) 23 | 24 | **This project demonstrates an example of Web scraping by retrieving data from the [Movies | NETFLIX](https://www.netflix.com/ug/browse/genre/34399) webpage and presenting it to the user.** 25 | 26 | 27 | The Scraper presents retrieved data to the user in 3 phases all of which depend on their selection or response : 28 | 29 | - **Phase 1** : A list of movie categories 30 | - **Phase 2** : A list of movies from a particular category 31 | - **Phase 3** : Information about **A MOVIE** from the list of movies in **Phase 2** 32 | 33 | 34 | CATEGORIES | 35 | -----------| 36 | ![](images/scraper1.png) | 37 | 38 | MOVIE LIST | 39 | -----------| 40 | ![](images/scraper2.png) | 41 | 42 | MOVIE INFORMATION | 43 | ------------------| 44 | ![](images/scraper3.png) | 45 | 46 | 47 | ## Built With 48 | 49 | - Ruby 50 | - Nokogiri Gem 51 | 52 | ## Tested With 53 | 54 | - Rspec 3.9 55 | 56 | ## How to Deploy this Scraper 57 | > This scraper can be deployed on the following platforms. 58 | 59 | > A. [Your Computer](#a-on-your-computer) 60 | 61 | > B. [Online](#b-online) 62 | 63 | 64 | ### A. On your computer 65 | 66 | #### Pre-requisites 67 | 1. You should have [Ruby](https://www.ruby-lang.org/en/) installed on your computer. 68 | 1. Your computer should be able to run `terminal` or `command prompt` or `bash` or `Powershell` commands. 69 | 70 | #### A. 1. Using the Release tag 71 | 1. [Click Here](https://github.com/RNtaate/Web_Scraper/releases/tag/v1.0.0-beta) to download the zip file of this Scraper. 72 | 1. Unzip the downloaded file to a folder of your choice. 73 | 1. Open terminal and navigate to folder containing the unzipped file using `cd` 74 | 1. Run the following command to start the Scraper. 75 | ```bash 76 | bin/main.rb 77 | ``` 78 | 5. At this point, you should see a welcome message indicating the Scraper has opened. 79 | 80 | #### A. 2. Using a Repository 81 | 1. Run this command `git clone https://github.com/RNtaate/Web_Scraper.git` to clone the repository on to your local machine. 82 | 1. Run `cd Web_Scraper` to enter into the scraper folder 83 | 1. Run the following command to deploy the scraper 84 | 85 | ```bash 86 | bin/main.rb 87 | ``` 88 | 4. At this point, you should see a welcome message indicating the scraper has opened. 89 | 90 | ### B. Online 91 | 92 | 1. click the following link [Scraper's link](https://repl.it/@RNtaate/WebScraper#bin/main.rb) 93 | 1. When the link has been opened, click the `green run button` you will see at the top to run the Scraper. 94 | 95 | ## How to use this Web Scraper 96 | 1. When the scraper is opened, it displays a brief description of how to obtain information and then asks you to enter 'y' or 'yes' if you wish to continue or enter any other key to abort. 97 | 98 | 1. When you choose to continue, the Scraper will take a couple of seconds to fetch the required information. 99 | 1. When it is done retrieving data, it will display a list of movie categories as seen in the **CATEGORIES** image above. 100 | 1. At this point, below the list, the Scraper will ask you to enter a category selection by typing the number appearing before your choice of category. 101 | 1. When you enter a valid number, the scraper will display a list of movies contained with in your category of choice as seen in the **MOVIE LIST** image above 102 | 1. Again, at this point, below the movies list, the Scraper will ask you to enter a movie selection by typing the number appearing before your choice of movie. 103 | 1. When you make a valid selection, the Scraper will take a couple of seconds to fetch the information about your choice of movie. 104 | 1. When it is done retrieving data, it will display the information about the movie you selected in step **6** as seen in the **MOVIE INFORMATION** image above. 105 | 1. After successfully displaying this information, the Scraper will further request you to enter 'y' or 'yes' if you wish to continue or any other key to abort. 106 | 1. When you choose to continue, the Scraper will go back to step **3** of this process. 107 | 108 | ## Contributions 109 | 110 | There are two ways of contributing to this project: 111 | 112 | 1. If you see something wrong or not working, please check [the issue tracker section](https://github.com/RNtaate/Web_Scraper/issues), if that problem you met is not in already opened issues then open the issue by clicking on `new issue` button. 113 | 114 | 2. If you have a solution to that, and you are willing to work on it, follow the below steps to contribute: 115 | 1. Fork this repository 116 | 1. Clone it on your local computer by running `git clone https://github.com/RNtaate/Web_Scraper.git` __Replace *RNtaate* with the username you use on github__ 117 | 1. Open the cloned repository which appears as a folder on your local computer with your favorite code editor 118 | 1. Create a separate branch off the *master branch*, 119 | 1. Write your codes which fix the issue you found 120 | 1. Commit and push the branch you created 121 | 1. Raise a pull request, comparing your new created branch with our original master branch [here](https://github.com/RNtaate/Web_Scraper) 122 | 123 | ## Authors 124 | 125 | 👤 **Roy Ntaate** 126 | 127 | - Github: [@RNtaate](https://github.com/RNtaate) 128 | - Twitter: [@RNtaate](https://twitter.com/RNtaate) 129 | - Linkedin: [roy-ntaate](https://linkedin.com/in/roy-ntaate) 130 | 131 | 132 | ## Show your support 133 | 134 | Give a ⭐️ if you like this project! 135 | 136 | ## Acknowledgments 137 | 138 | - This project was inspired by the [Microverse](https:www.microverse.org) program 139 | 140 | ## 📝 License 141 | 142 | This project is [MIT](lic.url) licensed. 143 | --------------------------------------------------------------------------------