mechanize 2.7.6 → 2.12.2
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 +5 -5
- data/.github/dependabot.yml +11 -0
- data/.github/workflows/ci.yml +43 -0
- data/.github/workflows/upstream.yml +51 -0
- data/.yardopts +8 -0
- data/{CHANGELOG.rdoc → CHANGELOG.md} +221 -96
- data/EXAMPLES.rdoc +1 -24
- data/Gemfile +10 -4
- data/{LICENSE.rdoc → LICENSE.txt} +4 -0
- data/README.md +77 -0
- data/Rakefile +18 -3
- data/examples/latest_user_agents.rb +100 -0
- data/examples/rubygems.rb +2 -2
- data/examples/wikipedia_links_to_philosophy.rb +5 -6
- data/lib/mechanize/chunked_termination_error.rb +1 -0
- data/lib/mechanize/content_type_error.rb +1 -0
- data/lib/mechanize/cookie.rb +3 -15
- data/lib/mechanize/cookie_jar.rb +13 -9
- data/lib/mechanize/directory_saver.rb +1 -0
- data/lib/mechanize/download.rb +2 -1
- data/lib/mechanize/element_matcher.rb +1 -0
- data/lib/mechanize/element_not_found_error.rb +1 -0
- data/lib/mechanize/file.rb +2 -1
- data/lib/mechanize/file_connection.rb +5 -3
- data/lib/mechanize/file_request.rb +1 -0
- data/lib/mechanize/file_response.rb +4 -1
- data/lib/mechanize/file_saver.rb +1 -0
- data/lib/mechanize/form/button.rb +1 -0
- data/lib/mechanize/form/check_box.rb +1 -0
- data/lib/mechanize/form/field.rb +1 -0
- data/lib/mechanize/form/file_upload.rb +1 -0
- data/lib/mechanize/form/hidden.rb +1 -0
- data/lib/mechanize/form/image_button.rb +1 -0
- data/lib/mechanize/form/keygen.rb +1 -0
- data/lib/mechanize/form/multi_select_list.rb +2 -1
- data/lib/mechanize/form/option.rb +1 -0
- data/lib/mechanize/form/radio_button.rb +1 -0
- data/lib/mechanize/form/reset.rb +1 -0
- data/lib/mechanize/form/select_list.rb +1 -0
- data/lib/mechanize/form/submit.rb +1 -0
- data/lib/mechanize/form/text.rb +1 -0
- data/lib/mechanize/form/textarea.rb +1 -0
- data/lib/mechanize/form.rb +5 -13
- data/lib/mechanize/headers.rb +1 -0
- data/lib/mechanize/history.rb +1 -0
- data/lib/mechanize/http/agent.rb +83 -10
- data/lib/mechanize/http/auth_challenge.rb +1 -0
- data/lib/mechanize/http/auth_realm.rb +1 -0
- data/lib/mechanize/http/auth_store.rb +1 -0
- data/lib/mechanize/http/content_disposition_parser.rb +15 -4
- data/lib/mechanize/http/www_authenticate_parser.rb +3 -3
- data/lib/mechanize/http.rb +1 -0
- data/lib/mechanize/image.rb +1 -0
- data/lib/mechanize/page/base.rb +1 -0
- data/lib/mechanize/page/frame.rb +1 -0
- data/lib/mechanize/page/image.rb +1 -0
- data/lib/mechanize/page/label.rb +1 -0
- data/lib/mechanize/page/link.rb +8 -1
- data/lib/mechanize/page/meta_refresh.rb +1 -0
- data/lib/mechanize/page.rb +6 -8
- data/lib/mechanize/parser.rb +1 -0
- data/lib/mechanize/pluggable_parsers.rb +2 -1
- data/lib/mechanize/prependable.rb +1 -0
- data/lib/mechanize/redirect_limit_reached_error.rb +1 -0
- data/lib/mechanize/redirect_not_get_or_head_error.rb +1 -0
- data/lib/mechanize/response_code_error.rb +2 -1
- data/lib/mechanize/response_read_error.rb +1 -0
- data/lib/mechanize/robots_disallowed_error.rb +1 -0
- data/lib/mechanize/test_case/bad_chunking_servlet.rb +1 -0
- data/lib/mechanize/test_case/basic_auth_servlet.rb +1 -0
- data/lib/mechanize/test_case/content_type_servlet.rb +1 -0
- data/lib/mechanize/test_case/digest_auth_servlet.rb +1 -0
- data/lib/mechanize/test_case/file_upload_servlet.rb +1 -0
- data/lib/mechanize/test_case/form_servlet.rb +1 -0
- data/lib/mechanize/test_case/gzip_servlet.rb +4 -3
- data/lib/mechanize/test_case/header_servlet.rb +1 -0
- data/lib/mechanize/test_case/http_refresh_servlet.rb +1 -0
- data/lib/mechanize/test_case/infinite_redirect_servlet.rb +1 -0
- data/lib/mechanize/test_case/infinite_refresh_servlet.rb +1 -0
- data/lib/mechanize/test_case/many_cookies_as_string_servlet.rb +1 -0
- data/lib/mechanize/test_case/many_cookies_servlet.rb +1 -0
- data/lib/mechanize/test_case/modified_since_servlet.rb +1 -0
- data/lib/mechanize/test_case/ntlm_servlet.rb +1 -0
- data/lib/mechanize/test_case/one_cookie_no_spaces_servlet.rb +1 -0
- data/lib/mechanize/test_case/one_cookie_servlet.rb +1 -0
- data/lib/mechanize/test_case/quoted_value_cookie_servlet.rb +1 -0
- data/lib/mechanize/test_case/redirect_servlet.rb +1 -0
- data/lib/mechanize/test_case/referer_servlet.rb +1 -0
- data/lib/mechanize/test_case/refresh_with_empty_url.rb +1 -0
- data/lib/mechanize/test_case/refresh_without_url.rb +1 -0
- data/lib/mechanize/test_case/response_code_servlet.rb +1 -0
- data/lib/mechanize/test_case/robots_txt_servlet.rb +1 -0
- data/lib/mechanize/test_case/send_cookies_servlet.rb +1 -0
- data/lib/mechanize/test_case/server.rb +1 -0
- data/lib/mechanize/test_case/servlets.rb +1 -0
- data/lib/mechanize/test_case/verb_servlet.rb +5 -6
- data/lib/mechanize/test_case.rb +34 -34
- data/lib/mechanize/unauthorized_error.rb +1 -0
- data/lib/mechanize/unsupported_scheme_error.rb +1 -0
- data/lib/mechanize/util.rb +2 -1
- data/lib/mechanize/version.rb +2 -1
- data/lib/mechanize/xml_file.rb +1 -0
- data/lib/mechanize.rb +56 -37
- data/mechanize.gemspec +43 -35
- data/test/htdocs/dir with spaces/foo.html +1 -0
- data/test/htdocs/tc_links.html +1 -1
- data/test/test_mechanize.rb +21 -8
- data/test/test_mechanize_cookie.rb +38 -26
- data/test/test_mechanize_cookie_jar.rb +87 -54
- data/test/test_mechanize_directory_saver.rb +1 -0
- data/test/test_mechanize_download.rb +14 -1
- data/test/test_mechanize_element_not_found_error.rb +1 -0
- data/test/test_mechanize_file.rb +11 -0
- data/test/test_mechanize_file_connection.rb +23 -4
- data/test/test_mechanize_file_request.rb +1 -0
- data/test/test_mechanize_file_response.rb +26 -1
- data/test/test_mechanize_file_saver.rb +1 -0
- data/test/test_mechanize_form.rb +14 -1
- data/test/test_mechanize_form_check_box.rb +1 -0
- data/test/test_mechanize_form_encoding.rb +2 -1
- data/test/test_mechanize_form_field.rb +1 -0
- data/test/test_mechanize_form_file_upload.rb +1 -0
- data/test/test_mechanize_form_image_button.rb +1 -0
- data/test/test_mechanize_form_keygen.rb +2 -0
- data/test/test_mechanize_form_multi_select_list.rb +1 -0
- data/test/test_mechanize_form_option.rb +1 -0
- data/test/test_mechanize_form_radio_button.rb +1 -0
- data/test/test_mechanize_form_select_list.rb +1 -0
- data/test/test_mechanize_form_textarea.rb +1 -0
- data/test/test_mechanize_headers.rb +1 -0
- data/test/test_mechanize_history.rb +1 -0
- data/test/test_mechanize_http_agent.rb +187 -26
- data/test/test_mechanize_http_auth_challenge.rb +1 -0
- data/test/test_mechanize_http_auth_realm.rb +1 -0
- data/test/test_mechanize_http_auth_store.rb +1 -0
- data/test/test_mechanize_http_content_disposition_parser.rb +28 -0
- data/test/test_mechanize_http_www_authenticate_parser.rb +1 -0
- data/test/test_mechanize_image.rb +1 -0
- data/test/test_mechanize_link.rb +25 -0
- data/test/test_mechanize_page.rb +15 -0
- data/test/test_mechanize_page_encoding.rb +33 -5
- data/test/test_mechanize_page_frame.rb +1 -0
- data/test/test_mechanize_page_image.rb +1 -0
- data/test/test_mechanize_page_link.rb +27 -23
- data/test/test_mechanize_page_meta_refresh.rb +1 -0
- data/test/test_mechanize_parser.rb +1 -0
- data/test/test_mechanize_pluggable_parser.rb +1 -0
- data/test/test_mechanize_redirect_limit_reached_error.rb +1 -0
- data/test/test_mechanize_redirect_not_get_or_head_error.rb +1 -0
- data/test/test_mechanize_response_read_error.rb +1 -0
- data/test/test_mechanize_subclass.rb +1 -0
- data/test/test_mechanize_util.rb +4 -3
- data/test/test_mechanize_xml_file.rb +1 -0
- data/test/test_multi_select.rb +1 -0
- metadata +106 -86
- data/.travis.yml +0 -36
- data/README.rdoc +0 -77
data/EXAMPLES.rdoc
CHANGED
|
@@ -24,29 +24,6 @@ example, <code>do ... end.submit</code> is the same as <code>{ ...
|
|
|
24
24
|
end
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
-
== Rubyforge
|
|
28
|
-
|
|
29
|
-
require 'rubygems'
|
|
30
|
-
require 'mechanize'
|
|
31
|
-
|
|
32
|
-
a = Mechanize.new
|
|
33
|
-
a.get('http://rubyforge.org/') do |page|
|
|
34
|
-
# Click the login link
|
|
35
|
-
login_page = a.click(page.link_with(:text => /Log In/))
|
|
36
|
-
|
|
37
|
-
# Submit the login form
|
|
38
|
-
my_page = login_page.form_with(:action => '/account/login.php') do |f|
|
|
39
|
-
f.form_loginname = ARGV[0]
|
|
40
|
-
f.form_pw = ARGV[1]
|
|
41
|
-
end.click_button
|
|
42
|
-
|
|
43
|
-
my_page.links.each do |link|
|
|
44
|
-
text = link.text.strip
|
|
45
|
-
next unless text.length > 0
|
|
46
|
-
puts text
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
|
|
50
27
|
== File Upload
|
|
51
28
|
|
|
52
29
|
Upload a file to flickr.
|
|
@@ -129,7 +106,7 @@ This example also demonstrates subclassing Mechanize.
|
|
|
129
106
|
|
|
130
107
|
class TestMech < Mechanize
|
|
131
108
|
def process
|
|
132
|
-
get 'http://
|
|
109
|
+
get 'http://rubygems.org/'
|
|
133
110
|
search_form = page.forms.first
|
|
134
111
|
search_form.words = 'WWW'
|
|
135
112
|
submit search_form
|
data/Gemfile
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
source
|
|
2
|
-
|
|
3
|
-
# In order to be able to install on 1.9.3 and 2.0.0
|
|
4
|
-
ruby RUBY_VERSION
|
|
1
|
+
source "https://rubygems.org"
|
|
5
2
|
|
|
6
3
|
gemspec
|
|
4
|
+
|
|
5
|
+
gem "minitest", "~> 5.14"
|
|
6
|
+
gem "rake", "~> 13.0"
|
|
7
|
+
gem "rdoc", "~> 6.3"
|
|
8
|
+
gem "rubocop", "~> 1.12"
|
|
9
|
+
unless RUBY_PLATFORM == 'java'
|
|
10
|
+
gem 'brotli', '>= 0.5'
|
|
11
|
+
gem 'zstd-ruby', '~> 1.5'
|
|
12
|
+
end
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
(The MIT License)
|
|
2
2
|
|
|
3
|
+
Copyright (c) 2005 by Michael Neumann (mneumann@ntecs.de)
|
|
4
|
+
|
|
5
|
+
Copyright (c) 2006-2021 by Eric Hodel, Akinori MUSHA, Aaron Patterson, Lee Jarvis, Mike Dalessio
|
|
6
|
+
|
|
3
7
|
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
8
|
a copy of this software and associated documentation files (the
|
|
5
9
|
'Software'), to deal in the Software without restriction, including
|
data/README.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Mechanize
|
|
2
|
+
|
|
3
|
+
* https://www.rubydoc.info/gems/mechanize/
|
|
4
|
+
* https://github.com/sparklemotion/mechanize
|
|
5
|
+
|
|
6
|
+
[](https://github.com/sparklemotion/mechanize/actions/workflows/ci.yml)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
## Description
|
|
10
|
+
|
|
11
|
+
The Mechanize library is used for automating interaction with websites. Mechanize automatically stores and sends cookies, follows redirects, and can follow links and submit forms. Form fields can be populated and submitted. Mechanize also keeps track of the sites that you have visited as a history.
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## Dependencies
|
|
15
|
+
|
|
16
|
+
* Ruby >= 2.6
|
|
17
|
+
* Gems:
|
|
18
|
+
* `addressable`
|
|
19
|
+
* `domain_name`
|
|
20
|
+
* `http-cookie`
|
|
21
|
+
* `mime-types`
|
|
22
|
+
* `net-http-digest_auth`
|
|
23
|
+
* `net-http-persistent`
|
|
24
|
+
* `nokogiri`
|
|
25
|
+
* `rubyntlm`
|
|
26
|
+
* `webrick`
|
|
27
|
+
* `webrobots`
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
## Support:
|
|
31
|
+
|
|
32
|
+
The bug tracker is available here:
|
|
33
|
+
|
|
34
|
+
* https://github.com/sparklemotion/mechanize/issues
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
## Examples
|
|
38
|
+
|
|
39
|
+
If you are just starting, check out [GUIDE.rdoc](https://github.com/sparklemotion/mechanize/blob/main/GUIDE.rdoc) or [EXAMPLES.rdoc](https://github.com/sparklemotion/mechanize/blob/main/EXAMPLES.rdoc).
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
## Developers
|
|
43
|
+
|
|
44
|
+
Use bundler to install dependencies:
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
bundle install
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Run all tests with:
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
bundle exec rake test
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
See also Mechanize::TestCase to read about the built-in testing infrastructure.
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
## Authors
|
|
60
|
+
|
|
61
|
+
* Eric Hodel
|
|
62
|
+
* Akinori MUSHA
|
|
63
|
+
* Aaron Patterson
|
|
64
|
+
* Lee Jarvis
|
|
65
|
+
* Mike Dalessio
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
## Acknowledgments
|
|
69
|
+
|
|
70
|
+
This library was heavily influenced by its namesake in the Perl world. A big
|
|
71
|
+
thanks goes to [Andy Lester](http://petdance.com), the author of the original Perl module WWW::Mechanize which is available [here](http://search.cpan.org/dist/WWW-Mechanize/). Ruby Mechanize would not be around without you!
|
|
72
|
+
|
|
73
|
+
Thank you to Michael Neumann for starting the Ruby version. Thanks to everyone who's helped out in various ways. Finally, thank you to the people using this library!
|
|
74
|
+
|
|
75
|
+
## License
|
|
76
|
+
|
|
77
|
+
This library is distributed under the MIT license. Please see [LICENSE.txt](https://github.com/sparklemotion/mechanize/blob/main/LICENSE.txt).
|
data/Rakefile
CHANGED
|
@@ -23,9 +23,9 @@ task('ssl_cert') do |p|
|
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
RDoc::Task.new do |rdoc|
|
|
26
|
-
rdoc.main = "README.
|
|
26
|
+
rdoc.main = "README.md"
|
|
27
27
|
rdoc.rdoc_dir = 'doc'
|
|
28
|
-
rdoc.rdoc_files.include( "CHANGELOG.
|
|
28
|
+
rdoc.rdoc_files.include( "CHANGELOG.md", "EXAMPLES.rdoc", "GUIDE.rdoc", "LICENSE.txt", "README.md", "lib/**/*.rb")
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
desc "Run tests"
|
|
@@ -38,4 +38,19 @@ task publish_docs: %w[rdoc] do
|
|
|
38
38
|
sh 'rsync', '-avzO', '--delete', 'doc/', 'docs-push.seattlerb.org:/data/www/docs.seattlerb.org/mechanize/'
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
desc "Run rubocop checks"
|
|
42
|
+
task :rubocop => ["rubocop:security", "rubocop:frozen_string_literals"]
|
|
43
|
+
|
|
44
|
+
namespace "rubocop" do
|
|
45
|
+
desc "Run rubocop security check"
|
|
46
|
+
task :security do
|
|
47
|
+
sh "rubocop lib --only Security"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
desc "Run rubocop string literals check"
|
|
51
|
+
task :frozen_string_literals do
|
|
52
|
+
sh "rubocop lib test --auto-correct-all --only Style/FrozenStringLiteralComment"
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
task default: [:rubocop, :test]
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
require 'mechanize'
|
|
2
|
+
require 'ostruct'
|
|
3
|
+
|
|
4
|
+
# LatestUAFetcher fetches latest user agents from `WhatIsMyBrowser.com`.
|
|
5
|
+
# It can use to update `Mechanize::AGENT_ALIASES`.
|
|
6
|
+
class LatestUAFetcher
|
|
7
|
+
attr_reader :user_agents
|
|
8
|
+
|
|
9
|
+
USER_AGENT_TYPES = OpenStruct.new(
|
|
10
|
+
linux_firefox: "Linux Firefox",
|
|
11
|
+
mac_firefox: "Mac Firefox",
|
|
12
|
+
mac_safari: "Mac Safari",
|
|
13
|
+
windows_chrome: "Windows Chrome",
|
|
14
|
+
windows_edge: "Windows Edge",
|
|
15
|
+
windows_firefox: "Windows Firefox",
|
|
16
|
+
android: "Android",
|
|
17
|
+
iphone: "iPhone",
|
|
18
|
+
ipad: "iPad",
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
BASE_URL = 'https://www.whatismybrowser.com/guides/the-latest-user-agent'
|
|
22
|
+
|
|
23
|
+
def initialize
|
|
24
|
+
@agent = Mechanize.new.tap { |a| a.user_agent_alias = 'Mac Firefox' }
|
|
25
|
+
@user_agents = {}
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def run
|
|
29
|
+
return unless user_agents.empty?
|
|
30
|
+
|
|
31
|
+
sleep_time = 1
|
|
32
|
+
|
|
33
|
+
fetch_user_agents('chrome')
|
|
34
|
+
fetch_user_agents('firefox')
|
|
35
|
+
fetch_user_agents('safari')
|
|
36
|
+
fetch_user_agents('edge')
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def ordered_user_agents
|
|
40
|
+
USER_AGENT_TYPES.to_h.values.each_with_object({}) do |type, ordered_user_agents|
|
|
41
|
+
ordered_user_agents[type] = user_agents[type]
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def fetch_user_agents(browser_name, sleep_time = 1)
|
|
48
|
+
puts "fetch #{browser_name} UA..."
|
|
49
|
+
send(browser_name)
|
|
50
|
+
puts "sleeping... (#{sleep_time}s)"
|
|
51
|
+
sleep sleep_time
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def edge
|
|
55
|
+
page = @agent.get("#{BASE_URL}/edge")
|
|
56
|
+
|
|
57
|
+
windows_dom = page.css("h2:contains('Latest Edge on Windows User Agents')")
|
|
58
|
+
|
|
59
|
+
@user_agents[USER_AGENT_TYPES.windows_edge] = windows_dom.css('+ .listing-of-useragents .code').first.text
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def firefox
|
|
63
|
+
page = @agent.get("#{BASE_URL}/firefox")
|
|
64
|
+
|
|
65
|
+
desktop_dom = page.css("h2:contains('Latest Firefox on Desktop User Agents')")
|
|
66
|
+
table_dom = desktop_dom.css('+ .listing-of-useragents')
|
|
67
|
+
|
|
68
|
+
@user_agents[USER_AGENT_TYPES.linux_firefox] = table_dom.css('td:contains("Linux")').css("+ td .code:contains('Ubuntu; Linux x86_64')").text
|
|
69
|
+
@user_agents[USER_AGENT_TYPES.windows_firefox] = table_dom.css('td:contains("Windows")').css('+ td .code').text
|
|
70
|
+
@user_agents[USER_AGENT_TYPES.mac_firefox] = table_dom.css('td:contains("Macos")').css('+ td .code').text
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def safari
|
|
74
|
+
page = @agent.get("#{BASE_URL}/safari")
|
|
75
|
+
|
|
76
|
+
macos_dom = page.css("h2:contains('Latest Safari on macOS User Agents')")
|
|
77
|
+
ios_dom = page.css("h2:contains('Latest Safari on iOS User Agents')")
|
|
78
|
+
|
|
79
|
+
@user_agents[USER_AGENT_TYPES.mac_safari] = macos_dom.css('+ .listing-of-useragents .code').first.text
|
|
80
|
+
@user_agents[USER_AGENT_TYPES.iphone] = ios_dom.css('+ .listing-of-useragents').css("tr:contains('Iphone') .code").text
|
|
81
|
+
@user_agents[USER_AGENT_TYPES.ipad] = ios_dom.css('+ .listing-of-useragents').css("tr:contains('Ipad') .code").text
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def chrome
|
|
85
|
+
page = @agent.get("#{BASE_URL}/chrome")
|
|
86
|
+
|
|
87
|
+
windows_dom = page.css("h2:contains('Latest Chrome on Windows 10 User Agents')")
|
|
88
|
+
android_dom = page.css("h2:contains('Latest Chrome on Android User Agents')")
|
|
89
|
+
|
|
90
|
+
@user_agents[USER_AGENT_TYPES.windows_chrome] = windows_dom.css('+ .listing-of-useragents .code').first.text
|
|
91
|
+
@user_agents[USER_AGENT_TYPES.android] = android_dom.css('+ .listing-of-useragents .code').first.text
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
if $0 == __FILE__
|
|
96
|
+
agent = LatestUAFetcher.new
|
|
97
|
+
agent.run
|
|
98
|
+
|
|
99
|
+
pp agent.ordered_user_agents
|
|
100
|
+
end
|
data/examples/rubygems.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# This example logs a user in to
|
|
1
|
+
# This example logs a user in to rubygems and prints out the body of the
|
|
2
2
|
# page after logging the user in.
|
|
3
3
|
require 'rubygems'
|
|
4
4
|
require 'mechanize'
|
|
@@ -9,7 +9,7 @@ mech = Mechanize.new
|
|
|
9
9
|
mech.log = Logger.new $stderr
|
|
10
10
|
mech.agent.http.debug_output = $stderr
|
|
11
11
|
|
|
12
|
-
# Load the
|
|
12
|
+
# Load the rubygems website
|
|
13
13
|
page = mech.get('https://rubygems.org/')
|
|
14
14
|
page = mech.click page.link_with(:text => /Sign in/) # Click the login link
|
|
15
15
|
form = page.forms[1] # Select the first form
|
|
@@ -58,10 +58,10 @@ class WikipediaLinksToPhilosophy
|
|
|
58
58
|
# the article.
|
|
59
59
|
|
|
60
60
|
def follow_first_link
|
|
61
|
-
puts @title
|
|
61
|
+
puts "#{@title} (#{@page.uri})"
|
|
62
62
|
|
|
63
63
|
# > p > a rejects italics
|
|
64
|
-
links = @page.root.css('.mw-content-ltr
|
|
64
|
+
links = @page.root.css('.mw-content-ltr p > a[href^="/wiki/"]')
|
|
65
65
|
|
|
66
66
|
# reject disambiguation and special pages, images and files
|
|
67
67
|
links = links.reject do |link_node|
|
|
@@ -74,10 +74,9 @@ class WikipediaLinksToPhilosophy
|
|
|
74
74
|
|
|
75
75
|
link = links.first
|
|
76
76
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
@page.root.css('.mw-content-ltr > ul > li > a[href^="/wiki/"]').first
|
|
77
|
+
if link.nil?
|
|
78
|
+
puts "Could not parse #{@page.uri}"
|
|
79
|
+
exit 1
|
|
81
80
|
end
|
|
82
81
|
|
|
83
82
|
# convert a Nokogiri HTML element back to a mechanize link
|
data/lib/mechanize/cookie.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
warn 'mechanize/cookie will be deprecated. Please migrate to the http-cookie APIs.' if $VERBOSE
|
|
2
3
|
|
|
3
4
|
require 'http/cookie'
|
|
@@ -6,7 +7,7 @@ class Mechanize
|
|
|
6
7
|
module CookieDeprecated
|
|
7
8
|
def __deprecated__(to = nil)
|
|
8
9
|
$VERBOSE or return
|
|
9
|
-
method =
|
|
10
|
+
method = caller_locations(1,1).first.base_label
|
|
10
11
|
to ||= method
|
|
11
12
|
case self
|
|
12
13
|
when Class
|
|
@@ -20,7 +21,7 @@ class Mechanize
|
|
|
20
21
|
this = '%s#%s' % [klass, method]
|
|
21
22
|
that = 'HTTP::%s#%s' % [lname, to]
|
|
22
23
|
end
|
|
23
|
-
warn '%s: The call of %s needs to be fixed to follow the new API (%s).' % [
|
|
24
|
+
warn '%s: The call of %s needs to be fixed to follow the new API (%s).' % [caller_locations(2,1).first, this, that]
|
|
24
25
|
end
|
|
25
26
|
private :__deprecated__
|
|
26
27
|
end
|
|
@@ -50,19 +51,6 @@ class Mechanize
|
|
|
50
51
|
|
|
51
52
|
Cookie = ::HTTP::Cookie
|
|
52
53
|
|
|
53
|
-
# Compatibility for Ruby 1.8/1.9
|
|
54
|
-
unless Cookie.respond_to?(:prepend, true)
|
|
55
|
-
require 'mechanize/prependable'
|
|
56
|
-
|
|
57
|
-
class Cookie
|
|
58
|
-
extend Prependable
|
|
59
|
-
|
|
60
|
-
class << self
|
|
61
|
-
extend Prependable
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
|
|
66
54
|
class Cookie
|
|
67
55
|
prepend CookieIMethods
|
|
68
56
|
|
data/lib/mechanize/cookie_jar.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
warn 'mechanize/cookie_jar will be deprecated. Please migrate to the http-cookie APIs.' if $VERBOSE
|
|
2
3
|
|
|
3
4
|
require 'http/cookie_jar'
|
|
@@ -65,7 +66,7 @@ class Mechanize
|
|
|
65
66
|
class CookieJar < ::HTTP::CookieJar
|
|
66
67
|
def save(output, *options)
|
|
67
68
|
output.respond_to?(:write) or
|
|
68
|
-
return open(output, 'w') { |io| save(io, *options) }
|
|
69
|
+
return ::File.open(output, 'w') { |io| save(io, *options) }
|
|
69
70
|
|
|
70
71
|
opthash = {
|
|
71
72
|
:format => :yaml,
|
|
@@ -119,7 +120,7 @@ class Mechanize
|
|
|
119
120
|
|
|
120
121
|
def load(input, *options)
|
|
121
122
|
input.respond_to?(:write) or
|
|
122
|
-
return open(input, 'r') { |io| load(io, *options) }
|
|
123
|
+
return ::File.open(input, 'r') { |io| load(io, *options) }
|
|
123
124
|
|
|
124
125
|
opthash = {
|
|
125
126
|
:format => :yaml,
|
|
@@ -148,7 +149,7 @@ class Mechanize
|
|
|
148
149
|
return super(input, opthash) if opthash[:format] != :yaml
|
|
149
150
|
|
|
150
151
|
begin
|
|
151
|
-
data =
|
|
152
|
+
data = load_yaml(input)
|
|
152
153
|
rescue ArgumentError
|
|
153
154
|
@logger.warn "unloadable YAML cookie data discarded" if @logger
|
|
154
155
|
return self
|
|
@@ -173,14 +174,17 @@ class Mechanize
|
|
|
173
174
|
return self
|
|
174
175
|
end
|
|
175
176
|
end
|
|
176
|
-
end
|
|
177
177
|
|
|
178
|
-
|
|
179
|
-
unless ::HTTP::CookieJar.respond_to?(:prepend, true)
|
|
180
|
-
require 'mechanize/prependable'
|
|
178
|
+
private
|
|
181
179
|
|
|
182
|
-
|
|
183
|
-
|
|
180
|
+
if YAML.name == "Psych" && Gem::Requirement.new(">= 3.1").satisfied_by?(Gem::Version.new(Psych::VERSION))
|
|
181
|
+
def load_yaml(yaml)
|
|
182
|
+
YAML.safe_load(yaml, aliases: true, permitted_classes: ["Mechanize::Cookie", "Time"])
|
|
183
|
+
end
|
|
184
|
+
else
|
|
185
|
+
def load_yaml(yaml)
|
|
186
|
+
YAML.load(yaml) # rubocop:disable Security/YAMLLoad
|
|
187
|
+
end
|
|
184
188
|
end
|
|
185
189
|
end
|
|
186
190
|
|
data/lib/mechanize/download.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
##
|
|
2
3
|
# Download is a pluggable parser for downloading files without loading them
|
|
3
4
|
# into memory first. You may subclass this class to handle content types you
|
|
@@ -71,7 +72,7 @@ class Mechanize::Download
|
|
|
71
72
|
dirname = File.dirname filename
|
|
72
73
|
FileUtils.mkdir_p dirname
|
|
73
74
|
|
|
74
|
-
open
|
|
75
|
+
::File.open(filename, 'wb')do |io|
|
|
75
76
|
until @body_io.eof? do
|
|
76
77
|
io.write @body_io.read 16384
|
|
77
78
|
end
|
data/lib/mechanize/file.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
##
|
|
2
3
|
# This is the base class for the Pluggable Parsers. If Mechanize cannot find
|
|
3
4
|
# an appropriate class to use for the content type, this class will be used.
|
|
@@ -82,7 +83,7 @@ class Mechanize::File
|
|
|
82
83
|
dirname = File.dirname filename
|
|
83
84
|
FileUtils.mkdir_p dirname
|
|
84
85
|
|
|
85
|
-
open
|
|
86
|
+
::File.open(filename, 'wb')do |f|
|
|
86
87
|
f.write body
|
|
87
88
|
end
|
|
88
89
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
##
|
|
2
3
|
# Wrapper to make a file URI work like an http URI
|
|
3
4
|
|
|
@@ -10,8 +11,9 @@ class Mechanize::FileConnection
|
|
|
10
11
|
end
|
|
11
12
|
|
|
12
13
|
def request uri, request
|
|
13
|
-
|
|
14
|
+
file_path = uri.select(:host, :path)
|
|
15
|
+
.select { |part| part && (part.length > 0) }
|
|
16
|
+
.join(":")
|
|
17
|
+
yield Mechanize::FileResponse.new(Mechanize::Util.uri_unescape(file_path))
|
|
14
18
|
end
|
|
15
|
-
|
|
16
19
|
end
|
|
17
|
-
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
##
|
|
2
3
|
# Fake response for dealing with file:/// requests
|
|
3
4
|
|
|
4
5
|
class Mechanize::FileResponse
|
|
5
6
|
|
|
7
|
+
attr_reader :file_path
|
|
8
|
+
|
|
6
9
|
def initialize(file_path)
|
|
7
10
|
@file_path = file_path
|
|
8
11
|
@uri = nil
|
|
@@ -15,7 +18,7 @@ class Mechanize::FileResponse
|
|
|
15
18
|
if directory?
|
|
16
19
|
yield dir_body
|
|
17
20
|
else
|
|
18
|
-
open
|
|
21
|
+
::File.open(@file_path, 'rb') do |io|
|
|
19
22
|
yield io.read
|
|
20
23
|
end
|
|
21
24
|
end
|
data/lib/mechanize/file_saver.rb
CHANGED
data/lib/mechanize/form/field.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
##
|
|
2
3
|
# This class represents a select list where multiple values can be selected.
|
|
3
4
|
# MultiSelectList#value= accepts an array, and those values are used as
|
|
@@ -35,7 +36,7 @@ class Mechanize::Form::MultiSelectList < Mechanize::Form::Field
|
|
|
35
36
|
# select_list.option_with(:value => '1').value = 'foo'
|
|
36
37
|
|
|
37
38
|
##
|
|
38
|
-
# :
|
|
39
|
+
# :method: option_with!(criteria)
|
|
39
40
|
#
|
|
40
41
|
# Same as +option_with+ but raises an ElementNotFoundError if no button
|
|
41
42
|
# matches +criteria+
|
data/lib/mechanize/form/reset.rb
CHANGED
data/lib/mechanize/form/text.rb
CHANGED