BibexPy 1.0.0__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.
Potentially problematic release.
This version of BibexPy might be problematic. Click here for more details.
- bibexpy-1.0.0/BibexPy.egg-info/PKG-INFO +119 -0
- bibexpy-1.0.0/BibexPy.egg-info/SOURCES.txt +10 -0
- bibexpy-1.0.0/BibexPy.egg-info/dependency_links.txt +1 -0
- bibexpy-1.0.0/BibexPy.egg-info/entry_points.txt +2 -0
- bibexpy-1.0.0/BibexPy.egg-info/requires.txt +12 -0
- bibexpy-1.0.0/BibexPy.egg-info/top_level.txt +1 -0
- bibexpy-1.0.0/DataProcessor.py +360 -0
- bibexpy-1.0.0/LICENSE +674 -0
- bibexpy-1.0.0/PKG-INFO +119 -0
- bibexpy-1.0.0/README.md +91 -0
- bibexpy-1.0.0/setup.cfg +4 -0
- bibexpy-1.0.0/setup.py +49 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: BibexPy
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: A Python library for advanced bibliography management and export.
|
|
5
|
+
Home-page: https://github.com/bcankara/BibexPy
|
|
6
|
+
Author: bcankara
|
|
7
|
+
Author-email: info@bibexpy.com
|
|
8
|
+
License: MIT
|
|
9
|
+
Project-URL: Bug Tracker, https://github.com/bcankara/BibexPy/issues
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Requires-Python: >=3.9
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
License-File: LICENSE
|
|
16
|
+
Requires-Dist: python-dotenv==1.0.0
|
|
17
|
+
Requires-Dist: pandas>=2.0.0
|
|
18
|
+
Requires-Dist: openpyxl>=3.1.2
|
|
19
|
+
Requires-Dist: numpy>=1.24.0
|
|
20
|
+
Requires-Dist: requests>=2.31.0
|
|
21
|
+
Requires-Dist: scikit-learn>=1.3.0
|
|
22
|
+
Requires-Dist: scipy>=1.11.0
|
|
23
|
+
Requires-Dist: tqdm>=4.65.0
|
|
24
|
+
Requires-Dist: colorama>=0.4.6
|
|
25
|
+
Requires-Dist: xlrd>=2.0.1
|
|
26
|
+
Requires-Dist: xlsxwriter>=3.1.0
|
|
27
|
+
Requires-Dist: typing-extensions>=4.7.0
|
|
28
|
+
|
|
29
|
+
# BibexPy
|
|
30
|
+
|
|
31
|
+
**Harmonizing the Bibliometric Symphony of Scopus and Web of Science**
|
|
32
|
+
|
|
33
|
+
BibexPy is a Python-based software designed to streamline bibliometric data integration, deduplication, metadata enrichment, and format conversion. It simplifies the preparation of high-quality datasets for advanced analyses by automating traditionally manual and error-prone tasks.
|
|
34
|
+
|
|
35
|
+
## Features
|
|
36
|
+
|
|
37
|
+
- **DOI-Based Deduplication and Merging**: Identifies and removes duplicate entries while enriching metadata by merging complementary records.
|
|
38
|
+
- **API-Driven Metadata Enrichment**: Completes missing fields such as abstracts, keywords, and affiliations using APIs like Unpaywall and Semantic Scholar.
|
|
39
|
+
- **Format Conversion**: Generates outputs compatible with VosViewer and Biblioshiny for easy analysis.
|
|
40
|
+
- **Command-Line Interface (CLI)**: Offers user-friendly interaction with minimal setup requirements.
|
|
41
|
+
|
|
42
|
+
# Prerequisites
|
|
43
|
+
|
|
44
|
+
## Required Python Version
|
|
45
|
+
- Python ≥ 3.9.0
|
|
46
|
+
|
|
47
|
+
**Libraries**:
|
|
48
|
+
- `python-dotenv==1.0.0`
|
|
49
|
+
- `pandas>=2.0.0`
|
|
50
|
+
- `openpyxl>=3.1.2`
|
|
51
|
+
- `numpy>=1.24.0`
|
|
52
|
+
- `requests>=2.31.0`
|
|
53
|
+
- `scikit-learn>=1.3.0`
|
|
54
|
+
- `scipy>=1.11.0`
|
|
55
|
+
- `tqdm>=4.65.0`
|
|
56
|
+
- `xlrd>=2.0.1`
|
|
57
|
+
- `xlsxwriter>=3.1.0`
|
|
58
|
+
- `colorama >= 0.4.6`
|
|
59
|
+
- `typing-extensions >= 4.7.0`
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
## Installation
|
|
63
|
+
|
|
64
|
+
1. **Clone the Repository**
|
|
65
|
+
```bash
|
|
66
|
+
git clone https://github.com/bcankara/BibexPy.git
|
|
67
|
+
```
|
|
68
|
+
2. **Navigate to the Directory**
|
|
69
|
+
```bash
|
|
70
|
+
cd BibexPy
|
|
71
|
+
```
|
|
72
|
+
3. **Install Dependencies**
|
|
73
|
+
```bash
|
|
74
|
+
pip install -r requirements.txt
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
4. **(Optional) Virtual Environment Setup**
|
|
78
|
+
```bash
|
|
79
|
+
python -m venv venv
|
|
80
|
+
source venv/bin/activate # Mac/Linux
|
|
81
|
+
venv\Scripts\activate # Windows
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Usage
|
|
85
|
+
|
|
86
|
+
1. **Run the Application**
|
|
87
|
+
```bash
|
|
88
|
+
python DataProcessor.py
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
2. **Follow the Workflow**
|
|
92
|
+
- Select your project.
|
|
93
|
+
- Upload Scopus (`.csv`) and Web of Science (`.txt`) files.
|
|
94
|
+
- Choose to enrich metadata (optional).
|
|
95
|
+
- Review and save the processed datasets.
|
|
96
|
+
|
|
97
|
+
## Outputs
|
|
98
|
+
|
|
99
|
+
BibexPy generates the following outputs:
|
|
100
|
+
- Unified datasets (`Prefix_Bib.xlsx`).
|
|
101
|
+
- VosViewer-compatible files (`Prefix_Vos.txt`).
|
|
102
|
+
- Statistical summaries for dataset quality and completeness.
|
|
103
|
+
|
|
104
|
+
## Documentation
|
|
105
|
+
|
|
106
|
+
For detailed documentation and examples, visit: [BibexPy Documentation](http://bibexpy.com/doc)
|
|
107
|
+
|
|
108
|
+
## Support
|
|
109
|
+
|
|
110
|
+
For questions or feedback, contact:
|
|
111
|
+
📧 **info@bibexpy.com**
|
|
112
|
+
|
|
113
|
+
## License
|
|
114
|
+
|
|
115
|
+
BibexPy is licensed under the **GNU General Public License (GPL)**. See the LICENSE file for details.
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
Enhance your bibliometric research with BibexPy, making data preparation efficient, reliable, and analysis-ready!
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
DataProcessor
|
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import time
|
|
4
|
+
import threading
|
|
5
|
+
import pandas as pd
|
|
6
|
+
from dotenv import load_dotenv
|
|
7
|
+
from Main.modules import (
|
|
8
|
+
ensure_dir,
|
|
9
|
+
find_files,
|
|
10
|
+
find_data_folders,
|
|
11
|
+
save_statistics,
|
|
12
|
+
save_comprehensive_statistics,
|
|
13
|
+
merge_databases_simple,
|
|
14
|
+
merge_databases_enhanced,
|
|
15
|
+
compare_merge_methods,
|
|
16
|
+
create_result_folder
|
|
17
|
+
)
|
|
18
|
+
from datetime import datetime
|
|
19
|
+
|
|
20
|
+
class ProcessIndicator:
|
|
21
|
+
"""Process indicator for showing progress"""
|
|
22
|
+
busy = False
|
|
23
|
+
delay = 0.1
|
|
24
|
+
|
|
25
|
+
@staticmethod
|
|
26
|
+
def indicator():
|
|
27
|
+
while 1:
|
|
28
|
+
for cursor in '|/-\\':
|
|
29
|
+
yield cursor
|
|
30
|
+
|
|
31
|
+
def __init__(self, description="Processing"):
|
|
32
|
+
self.description = description
|
|
33
|
+
self.generator = self.indicator()
|
|
34
|
+
self.busy = False
|
|
35
|
+
self.visible = False
|
|
36
|
+
|
|
37
|
+
def write_next(self):
|
|
38
|
+
with self._screen_lock:
|
|
39
|
+
if not self.visible:
|
|
40
|
+
sys.stdout.write(f"\r{self.description:<50}")
|
|
41
|
+
self.visible = True
|
|
42
|
+
sys.stdout.write(next(self.generator))
|
|
43
|
+
sys.stdout.flush()
|
|
44
|
+
sys.stdout.write('\b')
|
|
45
|
+
|
|
46
|
+
def remove_indicator(self, cleanup=False):
|
|
47
|
+
with self._screen_lock:
|
|
48
|
+
if self.visible:
|
|
49
|
+
sys.stdout.write('\b')
|
|
50
|
+
self.visible = False
|
|
51
|
+
if cleanup:
|
|
52
|
+
sys.stdout.write(f"\r{self.description:<50}[Completed]\n")
|
|
53
|
+
sys.stdout.flush()
|
|
54
|
+
|
|
55
|
+
def indicator_task(self):
|
|
56
|
+
while self.busy:
|
|
57
|
+
self.write_next()
|
|
58
|
+
time.sleep(self.delay)
|
|
59
|
+
|
|
60
|
+
def __enter__(self):
|
|
61
|
+
if sys.stdout.isatty():
|
|
62
|
+
self._screen_lock = threading.Lock()
|
|
63
|
+
self.busy = True
|
|
64
|
+
self.thread = threading.Thread(target=self.indicator_task)
|
|
65
|
+
self.thread.start()
|
|
66
|
+
|
|
67
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
68
|
+
if sys.stdout.isatty():
|
|
69
|
+
self.busy = False
|
|
70
|
+
time.sleep(self.delay)
|
|
71
|
+
self.remove_indicator(cleanup=True)
|
|
72
|
+
|
|
73
|
+
def process_wos_data(input_file: str, output_file: str) -> tuple[bool, pd.DataFrame, dict]:
|
|
74
|
+
"""Process WoS data"""
|
|
75
|
+
try:
|
|
76
|
+
from Main.wos2xlsx import save_to_excel
|
|
77
|
+
success = save_to_excel(input_file, output_file)
|
|
78
|
+
|
|
79
|
+
if success:
|
|
80
|
+
with ProcessIndicator("Converting WoS data to Excel format") as indicator:
|
|
81
|
+
df = pd.read_excel(output_file)
|
|
82
|
+
stats = {
|
|
83
|
+
'Record Count': len(df),
|
|
84
|
+
'Column Count': len(df.columns),
|
|
85
|
+
'Non-Empty Columns': df.count().to_dict()
|
|
86
|
+
}
|
|
87
|
+
return True, df, stats
|
|
88
|
+
return False, None, {}
|
|
89
|
+
except Exception as e:
|
|
90
|
+
sys.stderr.write(f"\nError: {str(e)}\n")
|
|
91
|
+
return False, None, {}
|
|
92
|
+
|
|
93
|
+
def process_scopus_data(input_file: str, output_file: str) -> tuple[bool, pd.DataFrame, dict]:
|
|
94
|
+
"""Process Scopus data"""
|
|
95
|
+
try:
|
|
96
|
+
from Main.scp2xlsx import save_to_excel
|
|
97
|
+
success = save_to_excel(input_file, output_file)
|
|
98
|
+
|
|
99
|
+
if success:
|
|
100
|
+
with ProcessIndicator("Converting Scopus data to Excel format") as indicator:
|
|
101
|
+
df = pd.read_excel(output_file)
|
|
102
|
+
stats = {
|
|
103
|
+
'Record Count': len(df),
|
|
104
|
+
'Column Count': len(df.columns),
|
|
105
|
+
'Non-Empty Columns': df.count().to_dict()
|
|
106
|
+
}
|
|
107
|
+
return True, df, stats
|
|
108
|
+
return False, None, {}
|
|
109
|
+
except Exception as e:
|
|
110
|
+
sys.stderr.write(f"\nError: {str(e)}\n")
|
|
111
|
+
return False, None, {}
|
|
112
|
+
|
|
113
|
+
def merge_txt_files(data_dir: str) -> str:
|
|
114
|
+
"""Merge all txt files in data directory into wos_raw.txt in merged_raw folder"""
|
|
115
|
+
txt_files = find_files(data_dir, "txt")
|
|
116
|
+
if not txt_files:
|
|
117
|
+
raise ValueError("No WoS files (txt) found in Data folder.")
|
|
118
|
+
|
|
119
|
+
# Create merged_raw directory if not exists
|
|
120
|
+
merged_raw_dir = os.path.join(data_dir, "merged_raw")
|
|
121
|
+
os.makedirs(merged_raw_dir, exist_ok=True)
|
|
122
|
+
|
|
123
|
+
output_file = os.path.join(merged_raw_dir, "wos_raw.txt")
|
|
124
|
+
with open(output_file, 'w', encoding='utf-8') as outfile:
|
|
125
|
+
for txt_file in txt_files:
|
|
126
|
+
with open(txt_file, 'r', encoding='utf-8') as infile:
|
|
127
|
+
outfile.write(infile.read())
|
|
128
|
+
outfile.write('\n') # Add newline between files
|
|
129
|
+
|
|
130
|
+
return output_file
|
|
131
|
+
|
|
132
|
+
def merge_csv_files(data_dir: str) -> str:
|
|
133
|
+
"""Merge all csv files in data directory into scp_raw.csv in merged_raw folder"""
|
|
134
|
+
csv_files = find_files(data_dir, "csv")
|
|
135
|
+
if not csv_files:
|
|
136
|
+
raise ValueError("No Scopus files (csv) found in Data folder.")
|
|
137
|
+
|
|
138
|
+
# Create merged_raw directory if not exists
|
|
139
|
+
merged_raw_dir = os.path.join(data_dir, "merged_raw")
|
|
140
|
+
os.makedirs(merged_raw_dir, exist_ok=True)
|
|
141
|
+
|
|
142
|
+
output_file = os.path.join(merged_raw_dir, "scp_raw.csv")
|
|
143
|
+
|
|
144
|
+
if len(csv_files) == 1:
|
|
145
|
+
# If only one CSV file, just copy it
|
|
146
|
+
import shutil
|
|
147
|
+
shutil.copy2(csv_files[0], output_file)
|
|
148
|
+
else:
|
|
149
|
+
# Read and combine all CSV files
|
|
150
|
+
all_data = []
|
|
151
|
+
for csv_file in csv_files:
|
|
152
|
+
df = pd.read_csv(csv_file, encoding='utf-8')
|
|
153
|
+
all_data.append(df)
|
|
154
|
+
|
|
155
|
+
# Concatenate all dataframes
|
|
156
|
+
combined_df = pd.concat(all_data, ignore_index=True)
|
|
157
|
+
|
|
158
|
+
# Save combined data
|
|
159
|
+
combined_df.to_csv(output_file, index=False, encoding='utf-8')
|
|
160
|
+
|
|
161
|
+
return output_file
|
|
162
|
+
|
|
163
|
+
def main():
|
|
164
|
+
try:
|
|
165
|
+
# Load environment variables
|
|
166
|
+
load_dotenv()
|
|
167
|
+
|
|
168
|
+
print("Database Merge Tool")
|
|
169
|
+
print("------------------")
|
|
170
|
+
|
|
171
|
+
# Find project folders
|
|
172
|
+
workspace_dir = "Workspace"
|
|
173
|
+
if not os.path.exists(workspace_dir):
|
|
174
|
+
os.makedirs(workspace_dir)
|
|
175
|
+
|
|
176
|
+
project_folders = [d for d in os.listdir(workspace_dir) if os.path.isdir(os.path.join(workspace_dir, d))]
|
|
177
|
+
|
|
178
|
+
if not project_folders:
|
|
179
|
+
sys.stderr.write("\nError: No project folder found in Workspace.\n")
|
|
180
|
+
return
|
|
181
|
+
|
|
182
|
+
print("\nProject Folders:")
|
|
183
|
+
for i, folder in enumerate(project_folders, 1):
|
|
184
|
+
print(f"{i}. {folder}")
|
|
185
|
+
|
|
186
|
+
# Project selection
|
|
187
|
+
while True:
|
|
188
|
+
try:
|
|
189
|
+
choice = int(input("\nSelect project number: "))
|
|
190
|
+
if 1 <= choice <= len(project_folders):
|
|
191
|
+
project_dir = os.path.join(workspace_dir, project_folders[choice-1])
|
|
192
|
+
break
|
|
193
|
+
else:
|
|
194
|
+
sys.stderr.write("Error: Invalid selection.\n")
|
|
195
|
+
except ValueError:
|
|
196
|
+
sys.stderr.write("Error: Invalid input. Please enter a number.\n")
|
|
197
|
+
|
|
198
|
+
# Create Data directory if not exists
|
|
199
|
+
data_dir = os.path.join(project_dir, "Data")
|
|
200
|
+
if not os.path.exists(data_dir):
|
|
201
|
+
os.makedirs(data_dir)
|
|
202
|
+
|
|
203
|
+
print(f"\nSelected Project: {project_folders[choice-1]}")
|
|
204
|
+
|
|
205
|
+
# Create unique analysis directory
|
|
206
|
+
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
207
|
+
analysis_dir = os.path.join(project_dir, f"Analysis_{timestamp}")
|
|
208
|
+
os.makedirs(analysis_dir, exist_ok=True)
|
|
209
|
+
|
|
210
|
+
# Create subfolders
|
|
211
|
+
text_files_dir = os.path.join(analysis_dir, "Text_Files")
|
|
212
|
+
cell_files_dir = os.path.join(analysis_dir, "Cell_Files")
|
|
213
|
+
os.makedirs(text_files_dir, exist_ok=True)
|
|
214
|
+
os.makedirs(cell_files_dir, exist_ok=True)
|
|
215
|
+
|
|
216
|
+
# Set output files in analysis directory
|
|
217
|
+
wos_output = os.path.join(cell_files_dir, "WoS.xlsx")
|
|
218
|
+
scopus_output = os.path.join(cell_files_dir, "Scopus.xlsx")
|
|
219
|
+
merged_bib = os.path.join(cell_files_dir, "Merged_Bib.xlsx")
|
|
220
|
+
merged_vos = os.path.join(text_files_dir, "Merged_Vos.txt")
|
|
221
|
+
api_enriched_bib = os.path.join(cell_files_dir, "Merged_API_Enriched_Bib.xlsx")
|
|
222
|
+
api_enriched_vos = os.path.join(text_files_dir, "Merged_API_Enriched_Vos.txt")
|
|
223
|
+
stats_excel = os.path.join(analysis_dir, "Statistics.xlsx")
|
|
224
|
+
api_log = os.path.join(analysis_dir, "Api_Log.txt")
|
|
225
|
+
api_updates = os.path.join(analysis_dir, "Api_Update.xlsx")
|
|
226
|
+
|
|
227
|
+
# Check if merged_raw directory exists and contains required files
|
|
228
|
+
merged_raw_dir = os.path.join(data_dir, "merged_raw")
|
|
229
|
+
wos_raw = os.path.join(merged_raw_dir, "wos_raw.txt")
|
|
230
|
+
scp_raw = os.path.join(merged_raw_dir, "scp_raw.csv")
|
|
231
|
+
|
|
232
|
+
use_existing = False
|
|
233
|
+
if os.path.exists(merged_raw_dir) and os.path.exists(wos_raw) and os.path.exists(scp_raw):
|
|
234
|
+
while True:
|
|
235
|
+
choice = input("\nPreviously merged raw files found. What would you like to do?\n"
|
|
236
|
+
"1. Use previously merged files\n"
|
|
237
|
+
"2. Perform new merge\n"
|
|
238
|
+
"Your choice (1/2): ")
|
|
239
|
+
if choice in ['1', '2']:
|
|
240
|
+
use_existing = (choice == '1')
|
|
241
|
+
break
|
|
242
|
+
else:
|
|
243
|
+
sys.stderr.write("Invalid choice. Please enter 1 or 2.\n")
|
|
244
|
+
|
|
245
|
+
if not use_existing:
|
|
246
|
+
if os.path.exists(merged_raw_dir):
|
|
247
|
+
print("\nDeleting old merged files...")
|
|
248
|
+
import shutil
|
|
249
|
+
shutil.rmtree(merged_raw_dir)
|
|
250
|
+
|
|
251
|
+
# Merge txt files into wos_raw.txt
|
|
252
|
+
print("\nMerging process in progress...")
|
|
253
|
+
try:
|
|
254
|
+
wos_input = merge_txt_files(data_dir)
|
|
255
|
+
print(f"WoS files merged: {os.path.basename(wos_input)}")
|
|
256
|
+
except ValueError as e:
|
|
257
|
+
sys.stderr.write(f"\nError: {str(e)}\n")
|
|
258
|
+
return
|
|
259
|
+
|
|
260
|
+
# Merge csv files into scp_raw.csv
|
|
261
|
+
print("\nMerging Scopus files...")
|
|
262
|
+
try:
|
|
263
|
+
scopus_input = merge_csv_files(data_dir)
|
|
264
|
+
print(f"Scopus files merged: {os.path.basename(scopus_input)}")
|
|
265
|
+
except ValueError as e:
|
|
266
|
+
sys.stderr.write(f"\nError: {str(e)}\n")
|
|
267
|
+
return
|
|
268
|
+
else:
|
|
269
|
+
print("\nUsing existing merged files...")
|
|
270
|
+
wos_input = wos_raw
|
|
271
|
+
scopus_input = scp_raw
|
|
272
|
+
|
|
273
|
+
# Process WoS data
|
|
274
|
+
print("\nProcessing WoS data...")
|
|
275
|
+
wos_success, wos_df, wos_stats = process_wos_data(wos_input, wos_output)
|
|
276
|
+
if not wos_success:
|
|
277
|
+
sys.stderr.write("\nError: Failed to process WoS data.\n")
|
|
278
|
+
return
|
|
279
|
+
print("WoS data processing completed.")
|
|
280
|
+
|
|
281
|
+
# Process Scopus data
|
|
282
|
+
print("\nProcessing Scopus data...")
|
|
283
|
+
scopus_success, scopus_df, scopus_stats = process_scopus_data(scopus_input, scopus_output)
|
|
284
|
+
if not scopus_success:
|
|
285
|
+
sys.stderr.write("\nError: Failed to process Scopus data.\n")
|
|
286
|
+
return
|
|
287
|
+
print("Scopus data processing completed.")
|
|
288
|
+
|
|
289
|
+
# Get Scopus API key from environment variable
|
|
290
|
+
scopus_api_key = os.getenv('SCOPUS_API_KEY')
|
|
291
|
+
unpaywall_email = os.getenv('UNPAYWALL_EMAIL')
|
|
292
|
+
|
|
293
|
+
if not scopus_api_key:
|
|
294
|
+
print("\nWarning: Scopus API key not found in .env file.")
|
|
295
|
+
print("You can add it to the .env file to enable Scopus metadata enrichment.")
|
|
296
|
+
print("Continuing with other data sources...")
|
|
297
|
+
|
|
298
|
+
if not unpaywall_email:
|
|
299
|
+
print("\nWarning: Unpaywall email not found in .env file.")
|
|
300
|
+
print("You can add it to the .env file to enable Unpaywall metadata enrichment.")
|
|
301
|
+
print("Continuing with other data sources...")
|
|
302
|
+
|
|
303
|
+
# Enhanced merge
|
|
304
|
+
print("\nMerging process in progress...")
|
|
305
|
+
enhanced_success, enhanced_stats, enhanced_df = merge_databases_enhanced(
|
|
306
|
+
wos_df,
|
|
307
|
+
scopus_df,
|
|
308
|
+
merged_bib,
|
|
309
|
+
scopus_api_key=scopus_api_key,
|
|
310
|
+
unpaywall_email=unpaywall_email,
|
|
311
|
+
result_dir=analysis_dir
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
print("\nConverting data to VosViewer format...")
|
|
315
|
+
from Main.xlsx2vos import convert_excel_to_wos
|
|
316
|
+
convert_excel_to_wos(merged_bib, merged_vos)
|
|
317
|
+
print("VosViewer conversion completed.")
|
|
318
|
+
|
|
319
|
+
if enhanced_success:
|
|
320
|
+
# Save statistics
|
|
321
|
+
print("\nPreparing statistics...")
|
|
322
|
+
all_stats = {
|
|
323
|
+
'WoS Statistics': wos_stats,
|
|
324
|
+
'Scopus Statistics': scopus_stats,
|
|
325
|
+
'Merge Statistics': enhanced_stats
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
save_comprehensive_statistics(all_stats, wos_df, scopus_df, enhanced_df, stats_excel)
|
|
329
|
+
print("Statistics completed.")
|
|
330
|
+
|
|
331
|
+
# Check and convert API enriched file
|
|
332
|
+
if os.path.exists(api_enriched_bib):
|
|
333
|
+
print("\nConverting API Enriched data to VosViewer format...")
|
|
334
|
+
convert_excel_to_wos(api_enriched_bib, api_enriched_vos)
|
|
335
|
+
print("API Enriched VosViewer conversion completed.")
|
|
336
|
+
|
|
337
|
+
print("\nProcess completed successfully.")
|
|
338
|
+
print(f"\nAnalysis results saved to: {analysis_dir}")
|
|
339
|
+
print("Generated Files:")
|
|
340
|
+
print(f"1. WoS Data: {os.path.basename(wos_output)}")
|
|
341
|
+
print(f"2. Scopus Data: {os.path.basename(scopus_output)}")
|
|
342
|
+
print(f"3. Merged Data (Biblioshiny): {os.path.basename(merged_bib)}")
|
|
343
|
+
print(f"4. Merged Data (VosViewer): {os.path.basename(merged_vos)}")
|
|
344
|
+
print(f"5. Statistics: {os.path.basename(stats_excel)}")
|
|
345
|
+
print(f"6. API Log: {os.path.basename(api_log)}")
|
|
346
|
+
if os.path.exists(api_updates):
|
|
347
|
+
print(f"7. API Updates: {os.path.basename(api_updates)}")
|
|
348
|
+
if os.path.exists(api_enriched_bib):
|
|
349
|
+
print(f"8. API Enriched Data (Biblioshiny): {os.path.basename(api_enriched_bib)}")
|
|
350
|
+
print(f"9. API Enriched Data (VosViewer): {os.path.basename(api_enriched_vos)}")
|
|
351
|
+
else:
|
|
352
|
+
sys.stderr.write("\nError: Merge process failed.\n")
|
|
353
|
+
|
|
354
|
+
except Exception as e:
|
|
355
|
+
print(f"\nAn unexpected error occurred: {str(e)}")
|
|
356
|
+
finally:
|
|
357
|
+
print("\nProgram terminating...")
|
|
358
|
+
|
|
359
|
+
if __name__ == "__main__":
|
|
360
|
+
main()
|