pyjstage2 0.1.2__tar.gz
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.
- pyjstage2-0.1.2/LICENSE +21 -0
- pyjstage2-0.1.2/MANIFEST.in +3 -0
- pyjstage2-0.1.2/PKG-INFO +160 -0
- pyjstage2-0.1.2/README.md +120 -0
- pyjstage2-0.1.2/pyjstage/__init__.py +1 -0
- pyjstage2-0.1.2/pyjstage/entry.py +76 -0
- pyjstage2-0.1.2/pyjstage/errors.py +78 -0
- pyjstage2-0.1.2/pyjstage/order.py +21 -0
- pyjstage2-0.1.2/pyjstage/parser.py +56 -0
- pyjstage2-0.1.2/pyjstage/pyjstage.py +153 -0
- pyjstage2-0.1.2/pyjstage/result.py +228 -0
- pyjstage2-0.1.2/pyjstage/service.py +11 -0
- pyjstage2-0.1.2/pyjstage/status.py +83 -0
- pyjstage2-0.1.2/pyjstage2.egg-info/PKG-INFO +160 -0
- pyjstage2-0.1.2/pyjstage2.egg-info/SOURCES.txt +23 -0
- pyjstage2-0.1.2/pyjstage2.egg-info/dependency_links.txt +1 -0
- pyjstage2-0.1.2/pyjstage2.egg-info/requires.txt +6 -0
- pyjstage2-0.1.2/pyjstage2.egg-info/top_level.txt +1 -0
- pyjstage2-0.1.2/requirements.txt +6 -0
- pyjstage2-0.1.2/setup.cfg +10 -0
- pyjstage2-0.1.2/setup.py +45 -0
- pyjstage2-0.1.2/test/test_pyjstage.py +78 -0
- pyjstage2-0.1.2/test/test_result.py +36 -0
- pyjstage2-0.1.2/test/test_status.py +138 -0
pyjstage2-0.1.2/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2020 matsurih
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
pyjstage2-0.1.2/PKG-INFO
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pyjstage2
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: J-STAGE API wrapper for Python - Python 3.12 Compatible
|
|
5
|
+
Home-page: https://github.com/lanshi17/pyjstage
|
|
6
|
+
Author: lanshi17
|
|
7
|
+
Author-email: lanshi17@users.noreply.github.com
|
|
8
|
+
License: MIT
|
|
9
|
+
Project-URL: Source, https://github.com/lanshi17/pyjstage
|
|
10
|
+
Project-URL: Original, https://github.com/matsurih/pyjstage
|
|
11
|
+
Keywords: jstage api wrapper japan science technology academic papers
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
18
|
+
Requires-Python: >=3.12
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Requires-Dist: certifi>=2023.0.0
|
|
22
|
+
Requires-Dist: chardet>=5.0.0
|
|
23
|
+
Requires-Dist: idna>=3.0
|
|
24
|
+
Requires-Dist: lxml>=5.0.0
|
|
25
|
+
Requires-Dist: requests>=2.31.0
|
|
26
|
+
Requires-Dist: urllib3>=2.0.0
|
|
27
|
+
Dynamic: author
|
|
28
|
+
Dynamic: author-email
|
|
29
|
+
Dynamic: classifier
|
|
30
|
+
Dynamic: description
|
|
31
|
+
Dynamic: description-content-type
|
|
32
|
+
Dynamic: home-page
|
|
33
|
+
Dynamic: keywords
|
|
34
|
+
Dynamic: license
|
|
35
|
+
Dynamic: license-file
|
|
36
|
+
Dynamic: project-url
|
|
37
|
+
Dynamic: requires-dist
|
|
38
|
+
Dynamic: requires-python
|
|
39
|
+
Dynamic: summary
|
|
40
|
+
|
|
41
|
+
# pyjstage2
|
|
42
|
+
|
|
43
|
+

|
|
44
|
+

|
|
45
|
+

|
|
46
|
+
|
|
47
|
+
## Overview
|
|
48
|
+
|
|
49
|
+
[J-STAGE WebAPI](https://www.jstage.jst.go.jp/static/pages/OtherJstageServices/TAB2/-char/ja) Wrapper for Python 3.
|
|
50
|
+
|
|
51
|
+
- J-STAGE is an electronic journal platform for science and technology information in Japan, developed and managed by the Japan Science and Technology Agency (JST).
|
|
52
|
+
- This package is a **Python 3.12 compatible fork** of [pyjstage](https://pypi.org/project/pyjstage/).
|
|
53
|
+
|
|
54
|
+
## Acknowledgments
|
|
55
|
+
|
|
56
|
+
This project is modified based on [matsurih/pyjstage](https://github.com/matsurih/pyjstage) (v0.0.2).
|
|
57
|
+
|
|
58
|
+
Special thanks to the original author [@matsurih](https://github.com/matsurih) for creating this useful J-STAGE API wrapper.
|
|
59
|
+
|
|
60
|
+
## What's Changed
|
|
61
|
+
|
|
62
|
+
| Package | Original | Forked |
|
|
63
|
+
|---------|----------|--------|
|
|
64
|
+
| lxml | 4.4.2 | >=5.0.0 |
|
|
65
|
+
| requests | 2.22.0 | >=2.31.0 |
|
|
66
|
+
| urllib3 | 1.25.7 | >=2.0.0 |
|
|
67
|
+
| certifi | 2019.11.28 | >=2023.0.0 |
|
|
68
|
+
|
|
69
|
+
- Fixed absolute imports to relative imports
|
|
70
|
+
- Fixed private method name mangling (`__finish_setup` → `_finish_setup`)
|
|
71
|
+
- Added `__init__.py` export for cleaner imports
|
|
72
|
+
|
|
73
|
+
## Prerequisites
|
|
74
|
+
|
|
75
|
+
- Python >= 3.12
|
|
76
|
+
|
|
77
|
+
## Installation
|
|
78
|
+
|
|
79
|
+
```shell
|
|
80
|
+
$ pip install pyjstage2
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Usage
|
|
84
|
+
|
|
85
|
+
### Basic Usage
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
from pyjstage.pyjstage import Pyjstage
|
|
89
|
+
|
|
90
|
+
jstage = Pyjstage()
|
|
91
|
+
|
|
92
|
+
# Search by ISSN
|
|
93
|
+
ret_search = jstage.search(issn='2186-6619', count=3)
|
|
94
|
+
|
|
95
|
+
# List articles in a journal
|
|
96
|
+
ret_list = jstage.list(issn='2186-6619')
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Accessing Results
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
for entry in ret_search.entries:
|
|
103
|
+
print(f"Title: {entry.title}")
|
|
104
|
+
print(f"Author: {entry.author.get('ja', '')}")
|
|
105
|
+
print(f"Journal: {entry.material_title.get('ja', '')}")
|
|
106
|
+
print(f"Year: {entry.pubyear}")
|
|
107
|
+
print(f"DOI: {entry.doi}")
|
|
108
|
+
print(f"Link: {entry.link}")
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Search Parameters
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
jstage.search(
|
|
115
|
+
pubyearfrom=2020, # Search from year
|
|
116
|
+
pubyearto=2024, # Search to year
|
|
117
|
+
material='journal', # Journal name contains
|
|
118
|
+
article='title', # Article title contains
|
|
119
|
+
author='name', # Author name contains
|
|
120
|
+
keyword='AI', # Keyword contains
|
|
121
|
+
issn='2186-6619', # ISSN
|
|
122
|
+
count=10 # Number of results (max 1000)
|
|
123
|
+
)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Important Notes
|
|
127
|
+
|
|
128
|
+
### What J-STAGE API Provides
|
|
129
|
+
|
|
130
|
+
- ✅ **Literature search** - Search by ISSN, keyword, author, year, etc.
|
|
131
|
+
- ✅ **Metadata** - Title, author, journal, year, DOI, page numbers
|
|
132
|
+
- ✅ **Article links** - Links to J-STAGE article pages
|
|
133
|
+
|
|
134
|
+
### What J-STAGE API Does NOT Provide
|
|
135
|
+
|
|
136
|
+
- ❌ **Full-text PDF download** - The API does not provide direct PDF downloads
|
|
137
|
+
- ❌ **Full-text content** - The API returns metadata, not full article text
|
|
138
|
+
|
|
139
|
+
To access full-text content, use the `link` or `doi` fields to visit the publisher's website.
|
|
140
|
+
|
|
141
|
+
## Changelog
|
|
142
|
+
|
|
143
|
+
### v0.1.2 (2025-06-16)
|
|
144
|
+
|
|
145
|
+
- **Fix**: Null-safe XML parsing in `SearchResult` and `ListResult` — handles missing/empty XML elements without raising `AttributeError`
|
|
146
|
+
- **Fix**: `WARN_002` (too many results) is now treated as a warning instead of raising an error, since the API still returns valid data
|
|
147
|
+
|
|
148
|
+
### v0.1.1 (2025-05-18)
|
|
149
|
+
|
|
150
|
+
- First PyPI release as `pyjstage2`
|
|
151
|
+
- Python 3.12 compatibility
|
|
152
|
+
- Updated dependencies (lxml >=5.0, requests >=2.31, urllib3 >=2.0)
|
|
153
|
+
|
|
154
|
+
## Source Code
|
|
155
|
+
|
|
156
|
+
https://github.com/lanshi17/pyjstage
|
|
157
|
+
|
|
158
|
+
## License
|
|
159
|
+
|
|
160
|
+
MIT License - see [LICENSE](https://github.com/lanshi17/pyjstage/blob/master/LICENSE) file.
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# pyjstage2
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+

|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
[J-STAGE WebAPI](https://www.jstage.jst.go.jp/static/pages/OtherJstageServices/TAB2/-char/ja) Wrapper for Python 3.
|
|
10
|
+
|
|
11
|
+
- J-STAGE is an electronic journal platform for science and technology information in Japan, developed and managed by the Japan Science and Technology Agency (JST).
|
|
12
|
+
- This package is a **Python 3.12 compatible fork** of [pyjstage](https://pypi.org/project/pyjstage/).
|
|
13
|
+
|
|
14
|
+
## Acknowledgments
|
|
15
|
+
|
|
16
|
+
This project is modified based on [matsurih/pyjstage](https://github.com/matsurih/pyjstage) (v0.0.2).
|
|
17
|
+
|
|
18
|
+
Special thanks to the original author [@matsurih](https://github.com/matsurih) for creating this useful J-STAGE API wrapper.
|
|
19
|
+
|
|
20
|
+
## What's Changed
|
|
21
|
+
|
|
22
|
+
| Package | Original | Forked |
|
|
23
|
+
|---------|----------|--------|
|
|
24
|
+
| lxml | 4.4.2 | >=5.0.0 |
|
|
25
|
+
| requests | 2.22.0 | >=2.31.0 |
|
|
26
|
+
| urllib3 | 1.25.7 | >=2.0.0 |
|
|
27
|
+
| certifi | 2019.11.28 | >=2023.0.0 |
|
|
28
|
+
|
|
29
|
+
- Fixed absolute imports to relative imports
|
|
30
|
+
- Fixed private method name mangling (`__finish_setup` → `_finish_setup`)
|
|
31
|
+
- Added `__init__.py` export for cleaner imports
|
|
32
|
+
|
|
33
|
+
## Prerequisites
|
|
34
|
+
|
|
35
|
+
- Python >= 3.12
|
|
36
|
+
|
|
37
|
+
## Installation
|
|
38
|
+
|
|
39
|
+
```shell
|
|
40
|
+
$ pip install pyjstage2
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Usage
|
|
44
|
+
|
|
45
|
+
### Basic Usage
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
from pyjstage.pyjstage import Pyjstage
|
|
49
|
+
|
|
50
|
+
jstage = Pyjstage()
|
|
51
|
+
|
|
52
|
+
# Search by ISSN
|
|
53
|
+
ret_search = jstage.search(issn='2186-6619', count=3)
|
|
54
|
+
|
|
55
|
+
# List articles in a journal
|
|
56
|
+
ret_list = jstage.list(issn='2186-6619')
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Accessing Results
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
for entry in ret_search.entries:
|
|
63
|
+
print(f"Title: {entry.title}")
|
|
64
|
+
print(f"Author: {entry.author.get('ja', '')}")
|
|
65
|
+
print(f"Journal: {entry.material_title.get('ja', '')}")
|
|
66
|
+
print(f"Year: {entry.pubyear}")
|
|
67
|
+
print(f"DOI: {entry.doi}")
|
|
68
|
+
print(f"Link: {entry.link}")
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Search Parameters
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
jstage.search(
|
|
75
|
+
pubyearfrom=2020, # Search from year
|
|
76
|
+
pubyearto=2024, # Search to year
|
|
77
|
+
material='journal', # Journal name contains
|
|
78
|
+
article='title', # Article title contains
|
|
79
|
+
author='name', # Author name contains
|
|
80
|
+
keyword='AI', # Keyword contains
|
|
81
|
+
issn='2186-6619', # ISSN
|
|
82
|
+
count=10 # Number of results (max 1000)
|
|
83
|
+
)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Important Notes
|
|
87
|
+
|
|
88
|
+
### What J-STAGE API Provides
|
|
89
|
+
|
|
90
|
+
- ✅ **Literature search** - Search by ISSN, keyword, author, year, etc.
|
|
91
|
+
- ✅ **Metadata** - Title, author, journal, year, DOI, page numbers
|
|
92
|
+
- ✅ **Article links** - Links to J-STAGE article pages
|
|
93
|
+
|
|
94
|
+
### What J-STAGE API Does NOT Provide
|
|
95
|
+
|
|
96
|
+
- ❌ **Full-text PDF download** - The API does not provide direct PDF downloads
|
|
97
|
+
- ❌ **Full-text content** - The API returns metadata, not full article text
|
|
98
|
+
|
|
99
|
+
To access full-text content, use the `link` or `doi` fields to visit the publisher's website.
|
|
100
|
+
|
|
101
|
+
## Changelog
|
|
102
|
+
|
|
103
|
+
### v0.1.2 (2025-06-16)
|
|
104
|
+
|
|
105
|
+
- **Fix**: Null-safe XML parsing in `SearchResult` and `ListResult` — handles missing/empty XML elements without raising `AttributeError`
|
|
106
|
+
- **Fix**: `WARN_002` (too many results) is now treated as a warning instead of raising an error, since the API still returns valid data
|
|
107
|
+
|
|
108
|
+
### v0.1.1 (2025-05-18)
|
|
109
|
+
|
|
110
|
+
- First PyPI release as `pyjstage2`
|
|
111
|
+
- Python 3.12 compatibility
|
|
112
|
+
- Updated dependencies (lxml >=5.0, requests >=2.31, urllib3 >=2.0)
|
|
113
|
+
|
|
114
|
+
## Source Code
|
|
115
|
+
|
|
116
|
+
https://github.com/lanshi17/pyjstage
|
|
117
|
+
|
|
118
|
+
## License
|
|
119
|
+
|
|
120
|
+
MIT License - see [LICENSE](https://github.com/lanshi17/pyjstage/blob/master/LICENSE) file.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .pyjstage import Pyjstage
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
class Entry:
|
|
2
|
+
"""Base class for Entry
|
|
3
|
+
|
|
4
|
+
Attributes:
|
|
5
|
+
issn: ISSN
|
|
6
|
+
eissn: eISSN
|
|
7
|
+
cdjournal: journal name
|
|
8
|
+
material_title: journal title
|
|
9
|
+
volume: journal volume
|
|
10
|
+
number: journal number
|
|
11
|
+
starting_page: starting page this document is.
|
|
12
|
+
pubyear: Published year.
|
|
13
|
+
systemcode: System code
|
|
14
|
+
systemname: System name
|
|
15
|
+
title: Title
|
|
16
|
+
link: Link
|
|
17
|
+
id: ID, it is always the same as link parameter.
|
|
18
|
+
updated: updated date
|
|
19
|
+
"""
|
|
20
|
+
def __init__(self):
|
|
21
|
+
"""Initialize Entry class"""
|
|
22
|
+
self.issn = None
|
|
23
|
+
self.eissn = None
|
|
24
|
+
self.cdjournal = None
|
|
25
|
+
self.material_title = None
|
|
26
|
+
self.volume = None
|
|
27
|
+
self.number = None
|
|
28
|
+
self.starting_page = None
|
|
29
|
+
self.pubyear = None
|
|
30
|
+
self.systemcode = None
|
|
31
|
+
self.systemname = None
|
|
32
|
+
self.title = None
|
|
33
|
+
self.link = None
|
|
34
|
+
self.id = None
|
|
35
|
+
self.updated = None
|
|
36
|
+
|
|
37
|
+
def __str__(self):
|
|
38
|
+
return str(self.__dict__.items())
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class ListEntry(Entry):
|
|
42
|
+
"""Entry class for List API
|
|
43
|
+
|
|
44
|
+
Attributes:
|
|
45
|
+
vols_title: volumes title
|
|
46
|
+
vols_link: volumes link
|
|
47
|
+
publisher_name: publisher name
|
|
48
|
+
publisher_url: publisher url
|
|
49
|
+
"""
|
|
50
|
+
def __init__(self):
|
|
51
|
+
"""Initialize ListEntry class"""
|
|
52
|
+
super().__init__()
|
|
53
|
+
self.vols_title = {}
|
|
54
|
+
self.vols_link = {}
|
|
55
|
+
self.publisher_name = None
|
|
56
|
+
self.publisher_url = {}
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class SearchEntry(Entry):
|
|
60
|
+
"""Entry class for Search API
|
|
61
|
+
|
|
62
|
+
Attributes:
|
|
63
|
+
article_title: article title
|
|
64
|
+
article_link: article link
|
|
65
|
+
author: article author
|
|
66
|
+
ending_page: ending page
|
|
67
|
+
doi: DOI
|
|
68
|
+
"""
|
|
69
|
+
def __init__(self):
|
|
70
|
+
"""Initialize SearchEntry class"""
|
|
71
|
+
super().__init__()
|
|
72
|
+
self.article_title = {}
|
|
73
|
+
self.article_link = None
|
|
74
|
+
self.author = None
|
|
75
|
+
self.ending_page = None
|
|
76
|
+
self.doi = None
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
class JstageError(Exception):
|
|
2
|
+
"""Abstract class for errors caused by J-STAGE API"""
|
|
3
|
+
pass
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class JstageWarning(Warning):
|
|
7
|
+
"""Abstract class for warnings caused by J-STAGE API"""
|
|
8
|
+
pass
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class NoResultsError(JstageError):
|
|
12
|
+
"""ERR_001"""
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class TooManyResultsError(JstageWarning):
|
|
17
|
+
"""WARN_001"""
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class TooManyRequestsError(JstageError):
|
|
22
|
+
"""ERR_003"""
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class InvalidQueryError(JstageError):
|
|
27
|
+
"""ERR_004"""
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class EmptyRequiredFieldError(JstageError):
|
|
32
|
+
"""ERR_005"""
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class InvalidYearValueError(JstageError):
|
|
37
|
+
"""ERR_006"""
|
|
38
|
+
pass
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class InvalidCountsError(JstageError):
|
|
42
|
+
"""ERR_007"""
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class InvalidIssnError(JstageError):
|
|
47
|
+
"""ERR_008"""
|
|
48
|
+
pass
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class SystemFatalError(JstageError):
|
|
52
|
+
"""SYS_ERR_009"""
|
|
53
|
+
pass
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class InvalidUrlError(JstageError):
|
|
57
|
+
"""ERR_010"""
|
|
58
|
+
pass
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class ListNoQueryError(JstageError):
|
|
62
|
+
"""ERR_011"""
|
|
63
|
+
pass
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class SearchNoQueryError(JstageError):
|
|
67
|
+
"""ERR_012"""
|
|
68
|
+
pass
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class ListUnspecifiedError(JstageError):
|
|
72
|
+
"""ERR_013"""
|
|
73
|
+
pass
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class SearchUnsortableError(JstageError):
|
|
77
|
+
"""ERR_014"""
|
|
78
|
+
pass
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class ListOrder(Enum):
|
|
5
|
+
"""Enum for list's order
|
|
6
|
+
|
|
7
|
+
ListOrder.ASCENDING: sort by ascending
|
|
8
|
+
ListOrder.DESCENDING: sort by descending
|
|
9
|
+
"""
|
|
10
|
+
ASCENDING = 1
|
|
11
|
+
DESCENDING = 2
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class SearchOrder(Enum):
|
|
15
|
+
"""Enum for search's order
|
|
16
|
+
|
|
17
|
+
SearchOrder.SCORE: sort by score
|
|
18
|
+
SearchOrder.NUMBER: sort by number ascending
|
|
19
|
+
"""
|
|
20
|
+
SCORE = 1
|
|
21
|
+
NUMBER = 2
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
from lxml import etree
|
|
2
|
+
from .result import Result, ListResult, SearchResult
|
|
3
|
+
from .status import Status
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
import re
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Parser:
|
|
9
|
+
"""Parser Class"""
|
|
10
|
+
def __init__(self):
|
|
11
|
+
"""Initialize Parser class"""
|
|
12
|
+
self.regex = re.compile(r'\n* +')
|
|
13
|
+
|
|
14
|
+
def parse(self, xml_text: bytes) -> Result:
|
|
15
|
+
"""Parse XML returned from J-STAGE API
|
|
16
|
+
|
|
17
|
+
Parse XML document (as bytes object) into Result object.
|
|
18
|
+
This function may raise Error or Warning.
|
|
19
|
+
If that error starts with Jstage, that error was occurred by J-STAGE.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
xml_text: raw xml text's bytes encoded by UTF-8
|
|
23
|
+
Returns:
|
|
24
|
+
Result object which contains meta data and contents.
|
|
25
|
+
Raises:
|
|
26
|
+
JstageError: error depending on j-stage api
|
|
27
|
+
JstageWarning: warning depending on j-stage api
|
|
28
|
+
"""
|
|
29
|
+
result = Result()
|
|
30
|
+
|
|
31
|
+
root = etree.fromstring(xml_text)
|
|
32
|
+
result.xmlns = root.nsmap
|
|
33
|
+
result.xmlns['xml'] = 'http://www.w3.org/XML/1998/namespace'
|
|
34
|
+
result.xml_lang = root.find('[@xml:lang]', result.xmlns).attrib.values()[0]
|
|
35
|
+
result.xml_version = etree.ElementTree(root).docinfo.xml_version
|
|
36
|
+
result.encoding = etree.ElementTree(root).docinfo.encoding
|
|
37
|
+
result.servicecd = int(root.find('./servicecd', result.xmlns).text)
|
|
38
|
+
result.title = root.find('./title', result.xmlns).text
|
|
39
|
+
result.link = self.regex.sub('', root.find('./link', result.xmlns).attrib['href'])
|
|
40
|
+
result.id = self.regex.sub('', root.find('./id', result.xmlns).text)
|
|
41
|
+
result.updated = datetime.fromisoformat(root.find('./updated', result.xmlns).text)
|
|
42
|
+
result.total_results = int(root.find('./opensearch:totalResults', result.xmlns).text)
|
|
43
|
+
result.start_index = int(root.find('./opensearch:startIndex', result.xmlns).text)
|
|
44
|
+
result.items_per_page = int(root.find('./opensearch:itemsPerPage', result.xmlns).text)
|
|
45
|
+
result.entries = list(root.findall('./entry', result.xmlns))
|
|
46
|
+
result.status = root.find('./result/status', result.xmlns).text
|
|
47
|
+
result.message = root.find('./result/message', result.xmlns).text
|
|
48
|
+
Status.divide(result.status, result.message)
|
|
49
|
+
if result.servicecd == 2:
|
|
50
|
+
rresult = ListResult(result)
|
|
51
|
+
elif result.servicecd == 3:
|
|
52
|
+
rresult = SearchResult(result)
|
|
53
|
+
else:
|
|
54
|
+
raise Exception('Undefined service code')
|
|
55
|
+
|
|
56
|
+
return rresult
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
from .result import Result
|
|
2
|
+
from .parser import Parser
|
|
3
|
+
from .service import Service
|
|
4
|
+
from .order import ListOrder, SearchOrder
|
|
5
|
+
from urllib.parse import quote
|
|
6
|
+
from typing import List, Union
|
|
7
|
+
import requests
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Pyjstage:
|
|
11
|
+
"""Pyjstage Class
|
|
12
|
+
|
|
13
|
+
Attributes:
|
|
14
|
+
domain: J-STAGE API domain
|
|
15
|
+
parser: Parser object
|
|
16
|
+
"""
|
|
17
|
+
def __init__(self, domain: str = 'http://api.jstage.jst.go.jp/searchapi/do?'):
|
|
18
|
+
"""Initialize Pyjstage class
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
domain: (Optional) J-STAGE API domain
|
|
22
|
+
"""
|
|
23
|
+
self.domain: str = domain
|
|
24
|
+
self.parser: Parser = Parser()
|
|
25
|
+
|
|
26
|
+
def list(
|
|
27
|
+
self,
|
|
28
|
+
pubyearfrom: int = None,
|
|
29
|
+
pubyearto: int = None,
|
|
30
|
+
material: Union[str, List[str]] = None,
|
|
31
|
+
issn: str = None,
|
|
32
|
+
cdjournal: str = None,
|
|
33
|
+
volorder: ListOrder = None
|
|
34
|
+
) -> Result:
|
|
35
|
+
"""Access LIST API
|
|
36
|
+
|
|
37
|
+
Access LIST API and parse result as ListResult Object.
|
|
38
|
+
Union[xxx, List[xxx]] arguments can multiple value as list object.
|
|
39
|
+
If you set that argument as list, Search as 'AND'
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
pubyearfrom: (Optional) Year you want to search when papers were published from.
|
|
43
|
+
pubyearto: (Optional) Year you want to search when papers were published to.
|
|
44
|
+
material: (Optional) Keyword journal should contain.
|
|
45
|
+
issn: (Optional) ISSN you want to search.
|
|
46
|
+
cdjournal: (Optional) Journal code you want to search.
|
|
47
|
+
volorder: (Optional) How order are responses sorted.
|
|
48
|
+
Returns:
|
|
49
|
+
ListResult object which contains meta data and contents
|
|
50
|
+
Raises:
|
|
51
|
+
JstageError: Error caused by J-STAGE API
|
|
52
|
+
JstageWarning: Warning caused by J-STAGE API
|
|
53
|
+
"""
|
|
54
|
+
url = self.build_query(
|
|
55
|
+
service=Service.LIST.value,
|
|
56
|
+
pubyearfrom=pubyearfrom,
|
|
57
|
+
pubyearto=pubyearto,
|
|
58
|
+
material=material,
|
|
59
|
+
issn=issn,
|
|
60
|
+
cdjournal=cdjournal,
|
|
61
|
+
volorder=volorder.value)
|
|
62
|
+
response = requests.get(url)
|
|
63
|
+
return self.parser.parse(response.text.encode('utf-8'))
|
|
64
|
+
|
|
65
|
+
def search(
|
|
66
|
+
self,
|
|
67
|
+
pubyearfrom: int = None,
|
|
68
|
+
pubyearto: int = None,
|
|
69
|
+
material: Union[str, List[str]] = None,
|
|
70
|
+
article: Union[str, List[str]] = None,
|
|
71
|
+
author: Union[str, List[str]] = None,
|
|
72
|
+
affile: Union[str, List[str]] = None,
|
|
73
|
+
keyword: Union[str, List[str]] = None,
|
|
74
|
+
abst: Union[str, List[str]] = None,
|
|
75
|
+
text: Union[str, List[str]] = None,
|
|
76
|
+
issn: str = None,
|
|
77
|
+
cdjournal: str = None,
|
|
78
|
+
sortfig: SearchOrder = None,
|
|
79
|
+
vol: int = None,
|
|
80
|
+
no: int = None,
|
|
81
|
+
start: int = None,
|
|
82
|
+
count: int = None
|
|
83
|
+
) -> Result:
|
|
84
|
+
"""Access SEARCH API
|
|
85
|
+
|
|
86
|
+
Access SEARCH API and parse result as SearchResult Object.
|
|
87
|
+
Union[xxx, List[xxx]] arguments can multiple value as list object.
|
|
88
|
+
If you set that argument as list, Search as 'AND'
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
pubyearfrom: (Optional) Year you want to search when papers were published from.
|
|
92
|
+
pubyearto: (Optional) Year you want to search when papers were published to.
|
|
93
|
+
material: (Optional) Keyword journal should contain.
|
|
94
|
+
article: Keyword document's title should contain.
|
|
95
|
+
author: Keyword document's author name should contain.
|
|
96
|
+
affile: Keyword document's author's affile name should contain.
|
|
97
|
+
keyword: Keyword document's keyword should contain.
|
|
98
|
+
abst: Keyword document's abstract should contain.
|
|
99
|
+
text: Keyword document's body should contain
|
|
100
|
+
issn: (Optional) ISSN you want to search.
|
|
101
|
+
cdjournal: (Optional) Journal code you want to search.
|
|
102
|
+
sortfig: How order are responses sorted.
|
|
103
|
+
vol: What volume is document contained in journal
|
|
104
|
+
no: What number is document contained in journal
|
|
105
|
+
start: How many offsets you want to set, default 0.
|
|
106
|
+
count: How many results you want to fetch, max & default is 1000.
|
|
107
|
+
Returns:
|
|
108
|
+
SearchResult object which contains meta data and contents
|
|
109
|
+
Raises:
|
|
110
|
+
xxxError: xxx
|
|
111
|
+
"""
|
|
112
|
+
url = self.build_query(
|
|
113
|
+
service=Service.SEARCH.value,
|
|
114
|
+
pubyearfrom=pubyearfrom,
|
|
115
|
+
pubyearto=pubyearto,
|
|
116
|
+
material=material,
|
|
117
|
+
article=article,
|
|
118
|
+
author=author,
|
|
119
|
+
affile=affile,
|
|
120
|
+
keyword=keyword,
|
|
121
|
+
abst=abst,
|
|
122
|
+
text=text,
|
|
123
|
+
issn=issn,
|
|
124
|
+
cdjournal=cdjournal,
|
|
125
|
+
sortfig=sortfig.value if sortfig else None,
|
|
126
|
+
vol=vol,
|
|
127
|
+
no=no,
|
|
128
|
+
start=start,
|
|
129
|
+
count=count
|
|
130
|
+
)
|
|
131
|
+
response = requests.get(url)
|
|
132
|
+
result = self.parser.parse(response.text.encode('utf-8'))
|
|
133
|
+
return result
|
|
134
|
+
|
|
135
|
+
def build_query(self, **kwargs):
|
|
136
|
+
"""Build url with queries
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
kwargs: key-value pairs for querying. If multiple values, use list.
|
|
140
|
+
Returns:
|
|
141
|
+
URL-string which can access J-STAGE API
|
|
142
|
+
"""
|
|
143
|
+
return self.domain + '&'.join(
|
|
144
|
+
[
|
|
145
|
+
f'{quote(k, encoding="utf8")}={quote(str(v) if type(v) is not list else " ".join(v), encoding="utf8")}'
|
|
146
|
+
for k, v in kwargs.items() if v is not None
|
|
147
|
+
]
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
if __name__ == '__main__':
|
|
151
|
+
pj = Pyjstage()
|
|
152
|
+
ret = pj.search(text=['統合失調症', '精神分裂病'], count=10)
|
|
153
|
+
print(ret)
|