yasuri 2.0.11 → 3.2.0

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
- SHA1:
3
- metadata.gz: d8d6bd8c37be444f0c5568bcf20604d7bca5c223
4
- data.tar.gz: 8438eee300a7e4f73be7107cbd9417da18f5048d
2
+ SHA256:
3
+ metadata.gz: cd5fc7327c6d09b37771ac1c3ec40db2c052bf49ec9a1627e9ae49e047102856
4
+ data.tar.gz: a645f1e09ce72b73c54e2055af6fbf81bb145c8823e1d8428bb19c042bbb661d
5
5
  SHA512:
6
- metadata.gz: 107ddc8cd0310c646841e6fe6a2695313edb9692418a783e133a5d269d4a1ab39385975276ae167ac68863b9760794ebb2738832dccfc4f599686c5a9e50f244
7
- data.tar.gz: b6d089de8cd866f137ca58dd779396cd4948e080d3225cc4384f8f9cdb54f5a778cd4be85b89628938ccacbf11dfefe74ea8bd248e835971470e7a64df597411
6
+ metadata.gz: 654bd6cfe8012811283b1aa03e0dcc1200ce957ef4641eed2b5fa65956fb974070157b832e42f340d7299031756848c5118a7f43019ff94f088c49974e2304e8
7
+ data.tar.gz: 5ad07b82672ea2ceebfb8154bb91631c095e9ad8d69f3d62c0bf8d528c4c539fab2597f4112b4212bffe7ad641b30d913686e8e2bfea7dfdbdd9a4468311b6c0
@@ -0,0 +1,35 @@
1
+ # This workflow uses actions that are not certified by GitHub.
2
+ # They are provided by a third-party and are governed by
3
+ # separate terms of service, privacy policy, and support
4
+ # documentation.
5
+ # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
6
+ # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
7
+
8
+ name: Ruby
9
+
10
+ on:
11
+ push:
12
+ branches: [ master ]
13
+ pull_request:
14
+ branches: [ master ]
15
+
16
+ jobs:
17
+ test:
18
+
19
+ runs-on: ubuntu-latest
20
+ strategy:
21
+ matrix:
22
+ ruby-version: ['2.6', '2.7', '3.0']
23
+
24
+ steps:
25
+ - uses: actions/checkout@v2
26
+ - name: Set up Ruby
27
+ # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
28
+ # change this to (see https://github.com/ruby/setup-ruby#versioning):
29
+ # uses: ruby/setup-ruby@v1
30
+ uses: ruby/setup-ruby@473e4d8fe5dd94ee328fdfca9f8c9c7afc9dae5e
31
+ with:
32
+ ruby-version: ${{ matrix.ruby-version }}
33
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
34
+ - name: Run tests
35
+ run: bundle exec rake
data/.gitignore CHANGED
@@ -66,5 +66,4 @@ tramp
66
66
  # cask packages
67
67
  .cask/
68
68
 
69
- .ruby-version
70
- Gemfile.lock
69
+ Gemfile.lock
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.0.0
data/.travis.yml CHANGED
@@ -1,9 +1,7 @@
1
1
  language: ruby
2
- rvm:
3
- - 2.2.0
4
2
  script:
5
3
  - ruby --version
6
4
  - rspec spec
7
5
  addons:
8
6
  code_climate:
9
- repo_token: 0dc78d33107a7f11f257c0218ac1a37e0073005bb9734f2fd61d0f7e803fc151
7
+ repo_token: 0dc78d33107a7f11f257c0218ac1a37e0073005bb9734f2fd61d0f7e803fc151
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
- # Yasuri [![Build Status](https://travis-ci.org/tac0x2a/yasuri.svg?branch=master)](https://travis-ci.org/tac0x2a/yasuri) [![Coverage Status](https://coveralls.io/repos/tac0x2a/yasuri/badge.svg?branch=master)](https://coveralls.io/r/tac0x2a/yasuri?branch=master) [![Code Climate](https://codeclimate.com/github/tac0x2a/yasuri/badges/gpa.svg)](https://codeclimate.com/github/tac0x2a/yasuri)
1
+ # Yasuri
2
+ [![Build Status](https://github.com/tac0x2a/yasuri/actions/workflows/ruby.yml/badge.svg)](https://github.com/tac0x2a/yasuri/actions/workflows/ruby.yml)
3
+ [![Coverage Status](https://coveralls.io/repos/tac0x2a/yasuri/badge.svg?branch=master)](https://coveralls.io/r/tac0x2a/yasuri?branch=master) [![Maintainability](https://api.codeclimate.com/v1/badges/c29480fea1305afe999f/maintainability)](https://codeclimate.com/github/tac0x2a/yasuri/maintainability)
2
4
 
3
- Yasuri (鑢) is an easy web-scraping library for supporting "[Mechanize](https://github.com/sparklemotion/mechanize)".
5
+ Yasuri (鑢) is an easy web-scraping library for supporting "[Mechanize](https://github.com/sparklemotion/mechanize)", and CLI tool using it.
4
6
 
5
7
  Yasuri can reduce frequently processes in Scraping.
6
8
 
@@ -31,7 +33,10 @@ or
31
33
 
32
34
  ```ruby
33
35
  # for Ruby 1.9.3 or lower
34
- gem 'yasuri', '~> 1.9'
36
+ gem 'yasuri', '~> 2.0', '>= 2.0.13'
37
+
38
+ # for Ruby 3.0.0 or lower
39
+ gem 'yasuri', '~> 3.1'
35
40
  ```
36
41
 
37
42
 
@@ -44,6 +49,7 @@ Or install it yourself as:
44
49
  $ gem install yasuri
45
50
 
46
51
  ## Usage
52
+ ### Use as library
47
53
 
48
54
  ```ruby
49
55
  # Node tree constructing by DSL
@@ -52,32 +58,95 @@ root = Yasuri.links_root '//*[@id="menu"]/ul/li/a' do
52
58
  text_content '//*[@id="contents"]/p[1]'
53
59
  end
54
60
 
61
+
62
+ # Node tree constructing by YAML
63
+ src = <<-EOYAML
64
+ links_root:
65
+ path: "//*[@id='menu']/ul/li/a"
66
+ text_title: "//*[@id='contents']/h2"
67
+ text_content: "//*[@id='contents']/p[1]"
68
+ EOYAML
69
+ root = Yasuri.yaml2tree(src)
70
+
71
+
55
72
  # Node tree constructing by JSON
56
73
  src = <<-EOJSON
57
- { "node" : "links",
58
- "name" : "root",
59
- "path" : "//*[@id='menu']/ul/li/a",
60
- "children" : [
61
- { "node" : "text",
62
- "name" : "title",
63
- "path" : "//*[@id='contents']/h2"
64
- },
65
- { "node" : "text",
66
- "name" : "content",
67
- "path" : "//*[@id='contents']/p[1]"
68
- }
69
- ]
70
- }
74
+ {
75
+ "links_root": {
76
+ "path": "//*[@id='menu']/ul/li/a",
77
+ "text_title": "//*[@id='contents']/h2",
78
+ "text_content": "//*[@id='contents']/p[1]"
79
+ }
80
+ }
71
81
  EOJSON
72
82
  root = Yasuri.json2tree(src)
73
83
 
84
+
85
+ # Execution and getting scraped result
74
86
  agent = Mechanize.new
75
- root_page = agent.get("http://some.scraping.page.net/")
87
+ root_page = agent.get("http://some.scraping.page.tac42.net/")
76
88
 
77
89
  result = root.inject(agent, root_page)
78
- # => [ {"title" => "PageTitle", "content" => "Page Contents" }, ... ]
90
+ # => [
91
+ # {"title" => "PageTitle 01", "content" => "Page Contents 01" },
92
+ # {"title" => "PageTitle 02", "content" => "Page Contents 02" },
93
+ # ...
94
+ # {"title" => "PageTitle N", "content" => "Page Contents N" }
95
+ # ]
96
+ ```
97
+
98
+ ### Use as CLI
99
+
100
+ ```sh
101
+ # After gem installation..
102
+ $ yasuri help scrape
103
+ Usage:
104
+ yasuri scrape <URI> [[--file <TREE_FILE>] or [--json <JSON>]]
105
+
106
+ Options:
107
+ f, [--file=FILE] # path to file that written yasuri tree as json or yaml
108
+ j, [--json=JSON] # yasuri tree format json string
109
+
110
+ Getting from <URI> and scrape it. with <JSON> or json/yml from <TREE_FILE>. They should be Yasuri's format json or yaml string.
79
111
  ```
80
112
 
113
+ Example
114
+ ```sh
115
+ $ yasuri scrape "https://www.ruby-lang.org/en/" -j '
116
+ {
117
+ "text_title": "/html/head/title",
118
+ "text_desc": "//*[@id=\"intro\"]/p"
119
+ }'
120
+
121
+ {"title":"Ruby Programming Language","desc":"\n A dynamic, open source programming language with a focus on\n simplicity and productivity. It has an elegant syntax that is\n natural to read and easy to write.\n "}
122
+ ```
123
+
124
+ ## Dev
125
+ ```sh
126
+ $ gem install bundler
127
+ $ bundle install
128
+ ```
129
+ ### Test
130
+ ```sh
131
+ $ rake
132
+ # or
133
+ $ rspec spec/*spec.rb
134
+ ```
135
+
136
+ ### Test gem in local
137
+ ```sh
138
+ $ gem build yasuri.gemspec
139
+ $ gem install yasuri-*.gem
140
+ ```
141
+ ### Release RubyGems
142
+ ```sh
143
+ # Only first time
144
+ $ curl -u <user_name> https://rubygems.org/api/v1/api_key.yaml > ~/.gem/credentials
145
+ $ chmod 0600 ~/.gem/credentials
146
+
147
+ $ nano lib/yasuri/version.rb # edit gem version
148
+ $ rake release
149
+ ```
81
150
 
82
151
  ## Contributing
83
152
 
data/USAGE.ja.md CHANGED
@@ -1,24 +1,31 @@
1
- # Yasuri の使い方
1
+ # Yasuri
2
2
 
3
3
  ## Yasuri とは
4
- Yasuri (鑢) は簡単にWebスクレイピングを行うための、"[Mechanize](https://github.com/sparklemotion/mechanize)" をサポートするライブラリです.
4
+ Yasuri (鑢) Webスクレイピングを宣言的に行うためのライブラリと、それを用いたスクレイピングのコマンドラインツールです。
5
+ 簡単な宣言的記法で期待結果を記述するだけで、"[Mechanize](https://github.com/sparklemotion/mechanize)" によるスクレイピングを実行します。
5
6
 
6
7
  Yasuriは、スクレイピングにおける、よくある処理を簡単に記述することができます.
7
- 例えば、
8
+ 例えば、以下のような処理を簡単に実現することができます.
8
9
 
9
- + ページ内の複数のリンクを開いて、各ページをスクレイピングした結果をHashで取得する
10
10
  + ページ内の複数のテキストをスクレイピングし、名前をつけてHashにする
11
+ + ページ内の複数のリンクを開いて、各ページをスクレイピングした結果をHashで取得する
11
12
  + ページ内に繰り返し出現するテーブルをそれぞれスクレイピングして、配列として取得する
12
- + ページネーションで提供される各ページのうち、上位3つだけを順にスクレイピングする
13
-
14
- これらを簡単に実装することができます.
13
+ + ページネーションで提供される各ページのうち、最初の3ページだけをスクレイピングする
15
14
 
16
15
  ## クイックスタート
17
16
 
17
+ #### インストール
18
+ ```sh
19
+ # for Ruby 2.3.2
20
+ $ gem 'yasuri', '~> 2.0', '>= 2.0.13'
18
21
  ```
22
+ または
23
+ ```sh
24
+ # for Ruby 3.0.0 or upper
19
25
  $ gem install yasuri
20
26
  ```
21
27
 
28
+ #### ライブラリとして使う
22
29
  ```ruby
23
30
  require 'yasuri'
24
31
  require 'machinize'
@@ -30,82 +37,148 @@ root = Yasuri.links_root '//*[@id="menu"]/ul/li/a' do
30
37
  end
31
38
 
32
39
  agent = Mechanize.new
33
- root_page = agent.get("http://some.scraping.page.net/")
40
+ root_page = agent.get("http://some.scraping.page.tac42.net/")
34
41
 
35
42
  result = root.inject(agent, root_page)
36
- # => [ {"title" => "PageTitle1", "content" => "Page Contents1" },
37
- # {"title" => "PageTitle2", "content" => "Page Contents2" }, ... ]
38
-
43
+ # => [
44
+ # {"title" => "PageTitle 01", "content" => "Page Contents 01" },
45
+ # {"title" => "PageTitle 02", "content" => "Page Contents 02" },
46
+ # ...
47
+ # {"title" => "PageTitle N", "content" => "Page Contents N" }
48
+ # ]
39
49
  ```
50
+
40
51
  この例では、 LinkNode(`links_root`)の xpath で指定された各リンク先のページから、TextNode(`text_title`,`text_content`) の xpath で指定された2つのテキストをスクレイピングする例です.
41
52
 
42
53
  (言い換えると、`//*[@id="menu"]/ul/li/a` で示される各リンクを開いて、`//*[@id="contents"]/h2` と `//*[@id="contents"]/p[1]` で指定されたテキストをスクレイピングします)
43
54
 
44
- ## 基本
45
55
 
46
- 1. パースツリーを作る
47
- 2. Mechanize の agent と対象のページを与えてパースを開始する
56
+ #### CLIツールとして使う
57
+ 上記と同じことを、CLIのコマンドとして実行できます。
58
+
59
+ ```sh
60
+ $ yasuri scrape "http://some.scraping.page.tac42.net/" -j '
61
+ {
62
+ "links_root": {
63
+ "path": "//*[@id=\"menu\"]/ul/li/a",
64
+ "text_title": "//*[@id=\"contents\"]/h2",
65
+ "text_content": "//*[@id=\"contents\"]/p[1]"
66
+ }
67
+ }'
68
+
69
+ [
70
+ {"title":"PageTitle 01","content":"Page Contents 01"},
71
+ {"title":"PageTitle 02","content":"Page Contents 02"},
72
+ ...,
73
+ {"title":"PageTitle N","content":"Page Contents N"}
74
+ ]
75
+ ```
48
76
 
77
+ 結果はjson形式の文字列として取得できます。
49
78
 
50
- ### パースツリーを作る
79
+ ----------------------------
80
+ ## パースツリー
51
81
 
52
- ```ruby
53
- require 'mechanize'
54
- require 'yasuri'
82
+ パースツリーとは、スクレイピングする要素と出力構造を宣言的に定義するための木構造データです。
83
+ パースツリーは入れ子になった Node で構成されます.Node は `Type`, `Name`, `Path`, `Childlen`, `Options` 属性を持っており、その `Type` に応じたスクレイピング処理を行います.(ただし、`MapNode` のみ `Path` を持ちません)
55
84
 
56
85
 
57
- # 1. パースツリーを作る
58
- tree = Yasuri.links_title '/html/body/a' do
59
- text_name '/html/body/p'
60
- end
86
+ パースツリーは以下のフォーマットで定義されます.
61
87
 
62
- # 2. Mechanize の agent と対象のページを与えてパースを開始する
63
- agent = Mechanize.new
64
- page = agent.get(uri)
88
+ ```ruby
89
+ # 1ノードからなる単純なツリー
90
+ Yasuri.<Type>_<Name> <Path> [,<Options>]
65
91
 
92
+ # 入れ子になっているツリー
93
+ Yasuri.<Type>_<Name> <Path> [,<Options>] do
94
+ <Type>_<Name> <Path> [,<Options>] do
95
+ <Type>_<Name> <Path> [,<Options>]
96
+ ...
97
+ end
98
+ end
99
+ ```
66
100
 
67
- tree.inject(agent, page)
101
+ **例**
102
+
103
+ ```ruby
104
+ # 1ノードからなる単純なツリー
105
+ Yasuri.text_title '/html/head/title', truncate:/^[^,]+/
106
+
107
+ # 入れ子になっているツリー
108
+ Yasuri.links_root '//*[@id="menu"]/ul/li/a' do
109
+ struct_table './tr' do
110
+ text_title './td[1]'
111
+ text_pub_date './td[2]'
112
+ end
113
+ end
68
114
  ```
69
115
 
70
- ツリーは、DSLまたはjsonで定義することができます.上の例ではDSLで定義しています.
71
- 以下は、jsonで上記と等価な解析ツリーを定義した例です.
72
116
 
117
+ パースツリーはRubyのDSL、JSON、YAMLのいずれかで定義することができます。
118
+ 以下は、上記と同じパースツリーをそれぞれの記法で定義した例です。
119
+
120
+ **Ruby DSLで定義する場合**
73
121
  ```ruby
74
- # json で構成する場合
75
- src = <<-EOJSON
76
- { "node" : "links",
77
- "name" : "title",
78
- "path" : "/html/body/a",
79
- "children" : [
80
- { "node" : "text",
81
- "name" : "name",
82
- "path" : "/html/body/p"
83
- }
84
- ]
85
- }
86
- EOJSON
87
- tree = Yasuri.json2tree(src)
122
+ Yasuri.links_title '/html/body/a' do
123
+ text_name '/html/body/p'
124
+ end
88
125
  ```
89
126
 
127
+ **JSONで定義する場合**
128
+ ```json
129
+ {
130
+ links_title": {
131
+ "path": "/html/body/a",
132
+ "text_name": "/html/body/p"
133
+ }
134
+ }
135
+ ```
90
136
 
91
- ### Node
92
- ツリーは入れ子になった *Node* で構成されます.
93
- Node は `Type`, `Name`, `Path`, `Childlen`, `Options` を持っています.
137
+ **YAMLで定義する場合**
138
+ ```yaml
139
+ links_title:
140
+ path: "/html/body/a"
141
+ text_name: "/html/body/p"
142
+ ```
94
143
 
95
- Nodeは以下のフォーマットで定義されます.
144
+ **パースツリーの特殊なケース**
96
145
 
97
- ```ruby
98
- # トップレベル
99
- Yasuri.<Type>_<Name> <Path> [,<Options>]
146
+ rootの直下の要素が1つだけの場合、Hash(Object)ではなく、その要素を直接返します。
147
+ ```json
148
+ {
149
+ "text_title": "/html/head/title",
150
+ "text_body": "/html/body",
151
+ }
152
+ # => {"title": "Welcome to yasuri!", "body": "Yasuri is ..."}
100
153
 
101
- # 入れ子になっている場合
102
- Yasuri.<Type>_<Name> <Path> [,<Options>] do
103
- <Type>_<Name> <Path> [,<Options>] do
104
- <Children>
105
- end
106
- end
154
+ {
155
+ "text_title": "/html/head/title"}
156
+ }
157
+ # => Welcome to yasuri!
158
+ ```
159
+
160
+
161
+ jsonまたはyaml形式では、子Nodeを持たない場合、`path` を直接値に指定することができます。以下の2つのjsonは同じパースツリーになります。
162
+
163
+ ```json
164
+ {
165
+ "text_name": "/html/body/p"
166
+ }
167
+
168
+ {
169
+ "text_name": {
170
+ "path": "/html/body/p"
171
+ }
172
+ }
107
173
  ```
108
174
 
175
+
176
+ --------------------------
177
+ ## Node
178
+
179
+ Nodeはパースツリーの節または葉となる要素で、`Type`, `Name`, `Path`, `Childlen`, `Options` を持っており、その `Type` に応じてスクレイピングを行います.(ただし、`MapNode` のみ `Path` を持ちません)
180
+
181
+
109
182
  #### Type
110
183
  *Type* は Nodeの振る舞いを示します.Typeには以下のものがあります.
111
184
 
@@ -113,18 +186,21 @@ end
113
186
  - *Struct*
114
187
  - *Links*
115
188
  - *Paginate*
189
+ - *Map*
190
+
191
+ 詳細は各ノードの説明を参照してください。
116
192
 
117
- ### Name
193
+ #### Name
118
194
  *Name* は 解析結果のHashにおけるキーになります.
119
195
 
120
- ### Path
196
+ #### Path
121
197
  *Path* は xpath あるいは css セレクタによって、HTML上の特定のノードを指定します.
122
198
  これは Machinize の `search` で使用されます.
123
199
 
124
- ### Childlen
200
+ #### Childlen
125
201
  入れ子になっているノードの子ノードです.TextNodeはツリーの葉に当たるため、子ノードを持ちません.
126
202
 
127
- ### Options
203
+ #### Options
128
204
  パースのオプションです.オプションはTypeごとに異なります.
129
205
  各ノードに対して、`opt`メソッドをコールすることで、利用可能なオプションを取得できます.
130
206
 
@@ -156,13 +232,16 @@ page = agent.get("http://yasuri.example.net")
156
232
 
157
233
  p1 = Yasuri.text_title '/html/body/p[1]'
158
234
  p1t = Yasuri.text_title '/html/body/p[1]', truncate:/^[^,]+/
159
- p2u = Yasuri.text_title '/html/body/p[2]', proc: :upcase
235
+ p2u = Yasuri.text_title '/html/body/p[1]', proc: :upcase
160
236
 
161
- p1.inject(agent, page) #=> { "title" => "Hello,World" }
162
- p1t.inject(agent, page) #=> { "title" => "Hello" }
163
- node.inject(agent, page) #=> { "title" => "HELLO,YASURI" }
237
+ p1.inject(agent, page) #=> "Hello,World"
238
+ p1t.inject(agent, page) #=> "Hello"
239
+ p2u.inject(agent, page) #=> "HELLO,WORLD"
164
240
  ```
165
241
 
242
+ なお、同じページ内の複数の要素を一度にスクレイピングする場合は、`MapNode`を使用します。詳細は、`MapNode`の例を参照してください。
243
+
244
+
166
245
  ### オプション
167
246
  ##### `truncate`
168
247
  正規表現にマッチした文字列を取り出します.グループを指定した場合、最初にマッチしたグループだけを返します.
@@ -431,3 +510,186 @@ node.inject(agent, page)
431
510
  #=> [ {"content" => "Pagination01"}, {"content" => "Pagination02"}]
432
511
  ```
433
512
  この場合、PaginateNode は最大2つまでのページを開いてパースします.ページネーションは4つのページを持っているようですが、`limit:2`が指定されているため、結果の配列には2つの結果のみが含まれています.
513
+
514
+ ##### `flatten`
515
+ 取得した各ページの結果を展開します.
516
+
517
+ ```ruby
518
+ agent = Mechanize.new
519
+ page = agent.get("http://yasuri.example.net/page01.html")
520
+
521
+ node = Yasuri.pages_root "/html/body/nav/span/a[@class='next']" , flatten:true do
522
+ text_title '/html/head/title'
523
+ text_content '/html/body/p'
524
+ end
525
+ node.inject(agent, page)
526
+
527
+ #=> [ {"title" => "Page01",
528
+ "content" => "Patination01"},
529
+ {"title" => "Page01",
530
+ "content" => "Patination02"},
531
+ {"title" => "Page01",
532
+ "content" => "Patination03"}]
533
+
534
+
535
+ node = Yasuri.pages_root "/html/body/nav/span/a[@class='next']" , flatten:true do
536
+ text_title '/html/head/title'
537
+ text_content '/html/body/p'
538
+ end
539
+ node.inject(agent, page)
540
+
541
+ #=> [ "Page01",
542
+ "Patination01",
543
+ "Page02",
544
+ "Patination02",
545
+ "Page03",
546
+ "Patination03"]
547
+ ```
548
+
549
+ ## Map Node
550
+ *MapNode* はスクレイピングした結果をまとめるノードです.このノードはパースツリーにおいて常に節です.
551
+
552
+ ### 例
553
+
554
+ ```html
555
+ <!-- http://yasuri.example.net -->
556
+ <html>
557
+ <head><title>Yasuri Example</title></head>
558
+ <body>
559
+ <p>Hello,World</p>
560
+ <p>Hello,Yasuri</p>
561
+ </body>
562
+ </html>
563
+ ```
564
+
565
+ ```ruby
566
+ agent = Mechanize.new
567
+ page = agent.get("http://yasuri.example.net")
568
+
569
+
570
+ tree = Yasuri.map_root do
571
+ text_title '/html/head/title'
572
+ text_body_p '/html/body/p[1]'
573
+ end
574
+
575
+ tree.inject(agent, page) #=> { "title" => "Yasuri Example", "body_p" => "Hello,World" }
576
+
577
+
578
+ tree = Yasuri.map_root do
579
+ map_group1 { text_child01 '/html/body/a[1]' }
580
+ map_group2 do
581
+ text_child01 '/html/body/a[1]'
582
+ text_child03 '/html/body/a[3]'
583
+ end
584
+ end
585
+
586
+ tree.inject(agent, page) #=> {
587
+ # "group1" => {
588
+ # "child01" => "child01"
589
+ # },
590
+ # "group2" => {
591
+ # "child01" => "child01",
592
+ # "child03" => "child03"
593
+ # }
594
+ # }
595
+ ```
596
+
597
+ ### オプション
598
+ なし
599
+
600
+
601
+ -------------------------
602
+ ## 使い方
603
+
604
+ #### ライブラリとして使用する場合
605
+ ライブラリとして使用する場合は、DSL, json, yaml の形式でツリーを定義できます。
606
+ ```ruby
607
+ require 'mechanize'
608
+ require 'yasuri'
609
+
610
+
611
+ # 1. パースツリーを作る
612
+ # DSLで定義する倍
613
+ tree = Yasuri.links_title '/html/body/a' do
614
+ text_name '/html/body/p'
615
+ end
616
+
617
+ # jsonで定義する場合
618
+ src = <<-EOJSON
619
+ {
620
+ links_title": {
621
+ "path": "/html/body/a",
622
+ "text_name": "/html/body/p"
623
+ }
624
+ }
625
+ EOJSON
626
+ tree = Yasuri.json2tree(src)
627
+
628
+
629
+ # yamlで定義する場合
630
+ src = <<-EOYAML
631
+ links_title:
632
+ path: "/html/body/a"
633
+ text_name: "/html/body/p"
634
+ EOYAML
635
+ tree = Yasuri.yaml2tree(src)
636
+
637
+
638
+
639
+ # 2. Mechanize の agent と対象のページを与えてパースを開始する
640
+ agent = Mechanize.new
641
+ page = agent.get(uri)
642
+
643
+
644
+ tree.inject(agent, page)
645
+ ```
646
+
647
+ #### CLIツールとして使用する場合
648
+
649
+ **ヘルプ表示**
650
+ ```sh
651
+ $ yasuri help scrape
652
+ Usage:
653
+ yasuri scrape <URI> [[--file <TREE_FILE>] or [--json <JSON>]]
654
+
655
+ Options:
656
+ f, [--file=FILE] # path to file that written yasuri tree as json or yaml
657
+ j, [--json=JSON] # yasuri tree format json string
658
+
659
+ Getting from <URI> and scrape it. with <JSON> or json/yml from <TREE_FILE>. They should be Yasuri's format json or yaml string.
660
+ ```
661
+
662
+ CLIツールでは以下のどちらかの方法でパースツリーを指定します。
663
+ + `--file`, `-f` オプションで、ファイルに出力されたjson形式またはyaml形式のパースツリーを読み込む
664
+ + `--json`, `-j` オプションで、パースツリーを文字列として直接指定する
665
+
666
+
667
+ **パースツリーをファイルで指定する例**
668
+ ```sh
669
+ % cat sample.yml
670
+ text_title: "/html/head/title"
671
+ text_desc: "//*[@id=\"intro\"]/p"
672
+
673
+ % yasuri scrape "https://www.ruby-lang.org/en/" --file sample.yml
674
+ {"title":"Ruby Programming Language","desc":"\n A dynamic, open source programming language with a focus on\n simplicity and productivity. It has an elegant syntax that is\n natural to read and easy to write.\n "}
675
+
676
+ % cat sample.json
677
+ {
678
+ "text_title": "/html/head/title",
679
+ "text_desc": "//*[@id=\"intro\"]/p"
680
+ }
681
+
682
+ % yasuri scrape "https://www.ruby-lang.org/en/" --file sample.json
683
+ {"title":"Ruby Programming Language","desc":"\n A dynamic, open source programming language with a focus on\n simplicity and productivity. It has an elegant syntax that is\n natural to read and easy to write.\n "}
684
+ ```
685
+
686
+ **パースツリーをjsonで直接指定する例**
687
+ ```sh
688
+ $ yasuri scrape "https://www.ruby-lang.org/en/" -j '
689
+ {
690
+ "text_title": "/html/head/title",
691
+ "text_desc": "//*[@id=\"intro\"]/p"
692
+ }'
693
+
694
+ {"title":"Ruby Programming Language","desc":"\n A dynamic, open source programming language with a focus on\n simplicity and productivity. It has an elegant syntax that is\n natural to read and easy to write.\n "}
695
+ ```