-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbatch_request.py
More file actions
140 lines (111 loc) · 4.4 KB
/
Copy pathbatch_request.py
File metadata and controls
140 lines (111 loc) · 4.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
"""
Batch Request Example - Gets median and mean annual wages for all major
occupation groups across all states.
"""
import json
import time
import requests
import pandas as pd
from itertools import product
import os
# Load API key
API_KEY = os.getenv('BLS_API_KEY') # or hardcode for testing
if not API_KEY:
raise ValueError("Set BLS_API_KEY environment variable")
API_URL = 'https://api.bls.gov/publicAPI/v2/timeseries/data/'
# Load series ID codes from JSON
with open('reference/series_id_codes.json', 'r') as f:
codes = json.load(f)
# Extract codes we need
state_codes = list(codes['area_codes']['S']['state_codes'].keys())
occupation_codes = list(codes['occupation_codes']['major_occupational_groups'].keys())
industry_code = '000000' # All industries
datatype_codes = ['04', '13'] # Mean and median annual wages
print(f"Generating series IDs...")
print(f" States: {len(state_codes)}")
print(f" Occupations: {len(occupation_codes)}")
print(f" Data types: {len(datatype_codes)}")
# Generate all series ID combinations
series_ids = []
series_metadata = []
for state_code, occ_code, datatype in product(state_codes, occupation_codes, datatype_codes):
# Construct: OEUS + state_code + industry + occupation + datatype
series_id = f"OEUS{state_code}{industry_code}{occ_code}{datatype}"
series_ids.append(series_id)
series_metadata.append({
'series_id': series_id,
'state_code': state_code,
'occupation_code': occ_code,
'datatype_code': datatype
})
print(f"Generated {len(series_ids)} series IDs\n")
# Make batched API requests
BATCH_SIZE = 50
all_results = []
total_batches = (len(series_ids) + BATCH_SIZE - 1) // BATCH_SIZE
print("Making API requests...")
for i in range(0, len(series_ids), BATCH_SIZE):
batch_num = (i // BATCH_SIZE) + 1
batch = series_ids[i:i + BATCH_SIZE]
print(f" Batch {batch_num}/{total_batches}: {len(batch)} series")
payload = {
"seriesid": batch,
"registrationkey": API_KEY
}
try:
response = requests.post(API_URL, json=payload, timeout=30)
response.raise_for_status()
data = response.json()
if data['status'] == 'REQUEST_SUCCEEDED':
all_results.extend(data['Results']['series'])
print(f" ✓ Retrieved {len(data['Results']['series'])} series")
else:
print(f" ✗ API Error: {data.get('message', 'Unknown')}")
except requests.exceptions.RequestException as e:
print(f" ✗ Request failed: {e}")
# Rate limiting: 0.25 second delay between requests
if i + BATCH_SIZE < len(series_ids):
time.sleep(0.25)
print(f"\nTotal series retrieved: {len(all_results)}\n")
# Process results into DataFrame
print("Processing results into DataFrame...")
processed_data = []
for series in all_results:
series_id = series['seriesID']
# Find metadata for this series
metadata = next((m for m in series_metadata if m['series_id'] == series_id), None)
if not metadata:
continue
# Extract the data point (only one per series for most recent year)
for data_point in series['data']:
if data_point['period'] == 'A01': # Annual data
processed_data.append({
'series_id': series_id,
'state_code': metadata['state_code'],
'occupation_code': metadata['occupation_code'],
'datatype_code': metadata['datatype_code'],
'year': data_point['year'],
'value': float(data_point['value']) if data_point['value'] != '-' else None
})
# Create DataFrame
df = pd.DataFrame(processed_data)
# Add human-readable labels
state_names = codes['area_codes']['S']['state_codes']
occupation_names = codes['occupation_codes']['major_occupational_groups']
datatype_names = codes['datatype_codes']
df['state_name'] = df['state_code'].map(state_names)
df['occupation_name'] = df['occupation_code'].map(occupation_names)
df['datatype_name'] = df['datatype_code'].map(datatype_names)
# Pivot to wide format for easier viewing
df_wide = df.pivot_table(
index=['state_name', 'occupation_name'],
columns='datatype_name',
values='value',
aggfunc='first'
).reset_index()
print(f"Final DataFrame: {len(df_wide)} rows\n")
print(df_wide.head(10))
# Save to CSV
output_file = 'oews_batch_results.csv'
df.to_csv(output_file, index=False)
print(f"\nFull results saved to: {output_file}")