You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
**Verify the client** (run the script to hit the live site and print sample data):
76
+
77
+
```bash
78
+
pip install -e .
79
+
python scripts/verify_client.py # up to 3 pages of ratings per section (default)
80
+
python scripts/verify_client.py --max-pages 10 --page-size 20 # scrape more pages
81
+
```
82
+
83
+
**Scrape all ratings** for a professor or school: the client fetches the first page from HTML and subsequent pages via the site’s GraphQL API. Use the iterators to get every rating:
84
+
85
+
```python
86
+
with RMPClient() as client:
87
+
for rating in client.iter_professor_ratings("2823076"):
88
+
print(rating.date, rating.comment)
89
+
for rating in client.iter_school_ratings("1466"):
90
+
print(rating.date, rating.comment)
91
+
```
92
+
47
93
## How it works
48
94
49
95
### Package architecture
@@ -68,43 +114,57 @@ flowchart TB
68
114
end
69
115
70
116
subgraph External
71
-
API["RMP GraphQL API\n(ratemyprofessors.com)"]
117
+
RMP["RMP pages\n(ratemyprofessors.com)"]
72
118
end
73
119
74
120
User --> Client
75
121
Client --> Config
76
122
Client --> HttpCtx
77
123
HttpCtx --> Http
78
124
Http --> Bucket
79
-
Http --> API
125
+
Http --> RMP
80
126
Client --> Models
81
127
Client --> Errors
82
128
```
83
129
84
130
### Request flow
85
131
132
+
Professor, school, compare-schools, and search endpoints **fetch the relevant RMP page HTML** (GET), extract `window.__RELAY_STORE__` from the response, and parse it into `Professor`, `School`, `Rating`, or search result lists.
133
+
134
+
**Ratings pagination (Relay):** The first page of professor or school ratings comes from the same HTML (Relay store). The store’s connection includes:
135
+
136
+
-**`pageInfo.endCursor`** — opaque cursor for “start after this item”
137
+
-**`pageInfo.hasNextPage`** — whether more ratings exist
138
+
139
+
The client then requests the next page by POSTing to `/graphql` with the same query and variables:
140
+
141
+
-`id` — Relay node id (base64 of `Teacher-{legacyId}` or `School-{legacyId}`)
142
+
-`first` — page size (e.g. 20)
143
+
-`after` — `pageInfo.endCursor` from the previous response
144
+
145
+
Loop until `hasNextPage` is false. The cursor is typically base64 for an internal offset (e.g. `YXJyYXljb25uZWN0aW9uOjQ=` decodes to `arrayconnection:4`, meaning “after item 4”). RMP does not rotate or expire these cursors, so you can paginate with plain HTTP requests without a browser. This client sends the **full GraphQL query** in each request; if the site ever required persisted queries (e.g. `doc_id` only), you’d capture the real request from the browser and reuse that format.
146
+
86
147
```mermaid
87
148
sequenceDiagram
88
149
participant User
89
150
participant RMPClient
90
151
participant HttpClient
91
152
participant TokenBucket
92
153
participant httpx
93
-
participant RMP API
154
+
participant RMP
94
155
95
-
User->>RMPClient: e.g. get_professor(id) or iter_professors_for_school(school_id)
0 commit comments