bookmeter_scraper 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6c328c66bbd91ea36ee0471c01f4e16a69ffd347
4
- data.tar.gz: d1d5fde5a9d223c0aada00c670d1feed0b5e9c3a
3
+ metadata.gz: a8d0b08d6fe209f678ebda3c621b41412a575aef
4
+ data.tar.gz: 1d9db389c1c0ac92216c00e76f7a025327ed77c7
5
5
  SHA512:
6
- metadata.gz: 9a2c3a6149faa92850aca03c455bd5ccd95f8eddaee005e4befd4daa328c340e171df5018803f9feb0ebb0f7fdf630f91d9b9259c52fb358f5b3ccf5570595e7
7
- data.tar.gz: dcbf2db1efa63928b1c00a00d35af13ffba46345578c84b40b26a9b320ba69acd899c66c9319af5e15894a3d4e5ccc5fadbf64136fbbcbea804a0097f0729251
6
+ metadata.gz: 9df797a4925a93e8cb8a7f07e38bbd4b1288acadd27a2d0e32fd3e0161120a843dd3b2c5c184c7116e90bb6d8b52a2cacfc246a04f7ede74b6081359882f2d51
7
+ data.tar.gz: ba4d5f59e35034facda467d469a0f2ef3cfef10829f2e75a82af6a839233fe2ff0e588a9c1535db25bc48eb24a2d08fd81d614b67f1c92d66b2656b0603fc303
data/README.ja.md CHANGED
@@ -28,7 +28,16 @@ require 'bookmeter_scraper'
28
28
 
29
29
  ### ログイン
30
30
 
31
- 書籍情報、お気に入り / お気に入られユーザ情報を取得するには、`Bookmeter.log_in` でログインしておく必要があります。
31
+ 書籍情報、お気に入り / お気に入られユーザ情報を取得するには、`Bookmeter.log_in` または `Bookmeter#log_in` でログインしておく必要があります。
32
+
33
+ ログイン情報の入力には以下の 2 通りの方法があります。
34
+
35
+ 1. 引数として渡す
36
+ 2. `config.yml` へ記述しておく
37
+
38
+ #### 1. 引数として渡す
39
+
40
+ 以下のように `Bookmeter.log_in` へメールアドレスとパスワードを引数として渡すことで、ログインできます。
32
41
 
33
42
  ```ruby
34
43
  bookmeter = BookmeterScraper::Bookmeter.log_in('example@example.com', 'password')
@@ -42,6 +51,22 @@ bookmeter = BookmeterScraper::Bookmeter.new
42
51
  bookmeter.log_in('example@example.com', 'password')
43
52
  ```
44
53
 
54
+ #### 2. `config.yml` へ記述しておく
55
+
56
+ まず、以下のように YAML ファイル `config.yml` を記述し、Ruby スクリプトを実行する場所と同じディレクトリに置きます。
57
+
58
+ ```yml
59
+ mail: example@example.com
60
+ password: your_password
61
+ ```
62
+
63
+ 次に、引数なしで `Bookmeter.log_in` または `Bookmeter#log_in` を呼ぶと、`config.yml` からログイン情報を読みとり、ログインできます。
64
+
65
+ ```ruby
66
+ bookmeter = BookmeterScraper::Bookmeter.log_in
67
+ bookmeter.logged_in? # true
68
+ ```
69
+
45
70
  ### 書籍情報の取得
46
71
 
47
72
  以下の書籍情報
@@ -62,10 +87,17 @@ books = bookmeter.read_books # ログインユーザの「読んだ本」
62
87
  bookmeter.read_books('01010101') # 他のユーザの ID を指定して、そのユーザの「読んだ本」を取得
63
88
  ```
64
89
 
65
- 書籍情報は書名 `name` と読了日(初読了日と再読日の両方)の配列 `read_dates` を属性として持つ `Struct` の配列として取得できます。
90
+ 書籍情報は
91
+
92
+ - 書名 `name`
93
+ - 著者 `author`
94
+ - 読了日(初読了日と再読日の両方)の配列 `read_dates`
95
+
96
+ を属性として持つ `Struct` の配列として取得できます。
66
97
 
67
98
  ```ruby
68
99
  books[0].name
100
+ books[0].author
69
101
  books[0].read_dates
70
102
  ```
71
103
 
@@ -95,6 +127,7 @@ books = bookmeter.read_books_in(2016, 1, '01010101') # ID で指定した他
95
127
  ```ruby
96
128
  books = bookmeter.reading_books # ログインユーザの「読んでる本」を取得
97
129
  books[0].name
130
+ books[0].author
98
131
  books[0].read_dates # 読了日の Array は空
99
132
 
100
133
  bookmeter.tsundoku # ログインユーザの「積読本」を取得
data/README.md CHANGED
@@ -32,10 +32,19 @@ require 'bookmeter_scraper'
32
32
 
33
33
  ### Log in
34
34
 
35
- You need to log in Bookmeter to get books and followings / followers information by `Bookmeter.log_in`:
35
+ You need to log in Bookmeter to get books and followings / followers information by `Bookmeter.log_in` or `Bookmeter#log_in`.
36
+
37
+ There are 2 ways to input authentication information:
38
+
39
+ 1. Passing as arguments
40
+ 2. Writing out to `config.yml`
41
+
42
+ #### 1. Passing as arguments
43
+
44
+ You can log in Bookmeter by passing mail address and password to `Bookmeter.log_in`:
36
45
 
37
46
  ```ruby
38
- bookmeter = BookmeterScraper::Bookmeter.log_in('example@example.com', 'password')
47
+ bookmeter = BookmeterScraper::Bookmeter.log_in('example@example.com', 'your_password')
39
48
  bookmeter.logged_in? # true
40
49
  ```
41
50
 
@@ -46,6 +55,23 @@ bookmeter = BookmeterScraper::Bookmeter.new
46
55
  bookmeter.log_in('example@example.com', 'password')
47
56
  ```
48
57
 
58
+ #### 2. Writing out to `config.yml`
59
+
60
+ Create `config.yml` as followings and save it to the same directory as your Ruby script:
61
+
62
+ ```yml
63
+ mail: example@example.com
64
+ password: your_password
65
+ ```
66
+
67
+ Now you can log in Bookmeter by calling `Bookmeter.log_in` or `Bookmeter#log_in` with no arguments:
68
+
69
+ ```ruby
70
+ bookmeter = BookmeterScraper::Bookmeter.log_in
71
+ bookmeter.logged_in? # true
72
+ ```
73
+
74
+
49
75
  ### Get books information
50
76
 
51
77
  You can get books information:
@@ -18,11 +18,13 @@ Gem::Specification.new do |spec|
18
18
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_development_dependency "bundler", "~> 1.10"
22
- spec.add_development_dependency "rake", "~> 10.0"
23
- spec.add_development_dependency "rspec", "~> 3.4"
24
- spec.add_development_dependency "webmock", "~> 1.22"
21
+ spec.required_ruby_version = '>= 2.0'
25
22
 
26
- spec.add_dependency "yasuri", "~> 0.0"
27
- spec.add_dependency "mechanize", "~> 2.7"
23
+ spec.add_development_dependency "bundler"
24
+ spec.add_development_dependency "rake"
25
+ spec.add_development_dependency "rspec"
26
+ spec.add_development_dependency "webmock"
27
+
28
+ spec.add_dependency "mechanize"
29
+ spec.add_dependency "yasuri"
28
30
  end
@@ -1,2 +1,3 @@
1
1
  require 'bookmeter_scraper/bookmeter'
2
+ require 'bookmeter_scraper/configuration'
2
3
  require 'bookmeter_scraper/version'
@@ -1,16 +1,39 @@
1
+ require 'forwardable'
1
2
  require 'mechanize'
2
3
  require 'yasuri'
3
4
 
4
5
  module BookmeterScraper
5
6
  class Bookmeter
7
+ DEFAULT_CONFIG_PATH = './config.yml'.freeze
8
+
6
9
  ROOT_URI = 'http://bookmeter.com'.freeze
7
10
  LOGIN_URI = "#{ROOT_URI}/login".freeze
8
11
 
9
12
  PROFILE_ATTRIBUTES = %i(name gender age blood_type job address url description first_day elapsed_days read_books_count read_pages_count reviews_count bookshelfs_count)
10
13
  Profile = Struct.new(*PROFILE_ATTRIBUTES)
11
14
 
12
- BOOK_ATTRIBUTES = %i(name read_dates)
15
+ BOOK_ATTRIBUTES = %i(name author read_dates)
13
16
  Book = Struct.new(*BOOK_ATTRIBUTES)
17
+ class Books
18
+ extend Forwardable
19
+
20
+ def_delegator :@books, :[]
21
+ def_delegator :@books, :[]=
22
+ def_delegator :@books, :<<
23
+ def_delegator :@books, :each
24
+ def_delegator :@books, :flatten!
25
+
26
+ def initialize; @books = []; end
27
+
28
+ def concat(books)
29
+ books.each do |book|
30
+ next if @books.any? { |b| b.name == book.name && b.author == book.author }
31
+ @books << book
32
+ end
33
+ end
34
+
35
+ def to_a; @books; end
36
+ end
14
37
 
15
38
  USER_ATTRIBUTES = %i(name id)
16
39
  User = Struct.new(*USER_ATTRIBUTES)
@@ -71,7 +94,7 @@ module BookmeterScraper
71
94
  "#{ROOT_URI}/u/#{user_id}/favorited_user"
72
95
  end
73
96
 
74
- def self.log_in(mail, password)
97
+ def self.log_in(mail = nil, password = nil)
75
98
  Bookmeter.new.tap do |bookmeter|
76
99
  bookmeter.log_in(mail, password)
77
100
  end
@@ -81,22 +104,26 @@ module BookmeterScraper
81
104
  def initialize(agent = nil)
82
105
  @agent = agent.nil? ? Bookmeter.new_agent : agent
83
106
  @logged_in = false
107
+ @log_in_user_id = nil
108
+ @book_pages = {}
84
109
  end
85
110
 
86
- def log_in(mail, password)
111
+ def log_in(mail = nil, password = nil)
87
112
  raise BookmeterError if @agent.nil?
88
113
 
89
- next_page = nil
114
+ config = Configuration.new(DEFAULT_CONFIG_PATH) if mail.nil? && password.nil?
115
+
116
+ page_after_submitting_form = nil
90
117
  page = @agent.get(LOGIN_URI) do |page|
91
- next_page = page.form_with(action: '/login') do |form|
92
- form.field_with(name: 'mail').value = mail
93
- form.field_with(name: 'password').value = password
118
+ page_after_submitting_form = page.form_with(action: '/login') do |form|
119
+ form.field_with(name: 'mail').value = config ? config.mail : mail
120
+ form.field_with(name: 'password').value = config ? config.password : password.to_s
94
121
  end.submit
95
122
  end
96
- @logged_in = next_page.uri.to_s == ROOT_URI + '/'
123
+ @logged_in = page_after_submitting_form.uri.to_s == ROOT_URI + '/'
97
124
  return unless logged_in?
98
125
 
99
- mypage = next_page.link_with(text: 'マイページ').click
126
+ mypage = page_after_submitting_form.link_with(text: 'マイページ').click
100
127
  @log_in_user_id = extract_user_id(mypage)
101
128
  end
102
129
 
@@ -124,32 +151,32 @@ module BookmeterScraper
124
151
  def read_books(user_id = @log_in_user_id)
125
152
  books = get_books(user_id, :read_books_uri)
126
153
  books.each { |b| yield b } if block_given?
127
- books
154
+ books.to_a
128
155
  end
129
156
 
130
157
  def read_books_in(year, month, user_id = @log_in_user_id)
131
158
  date = Time.local(year, month)
132
159
  books = get_read_books(user_id, date)
133
160
  books.each { |b| yield b } if block_given?
134
- books
161
+ books.to_a
135
162
  end
136
163
 
137
164
  def reading_books(user_id = @log_in_user_id)
138
165
  books = get_books(user_id, :reading_books_uri)
139
166
  books.each { |b| yield b } if block_given?
140
- books
167
+ books.to_a
141
168
  end
142
169
 
143
170
  def tsundoku(user_id = @log_in_user_id)
144
171
  books = get_books(user_id, :tsundoku_uri)
145
172
  books.each { |b| yield b } if block_given?
146
- books
173
+ books.to_a
147
174
  end
148
175
 
149
176
  def wish_list(user_id = @log_in_user_id)
150
177
  books = get_books(user_id, :wish_list_uri)
151
178
  books.each { |b| yield b } if block_given?
152
- books
179
+ books.to_a
153
180
  end
154
181
 
155
182
  def followings(user_id = @log_in_user_id)
@@ -164,7 +191,9 @@ module BookmeterScraper
164
191
 
165
192
  def self.new_agent
166
193
  agent = Mechanize.new do |a|
167
- a.user_agent_alias = 'Mac Safari'
194
+ a.user_agent_alias = Mechanize::AGENT_ALIASES.keys.reject do |ua_alias|
195
+ %w(Android iPad iPhone Mechanize).include?(ua_alias)
196
+ end.sample
168
197
  end
169
198
  end
170
199
 
@@ -173,7 +202,7 @@ module BookmeterScraper
173
202
  end
174
203
 
175
204
  def get_books(user_id, uri_method)
176
- books = []
205
+ books = Books.new
177
206
  scraped_pages = scrape_book_pages(user_id, uri_method)
178
207
  scraped_pages.each do |page|
179
208
  books << get_book_structs(page)
@@ -183,7 +212,7 @@ module BookmeterScraper
183
212
  end
184
213
 
185
214
  def get_read_books(user_id, target_ym)
186
- result = []
215
+ result = Books.new
187
216
  scrape_book_pages(user_id, :read_books_uri).each do |page|
188
217
  first_book_date = get_read_date(page['book_1_link'])
189
218
  last_book_date = get_last_book_date(page)
@@ -217,7 +246,7 @@ module BookmeterScraper
217
246
  end
218
247
 
219
248
  def get_target_books(target_ym, page)
220
- target_books = []
249
+ target_books = Books.new
221
250
 
222
251
  1.upto(NUM_BOOKS_PER_PAGE) do |i|
223
252
  next if page["book_#{i}_link"].empty?
@@ -245,7 +274,8 @@ module BookmeterScraper
245
274
  end
246
275
  end
247
276
  book_name = get_book_name(page["book_#{i}_link"])
248
- book = Book.new(book_name, read_dates)
277
+ book_author = get_book_author(page["book_#{i}_link"])
278
+ book = Book.new(book_name, book_author, read_dates)
249
279
  target_books << book
250
280
  end
251
281
 
@@ -282,28 +312,35 @@ module BookmeterScraper
282
312
  books_root.inject(@agent, books_page)
283
313
  end
284
314
 
285
- def get_book_name(book_link)
286
- @agent.get(ROOT_URI + book_link).search('#title').text
315
+ def get_book_page(book_uri)
316
+ @book_pages[book_uri] = @agent.get(ROOT_URI + book_uri) unless @book_pages[book_uri]
317
+ @book_pages[book_uri]
318
+ end
319
+
320
+ def get_book_name(book_uri)
321
+ get_book_page(book_uri).search('#title').text
322
+ end
323
+
324
+ def get_book_author(book_uri)
325
+ get_book_page(book_uri).search('#author_name').text
287
326
  end
288
327
 
289
- def get_read_date(book_link)
290
- book_page = @agent.get(ROOT_URI + book_link)
328
+ def get_read_date(book_uri)
291
329
  book_date = Yasuri.struct_date '//*[@id="book_edit_area"]/form[1]/div[2]' do
292
330
  text_year '//*[@id="read_date_y"]/option[1]', truncate: /\d+/, proc: :to_i
293
331
  text_month '//*[@id="read_date_m"]/option[1]', truncate: /\d+/, proc: :to_i
294
332
  text_day '//*[@id="read_date_d"]/option[1]', truncate: /\d+/, proc: :to_i
295
333
  end
296
- book_date.inject(@agent, book_page)
334
+ book_date.inject(@agent, get_book_page(book_uri))
297
335
  end
298
336
 
299
- def get_reread_date(book_link)
300
- book_page = @agent.get(ROOT_URI + book_link)
337
+ def get_reread_date(book_uri)
301
338
  book_reread_date = Yasuri.struct_reread_date '//*[@id="book_edit_area"]/div/form[1]/div[2]' do
302
339
  text_reread_year '//div[@class="reread_box"]/form[1]/div[2]/select[1]/option[1]', truncate: /\d+/, proc: :to_i
303
340
  text_reread_month '//div[@class="reread_box"]/form[1]/div[2]/select[2]/option[1]', truncate: /\d+/, proc: :to_i
304
341
  text_reread_day '//div[@class="reread_box"]/form[1]/div[2]/select[3]/option[1]', truncate: /\d+/, proc: :to_i
305
342
  end
306
- book_reread_date.inject(@agent, book_page)
343
+ book_reread_date.inject(@agent, get_book_page(book_uri))
307
344
  end
308
345
 
309
346
  def get_book_structs(page)
@@ -329,7 +366,8 @@ module BookmeterScraper
329
366
  end
330
367
 
331
368
  book_name = get_book_name(page["book_#{i}_link"])
332
- book = Book.new(book_name, read_dates)
369
+ book_author = get_book_author(page["book_#{i}_link"])
370
+ book = Book.new(book_name, book_author, read_dates)
333
371
  books << book
334
372
  end
335
373
 
@@ -0,0 +1,19 @@
1
+ require 'yaml'
2
+
3
+ module BookmeterScraper
4
+ class Configuration
5
+ attr_reader :mail, :password
6
+
7
+ def initialize(config_file)
8
+ config = YAML.load_file(config_file)
9
+ unless config.has_key?('mail') && config.has_key?('password')
10
+ raise ConfigurationError, "#{config_file}: Invalid configuration file"
11
+ end
12
+
13
+ @mail = config['mail']
14
+ @password = config['password']
15
+ end
16
+ end
17
+
18
+ class ConfigurationError < StandardError; end
19
+ end
@@ -1,3 +1,3 @@
1
1
  module BookmeterScraper
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
metadata CHANGED
@@ -1,99 +1,99 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bookmeter_scraper
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kohei Yamamoto
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-02-26 00:00:00.000000000 Z
11
+ date: 2016-03-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '1.10'
19
+ version: '0'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '1.10'
26
+ version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '10.0'
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: '3.4'
47
+ version: '0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - "~>"
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: '3.4'
54
+ version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: webmock
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
- version: '1.22'
61
+ version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
- version: '1.22'
68
+ version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: yasuri
70
+ name: mechanize
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - "~>"
73
+ - - ">="
74
74
  - !ruby/object:Gem::Version
75
- version: '0.0'
75
+ version: '0'
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - "~>"
80
+ - - ">="
81
81
  - !ruby/object:Gem::Version
82
- version: '0.0'
82
+ version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
- name: mechanize
84
+ name: yasuri
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - "~>"
87
+ - - ">="
88
88
  - !ruby/object:Gem::Version
89
- version: '2.7'
89
+ version: '0'
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - "~>"
94
+ - - ">="
95
95
  - !ruby/object:Gem::Version
96
- version: '2.7'
96
+ version: '0'
97
97
  description: Bookmeter scraping library
98
98
  email:
99
99
  - kymmt90@gmail.com
@@ -116,6 +116,7 @@ files:
116
116
  - exe/bookmeter_scraper
117
117
  - lib/bookmeter_scraper.rb
118
118
  - lib/bookmeter_scraper/bookmeter.rb
119
+ - lib/bookmeter_scraper/configuration.rb
119
120
  - lib/bookmeter_scraper/version.rb
120
121
  homepage: https://github.com/kymmt90/bookmeter_scraper
121
122
  licenses:
@@ -129,7 +130,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
129
130
  requirements:
130
131
  - - ">="
131
132
  - !ruby/object:Gem::Version
132
- version: '0'
133
+ version: '2.0'
133
134
  required_rubygems_version: !ruby/object:Gem::Requirement
134
135
  requirements:
135
136
  - - ">="
@@ -137,7 +138,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
137
138
  version: '0'
138
139
  requirements: []
139
140
  rubyforge_project:
140
- rubygems_version: 2.5.1
141
+ rubygems_version: 2.4.5.1
141
142
  signing_key:
142
143
  specification_version: 4
143
144
  summary: Bookmeter scraping library