vlr-stats-scraper 1.1.0 → 1.2.0
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.
- package/README.md +170 -88
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,88 +1,170 @@
|
|
|
1
|
-
# vlr-stats-scraper
|
|
2
|
-
|
|
3
|
-
Scrapes player stats from [vlr.gg](https://www.vlr.gg) and stores them in a local SQLite
|
|
4
|
-
database, grouped by tournament or stage, so you can pull a backlog of players.
|
|
5
|
-
|
|
6
|
-
## Setup
|
|
7
|
-
|
|
8
|
-
Requires a [Hyperbrowser](https://hyperbrowser.ai) API key for scraping.
|
|
9
|
-
|
|
10
|
-
```bash
|
|
11
|
-
npm install vlr-stats-scraper
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
Create a `.env` file in the directory you run it from:
|
|
15
|
-
|
|
16
|
-
```
|
|
17
|
-
HYPERBROWSER_API_KEY=your_key_here
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
## CLI usage
|
|
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
|
-
|
|
1
|
+
# vlr-stats-scraper
|
|
2
|
+
|
|
3
|
+
Scrapes player stats from [vlr.gg](https://www.vlr.gg) and stores them in a local SQLite
|
|
4
|
+
database, grouped by tournament or stage, so you can pull a backlog of players.
|
|
5
|
+
|
|
6
|
+
## Setup
|
|
7
|
+
|
|
8
|
+
Requires Node.js 18+ and a [Hyperbrowser](https://hyperbrowser.ai) API key for scraping.
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install vlr-stats-scraper
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Create a `.env` file in the directory you run it from:
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
HYPERBROWSER_API_KEY=your_key_here
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## CLI usage
|
|
21
|
+
|
|
22
|
+
The package installs a `valstats` command.
|
|
23
|
+
|
|
24
|
+
| Command | What it does |
|
|
25
|
+
| --- | --- |
|
|
26
|
+
| `valstats <link> <year> <event-name>` | Scrape every player on an event page and save them under that event |
|
|
27
|
+
| `valstats --clear-event <event-name>` | Remove one event and its players |
|
|
28
|
+
| `valstats --clear` | Wipe the whole database (asks for confirmation) |
|
|
29
|
+
|
|
30
|
+
### Scraping an event
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npx valstats <link> <year> <event-name>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npx valstats https://www.vlr.gg/event/2977/vct-2026-americas-stage-2/group-stage 2026 "Stage 2"
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
- `link` — the vlr.gg event/group-stage page to scrape.
|
|
41
|
+
- `year` — the year the event took place.
|
|
42
|
+
- `event-name` — a label for this tournament/stage (used to group players together later).
|
|
43
|
+
|
|
44
|
+
What happens:
|
|
45
|
+
|
|
46
|
+
1. If the event name contains the word **"stage"** (case-insensitive), you're prompted to
|
|
47
|
+
enter a region (e.g. `AMER`, `EMEA`). That region is saved on the event and on every
|
|
48
|
+
player scraped. Otherwise region is left empty.
|
|
49
|
+
2. Every player profile linked on the event page is collected. Stats are pulled using
|
|
50
|
+
vlr.gg's **all-time** timespan.
|
|
51
|
+
3. Each player is scraped, saved to `players.db` in your current directory, linked to the
|
|
52
|
+
event, and printed to the console.
|
|
53
|
+
|
|
54
|
+
Running it again with an event name and year that are already saved replaces that event's
|
|
55
|
+
players with the freshly scraped ones. A player already in the database is updated with the
|
|
56
|
+
new data rather than duplicated.
|
|
57
|
+
|
|
58
|
+
### Clearing data
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
npx valstats --clear-event "Stage 2" # remove one event and its players
|
|
62
|
+
npx valstats --clear # wipe the whole database (type "yes" to confirm)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Players that also belong to another event are kept when a single event is cleared.
|
|
66
|
+
|
|
67
|
+
## What gets scraped
|
|
68
|
+
|
|
69
|
+
Each player is stored as an object like this:
|
|
70
|
+
|
|
71
|
+
```js
|
|
72
|
+
{
|
|
73
|
+
name: 'tenz', // from the profile URL
|
|
74
|
+
team: 'Sentinels', // current team
|
|
75
|
+
past_teams: ['Cloud9', ...], // previous teams
|
|
76
|
+
winnings: '$123,456', // total event winnings
|
|
77
|
+
most_played_agents: ['Jett', ...], // top 3 agents by usage
|
|
78
|
+
avg_kda: 1.23, // average K:D across those top 3 agents
|
|
79
|
+
nationality: 'Canada',
|
|
80
|
+
region: 'AMER', // from the CLI prompt / argument, or null
|
|
81
|
+
stats: [ // full agent stat rows for the top 3 agents,
|
|
82
|
+
{ Agent: 'Jett', 'K:D': '1.25', ... } // keyed by vlr.gg's column headers
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Library usage
|
|
88
|
+
|
|
89
|
+
```js
|
|
90
|
+
import {
|
|
91
|
+
scrapePlayer,
|
|
92
|
+
scrapeWebsite,
|
|
93
|
+
savePlayer,
|
|
94
|
+
saveEvent,
|
|
95
|
+
addPlayerToEvent,
|
|
96
|
+
getPlayersByEvent,
|
|
97
|
+
getRandomPlayerFromEvent,
|
|
98
|
+
} from 'vlr-stats-scraper';
|
|
99
|
+
|
|
100
|
+
const eventId = saveEvent({ name: 'Stage 2', region: 'AMER', year: 2026 });
|
|
101
|
+
|
|
102
|
+
const links = await scrapeWebsite('https://www.vlr.gg/event/.../group-stage');
|
|
103
|
+
for (const link of links) {
|
|
104
|
+
const player = await scrapePlayer(link, 'AMER');
|
|
105
|
+
if (player) {
|
|
106
|
+
savePlayer(player);
|
|
107
|
+
addPlayerToEvent(eventId, player.name);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const roster = getPlayersByEvent('Stage 2');
|
|
112
|
+
const pick = getRandomPlayerFromEvent('Stage 2');
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Exports
|
|
116
|
+
|
|
117
|
+
#### Scraping
|
|
118
|
+
|
|
119
|
+
| Function | Returns | Description |
|
|
120
|
+
| --- | --- | --- |
|
|
121
|
+
| `scrapeWebsite(url)` | `Promise<string[]>` | Scrapes an event page and returns every player profile link on it (with `?timespan=all`). |
|
|
122
|
+
| `scrapePlayer(url, region)` | `Promise<Player>` | Scrapes one player's profile page into a player object (see above). `region` is stored as-is. Returns `undefined` if scraping fails. |
|
|
123
|
+
|
|
124
|
+
#### Players
|
|
125
|
+
|
|
126
|
+
| Function | Returns | Description |
|
|
127
|
+
| --- | --- | --- |
|
|
128
|
+
| `savePlayer(player)` | — | Inserts a player, or updates them if one with the same name exists. |
|
|
129
|
+
| `getPlayer(name)` | `Player \| null` | Looks up a player by name. |
|
|
130
|
+
| `getAllPlayers()` | `Player[]` | Every player in the database. |
|
|
131
|
+
| `getRandomPlayer()` | `Player \| null` | A random player from the whole database. |
|
|
132
|
+
|
|
133
|
+
#### Events (tournaments / stages)
|
|
134
|
+
|
|
135
|
+
| Function | Returns | Description |
|
|
136
|
+
| --- | --- | --- |
|
|
137
|
+
| `saveEvent({ name, url, region, year, stage })` | `number` | Creates or updates an event by name and returns its id. Only `name` is required. |
|
|
138
|
+
| `addPlayerToEvent(eventId, playerName)` | — | Links a saved player to an event (ignored if already linked). |
|
|
139
|
+
| `getEvents()` | `Event[]` | Every saved event. |
|
|
140
|
+
| `getEventByName(name)` | `Event \| undefined` | Looks up an event by name. |
|
|
141
|
+
| `getPlayersByEvent(eventName)` | `Player[]` | All players linked to an event. |
|
|
142
|
+
| `getRandomPlayerFromEvent(eventName)` | `Player \| null` | A random player from one event. |
|
|
143
|
+
|
|
144
|
+
#### Clearing
|
|
145
|
+
|
|
146
|
+
| Function | Returns | Description |
|
|
147
|
+
| --- | --- | --- |
|
|
148
|
+
| `emptyEvent(eventName)` | `boolean` | Removes an event's players but keeps the event so it can be re-scraped. `false` if the event doesn't exist. |
|
|
149
|
+
| `clearEvent(eventName)` | `boolean` | Removes an event and its players. `false` if the event doesn't exist. |
|
|
150
|
+
| `clearDatabase()` | — | Deletes every event and player. |
|
|
151
|
+
|
|
152
|
+
Players that still belong to another event are never deleted by `emptyEvent` or
|
|
153
|
+
`clearEvent`.
|
|
154
|
+
|
|
155
|
+
## Data storage
|
|
156
|
+
|
|
157
|
+
Player and event data is stored in a `players.db` SQLite file created in whichever
|
|
158
|
+
directory you run the tool from. It has three tables:
|
|
159
|
+
|
|
160
|
+
- `players` — one row per player (`past_teams`, `most_played_agents` and `stats` are stored
|
|
161
|
+
as JSON and parsed back automatically when read).
|
|
162
|
+
- `events` — one row per tournament/stage (`name`, `url`, `region`, `year`, `stage`).
|
|
163
|
+
- `event_players` — links players to the events they were scraped from.
|
|
164
|
+
|
|
165
|
+
Databases created by older versions (with `tournaments` / `tournament_players` tables) are
|
|
166
|
+
migrated automatically.
|
|
167
|
+
|
|
168
|
+
## License
|
|
169
|
+
|
|
170
|
+
ISC
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vlr-stats-scraper",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Scrapes player stats from vlr.gg and stores them in a local SQLite database, grouped by tournament or stage.",
|
|
5
5
|
"homepage": "https://github.com/OverYander/VLR-Webscraper#readme",
|
|
6
6
|
"bugs": {
|