ai-crawler-robots 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.
- ai_crawler_robots-1.0.0/LICENSE +28 -0
- ai_crawler_robots-1.0.0/PKG-INFO +186 -0
- ai_crawler_robots-1.0.0/README.md +158 -0
- ai_crawler_robots-1.0.0/pyproject.toml +60 -0
- ai_crawler_robots-1.0.0/setup.cfg +4 -0
- ai_crawler_robots-1.0.0/src/ai_crawler_robots/__init__.py +1087 -0
- ai_crawler_robots-1.0.0/src/ai_crawler_robots/__main__.py +5 -0
- ai_crawler_robots-1.0.0/src/ai_crawler_robots/data.json +1 -0
- ai_crawler_robots-1.0.0/src/ai_crawler_robots/py.typed +0 -0
- ai_crawler_robots-1.0.0/src/ai_crawler_robots.egg-info/PKG-INFO +186 -0
- ai_crawler_robots-1.0.0/src/ai_crawler_robots.egg-info/SOURCES.txt +12 -0
- ai_crawler_robots-1.0.0/src/ai_crawler_robots.egg-info/dependency_links.txt +1 -0
- ai_crawler_robots-1.0.0/src/ai_crawler_robots.egg-info/entry_points.txt +2 -0
- ai_crawler_robots-1.0.0/src/ai_crawler_robots.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Pathwren
|
|
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.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
The crawler table shipped in data.json is dedicated to the public domain under
|
|
26
|
+
CC0-1.0. Robots tokens, user-agent strings and documentation URLs are taken
|
|
27
|
+
from each operator's own published documentation; the categories and the prose
|
|
28
|
+
are the index's own.
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ai-crawler-robots
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Lint a robots.txt and audit it against 56 AI crawlers: which ones it really blocks, which rules do nothing, and which fetchers robots.txt cannot stop at all. RFC 9309, zero dependencies, no network.
|
|
5
|
+
Author: Pathwren
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://www.pathwren.workers.dev/c/pypi-registry/ai-crawler-robots/
|
|
8
|
+
Project-URL: Documentation, https://www.pathwren.workers.dev/c/pypi-registry/ai-crawler-robots/
|
|
9
|
+
Project-URL: Data source, https://www.pathwren.workers.dev/c/pypi-registry/ai-crawler-robots/data.json
|
|
10
|
+
Project-URL: Companion package, https://pypi.org/project/ai-crawler-index/
|
|
11
|
+
Keywords: robots.txt,robots,rfc9309,lint,linter,crawler,ai,gptbot,claudebot,seo,crawl,user-agent,offline
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Intended Audience :: System Administrators
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
19
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
20
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: Indexing/Search
|
|
21
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
22
|
+
Classifier: Topic :: Text Processing :: Linguistic
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.8
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Dynamic: license-file
|
|
28
|
+
|
|
29
|
+
# ai-crawler-robots
|
|
30
|
+
|
|
31
|
+
**A robots.txt that looks right and blocks nothing is the normal failure.**
|
|
32
|
+
This package reads the file you already have and tells you which of the
|
|
33
|
+
56 AI crawlers it actually stops.
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
from ai_crawler_robots import lint, audit, is_allowed
|
|
37
|
+
|
|
38
|
+
lint(open("robots.txt").read())
|
|
39
|
+
# [{'level': 'error', 'line': 3, 'code': 'ua-is-not-a-token',
|
|
40
|
+
# 'message': 'User-agent takes a product token, not a full user-agent string. '
|
|
41
|
+
# 'This group matches no crawler.',
|
|
42
|
+
# 'found': 'Mozilla/5.0 (compatible; GPTBot/1.2; +https://openai.com/gptbot)',
|
|
43
|
+
# 'fix': 'User-agent: GPTBot'}]
|
|
44
|
+
|
|
45
|
+
is_allowed(text, "GPTBot", "/blog/post")
|
|
46
|
+
# {'allowed': False, 'rule': 'Disallow: /blog', 'line': 8, 'group': 'GPTBot', ...}
|
|
47
|
+
|
|
48
|
+
audit(text)["blocked"] # ['anthropic-claudebot', 'openai-gptbot', ...]
|
|
49
|
+
audit(text)["unenforceable"] # crawlers that will not obey it whatever it says
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Install
|
|
53
|
+
|
|
54
|
+
```sh
|
|
55
|
+
pip install ai-crawler-robots
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Python >= 3.8. **Zero dependencies, standard library only.** No network at
|
|
59
|
+
import: 56 crawler records and 8 ready-made stances ship
|
|
60
|
+
inside the wheel (68.1 KB), snapshot taken 2026-09-01.
|
|
61
|
+
|
|
62
|
+
**Nothing in this package fetches a URL.** There is no argument anywhere that
|
|
63
|
+
takes one. `refresh()` is the only call that touches the network, you have to
|
|
64
|
+
name it, and it fetches exactly one document: the same
|
|
65
|
+
[data.json](https://www.pathwren.workers.dev/c/pypi-registry/ai-crawler-robots/data.json) that ships in the wheel.
|
|
66
|
+
|
|
67
|
+
## The faults it finds
|
|
68
|
+
|
|
69
|
+
The most common robots.txt failure is not a syntax error — it is a file that a
|
|
70
|
+
person reads as correct and a parser reads as empty. 23 checks, of
|
|
71
|
+
which these are the ones that cost real traffic:
|
|
72
|
+
|
|
73
|
+
| code | what it means |
|
|
74
|
+
| --- | --- |
|
|
75
|
+
| `user_agent_is_a_ua_string` | `User-agent:` carrying a whole browser-style string. RFC 9309 matches a **product token**; that group matches nothing. |
|
|
76
|
+
| `unknown-token` | a token no crawler in the table sends — usually a typo, `ChatGPT-user` for `ChatGPT-User`, or a name somebody invented |
|
|
77
|
+
| `duplicate_group` | a second group for the same token; only the first one applies, the rest is decoration |
|
|
78
|
+
| `noindex_in_robots` | `Noindex:` in robots.txt. Google stopped honouring it on 1 September 2019 and it never worked anywhere else. |
|
|
79
|
+
| `unenforceable` | the rule is correct and the operator states robots.txt does not apply to that fetcher. You need an edge rule, and this says so. |
|
|
80
|
+
| `crawl_delay` | `Crawl-delay:` is not in RFC 9309 and Google, OpenAI and Anthropic all ignore it |
|
|
81
|
+
| `path_without_slash` | `Disallow: admin` does not match `/admin` |
|
|
82
|
+
| `html_response` / `empty` / `bom` | the file never parsed at all |
|
|
83
|
+
|
|
84
|
+
Every finding carries a line number, what was found, and a `fix` string you can
|
|
85
|
+
paste.
|
|
86
|
+
|
|
87
|
+
## Command line
|
|
88
|
+
|
|
89
|
+
```sh
|
|
90
|
+
ai-crawler-robots lint robots.txt # the faults, worst first
|
|
91
|
+
ai-crawler-robots audit robots.txt # every AI crawler: blocked / allowed / unenforceable
|
|
92
|
+
ai-crawler-robots check robots.txt --agent GPTBot --path /blog/
|
|
93
|
+
ai-crawler-robots diff old.txt new.txt # what changed by effect, not by text
|
|
94
|
+
ai-crawler-robots policy block-ai-training # print a ready-made stance
|
|
95
|
+
ai-crawler-robots policy block-ai-training --merge robots.txt
|
|
96
|
+
ai-crawler-robots explain GPTBot # who it is, what blocking costs
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
`lint` exits `1` when it finds an error, `0` otherwise, so it works as a CI
|
|
100
|
+
gate:
|
|
101
|
+
|
|
102
|
+
```sh
|
|
103
|
+
ai-crawler-robots lint robots.txt --strict || exit 1
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## `audit` — the question people actually have
|
|
107
|
+
|
|
108
|
+
```sh
|
|
109
|
+
$ ai-crawler-robots audit robots.txt
|
|
110
|
+
robots.txt: 56 crawlers, 12 blocked, 39 allowed, 5 unenforceable
|
|
111
|
+
|
|
112
|
+
BLOCKED (12)
|
|
113
|
+
openai-gptbot GPTBot OpenAI ai-training
|
|
114
|
+
anthropic-claudebot ClaudeBot Anthropic ai-training
|
|
115
|
+
...
|
|
116
|
+
ALLOWED, AND YOU PROBABLY MEANT TO BLOCK (7)
|
|
117
|
+
google-extended Google-Extended Google ai-training
|
|
118
|
+
...
|
|
119
|
+
UNENFORCEABLE BY robots.txt (5)
|
|
120
|
+
These fetch on behalf of a user in a live session. Their operators state
|
|
121
|
+
robots.txt does not govern them. Blocking needs an edge rule.
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
The third group is the one that surprises people. A user-triggered fetcher is
|
|
125
|
+
not a crawler, most operators say so in their own documentation, and a
|
|
126
|
+
`Disallow` aimed at one is a line that will never fire.
|
|
127
|
+
|
|
128
|
+
## `diff` — did that edit do anything?
|
|
129
|
+
|
|
130
|
+
```sh
|
|
131
|
+
$ ai-crawler-robots diff robots.old robots.new
|
|
132
|
+
2 crawler(s) changed verdict for /
|
|
133
|
+
google-extended allowed -> blocked
|
|
134
|
+
meta-externalagent allowed -> blocked
|
|
135
|
+
44 unchanged. Formatting-only changes are not reported.
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Compares by **effect**. Reordering groups, changing whitespace and rewriting
|
|
139
|
+
comments produce an empty diff, because none of them change what a crawler does.
|
|
140
|
+
|
|
141
|
+
## Ready-made stances
|
|
142
|
+
|
|
143
|
+
8 of them, the same bodies published at the index:
|
|
144
|
+
|
|
145
|
+
- `allow-all` — Every crawler on this index is named and allowed. Use when you want maximum reach into search and assistants and have nothing to withhold
|
|
146
|
+
- `block-ai-training` — Refuse the crawlers that feed model training. Keep the ones that put you in ChatGPT, Claude, Perplexity and Gemini answers
|
|
147
|
+
- `block-all-ai` — Training, AI search, user-triggered fetches and corpus builders, all refused. Classic search engines still allowed
|
|
148
|
+
- `block-datasets` — Refuse the crawlers whose output is a dataset other people train on: Common Crawl, AI2, Webz.io, Diffbot, ImagesiftBot
|
|
149
|
+
- `allow-ai-search-only` — Be findable and citable in assistants without contributing to training corpora
|
|
150
|
+
- `block-seo-tools` — Ahrefs, Semrush and friends. No user-facing consequence, and often the largest single slice of your bot traffic
|
|
151
|
+
- `block-disputed` — The ones repeatedly reported as ignoring robots.txt. Included for completeness — expect to enforce this at the edge instead
|
|
152
|
+
- `maximum-ai-visibility` — Allow every AI crawler and every search engine; refuse only SEO scrapers. For sites whose goal is to be found and cited by machines
|
|
153
|
+
|
|
154
|
+
`--merge` adds a stance to an existing file **without touching the groups
|
|
155
|
+
already in it**, so your Googlebot rules survive.
|
|
156
|
+
|
|
157
|
+
## Where the data comes from
|
|
158
|
+
|
|
159
|
+
The [AI Crawler Index](https://www.pathwren.workers.dev/c/pypi-registry/ai-crawler-robots/) — an independent, non-commercial public
|
|
160
|
+
reference. Every crawler record links to the operator's own documentation, and
|
|
161
|
+
`explain` prints that link. Presence in the table means the operator documents
|
|
162
|
+
that crawler; it is not an opinion about whether you should allow it.
|
|
163
|
+
|
|
164
|
+
`refresh()` fetches today's table and caches it six hours, which is how often
|
|
165
|
+
the index behind it is rebuilt:
|
|
166
|
+
|
|
167
|
+
```python
|
|
168
|
+
from ai_crawler_robots import refresh
|
|
169
|
+
refresh() # {'crawlers': 56, 'generated_at': '...'}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Companion packages
|
|
173
|
+
|
|
174
|
+
Same table, different questions:
|
|
175
|
+
|
|
176
|
+
- [`ai-crawler-index`](https://pypi.org/project/ai-crawler-index/) — what does
|
|
177
|
+
this user-agent claim to be?
|
|
178
|
+
- [`ai-crawler-verify`](https://pypi.org/project/ai-crawler-verify/) — is that
|
|
179
|
+
claim true? Checks the address against the operator's published ranges.
|
|
180
|
+
- [`ai-crawler-logs`](https://pypi.org/project/ai-crawler-logs/) — who was
|
|
181
|
+
actually in your access log, and what to paste to act on it.
|
|
182
|
+
|
|
183
|
+
## Licence
|
|
184
|
+
|
|
185
|
+
Code MIT. Bundled data CC0-1.0. Independent and non-commercial; not affiliated
|
|
186
|
+
with, endorsed by or speaking for any crawler operator named in the table.
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# ai-crawler-robots
|
|
2
|
+
|
|
3
|
+
**A robots.txt that looks right and blocks nothing is the normal failure.**
|
|
4
|
+
This package reads the file you already have and tells you which of the
|
|
5
|
+
56 AI crawlers it actually stops.
|
|
6
|
+
|
|
7
|
+
```python
|
|
8
|
+
from ai_crawler_robots import lint, audit, is_allowed
|
|
9
|
+
|
|
10
|
+
lint(open("robots.txt").read())
|
|
11
|
+
# [{'level': 'error', 'line': 3, 'code': 'ua-is-not-a-token',
|
|
12
|
+
# 'message': 'User-agent takes a product token, not a full user-agent string. '
|
|
13
|
+
# 'This group matches no crawler.',
|
|
14
|
+
# 'found': 'Mozilla/5.0 (compatible; GPTBot/1.2; +https://openai.com/gptbot)',
|
|
15
|
+
# 'fix': 'User-agent: GPTBot'}]
|
|
16
|
+
|
|
17
|
+
is_allowed(text, "GPTBot", "/blog/post")
|
|
18
|
+
# {'allowed': False, 'rule': 'Disallow: /blog', 'line': 8, 'group': 'GPTBot', ...}
|
|
19
|
+
|
|
20
|
+
audit(text)["blocked"] # ['anthropic-claudebot', 'openai-gptbot', ...]
|
|
21
|
+
audit(text)["unenforceable"] # crawlers that will not obey it whatever it says
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Install
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
pip install ai-crawler-robots
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Python >= 3.8. **Zero dependencies, standard library only.** No network at
|
|
31
|
+
import: 56 crawler records and 8 ready-made stances ship
|
|
32
|
+
inside the wheel (68.1 KB), snapshot taken 2026-09-01.
|
|
33
|
+
|
|
34
|
+
**Nothing in this package fetches a URL.** There is no argument anywhere that
|
|
35
|
+
takes one. `refresh()` is the only call that touches the network, you have to
|
|
36
|
+
name it, and it fetches exactly one document: the same
|
|
37
|
+
[data.json](https://www.pathwren.workers.dev/c/pypi-registry/ai-crawler-robots/data.json) that ships in the wheel.
|
|
38
|
+
|
|
39
|
+
## The faults it finds
|
|
40
|
+
|
|
41
|
+
The most common robots.txt failure is not a syntax error — it is a file that a
|
|
42
|
+
person reads as correct and a parser reads as empty. 23 checks, of
|
|
43
|
+
which these are the ones that cost real traffic:
|
|
44
|
+
|
|
45
|
+
| code | what it means |
|
|
46
|
+
| --- | --- |
|
|
47
|
+
| `user_agent_is_a_ua_string` | `User-agent:` carrying a whole browser-style string. RFC 9309 matches a **product token**; that group matches nothing. |
|
|
48
|
+
| `unknown-token` | a token no crawler in the table sends — usually a typo, `ChatGPT-user` for `ChatGPT-User`, or a name somebody invented |
|
|
49
|
+
| `duplicate_group` | a second group for the same token; only the first one applies, the rest is decoration |
|
|
50
|
+
| `noindex_in_robots` | `Noindex:` in robots.txt. Google stopped honouring it on 1 September 2019 and it never worked anywhere else. |
|
|
51
|
+
| `unenforceable` | the rule is correct and the operator states robots.txt does not apply to that fetcher. You need an edge rule, and this says so. |
|
|
52
|
+
| `crawl_delay` | `Crawl-delay:` is not in RFC 9309 and Google, OpenAI and Anthropic all ignore it |
|
|
53
|
+
| `path_without_slash` | `Disallow: admin` does not match `/admin` |
|
|
54
|
+
| `html_response` / `empty` / `bom` | the file never parsed at all |
|
|
55
|
+
|
|
56
|
+
Every finding carries a line number, what was found, and a `fix` string you can
|
|
57
|
+
paste.
|
|
58
|
+
|
|
59
|
+
## Command line
|
|
60
|
+
|
|
61
|
+
```sh
|
|
62
|
+
ai-crawler-robots lint robots.txt # the faults, worst first
|
|
63
|
+
ai-crawler-robots audit robots.txt # every AI crawler: blocked / allowed / unenforceable
|
|
64
|
+
ai-crawler-robots check robots.txt --agent GPTBot --path /blog/
|
|
65
|
+
ai-crawler-robots diff old.txt new.txt # what changed by effect, not by text
|
|
66
|
+
ai-crawler-robots policy block-ai-training # print a ready-made stance
|
|
67
|
+
ai-crawler-robots policy block-ai-training --merge robots.txt
|
|
68
|
+
ai-crawler-robots explain GPTBot # who it is, what blocking costs
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
`lint` exits `1` when it finds an error, `0` otherwise, so it works as a CI
|
|
72
|
+
gate:
|
|
73
|
+
|
|
74
|
+
```sh
|
|
75
|
+
ai-crawler-robots lint robots.txt --strict || exit 1
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## `audit` — the question people actually have
|
|
79
|
+
|
|
80
|
+
```sh
|
|
81
|
+
$ ai-crawler-robots audit robots.txt
|
|
82
|
+
robots.txt: 56 crawlers, 12 blocked, 39 allowed, 5 unenforceable
|
|
83
|
+
|
|
84
|
+
BLOCKED (12)
|
|
85
|
+
openai-gptbot GPTBot OpenAI ai-training
|
|
86
|
+
anthropic-claudebot ClaudeBot Anthropic ai-training
|
|
87
|
+
...
|
|
88
|
+
ALLOWED, AND YOU PROBABLY MEANT TO BLOCK (7)
|
|
89
|
+
google-extended Google-Extended Google ai-training
|
|
90
|
+
...
|
|
91
|
+
UNENFORCEABLE BY robots.txt (5)
|
|
92
|
+
These fetch on behalf of a user in a live session. Their operators state
|
|
93
|
+
robots.txt does not govern them. Blocking needs an edge rule.
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
The third group is the one that surprises people. A user-triggered fetcher is
|
|
97
|
+
not a crawler, most operators say so in their own documentation, and a
|
|
98
|
+
`Disallow` aimed at one is a line that will never fire.
|
|
99
|
+
|
|
100
|
+
## `diff` — did that edit do anything?
|
|
101
|
+
|
|
102
|
+
```sh
|
|
103
|
+
$ ai-crawler-robots diff robots.old robots.new
|
|
104
|
+
2 crawler(s) changed verdict for /
|
|
105
|
+
google-extended allowed -> blocked
|
|
106
|
+
meta-externalagent allowed -> blocked
|
|
107
|
+
44 unchanged. Formatting-only changes are not reported.
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Compares by **effect**. Reordering groups, changing whitespace and rewriting
|
|
111
|
+
comments produce an empty diff, because none of them change what a crawler does.
|
|
112
|
+
|
|
113
|
+
## Ready-made stances
|
|
114
|
+
|
|
115
|
+
8 of them, the same bodies published at the index:
|
|
116
|
+
|
|
117
|
+
- `allow-all` — Every crawler on this index is named and allowed. Use when you want maximum reach into search and assistants and have nothing to withhold
|
|
118
|
+
- `block-ai-training` — Refuse the crawlers that feed model training. Keep the ones that put you in ChatGPT, Claude, Perplexity and Gemini answers
|
|
119
|
+
- `block-all-ai` — Training, AI search, user-triggered fetches and corpus builders, all refused. Classic search engines still allowed
|
|
120
|
+
- `block-datasets` — Refuse the crawlers whose output is a dataset other people train on: Common Crawl, AI2, Webz.io, Diffbot, ImagesiftBot
|
|
121
|
+
- `allow-ai-search-only` — Be findable and citable in assistants without contributing to training corpora
|
|
122
|
+
- `block-seo-tools` — Ahrefs, Semrush and friends. No user-facing consequence, and often the largest single slice of your bot traffic
|
|
123
|
+
- `block-disputed` — The ones repeatedly reported as ignoring robots.txt. Included for completeness — expect to enforce this at the edge instead
|
|
124
|
+
- `maximum-ai-visibility` — Allow every AI crawler and every search engine; refuse only SEO scrapers. For sites whose goal is to be found and cited by machines
|
|
125
|
+
|
|
126
|
+
`--merge` adds a stance to an existing file **without touching the groups
|
|
127
|
+
already in it**, so your Googlebot rules survive.
|
|
128
|
+
|
|
129
|
+
## Where the data comes from
|
|
130
|
+
|
|
131
|
+
The [AI Crawler Index](https://www.pathwren.workers.dev/c/pypi-registry/ai-crawler-robots/) — an independent, non-commercial public
|
|
132
|
+
reference. Every crawler record links to the operator's own documentation, and
|
|
133
|
+
`explain` prints that link. Presence in the table means the operator documents
|
|
134
|
+
that crawler; it is not an opinion about whether you should allow it.
|
|
135
|
+
|
|
136
|
+
`refresh()` fetches today's table and caches it six hours, which is how often
|
|
137
|
+
the index behind it is rebuilt:
|
|
138
|
+
|
|
139
|
+
```python
|
|
140
|
+
from ai_crawler_robots import refresh
|
|
141
|
+
refresh() # {'crawlers': 56, 'generated_at': '...'}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Companion packages
|
|
145
|
+
|
|
146
|
+
Same table, different questions:
|
|
147
|
+
|
|
148
|
+
- [`ai-crawler-index`](https://pypi.org/project/ai-crawler-index/) — what does
|
|
149
|
+
this user-agent claim to be?
|
|
150
|
+
- [`ai-crawler-verify`](https://pypi.org/project/ai-crawler-verify/) — is that
|
|
151
|
+
claim true? Checks the address against the operator's published ranges.
|
|
152
|
+
- [`ai-crawler-logs`](https://pypi.org/project/ai-crawler-logs/) — who was
|
|
153
|
+
actually in your access log, and what to paste to act on it.
|
|
154
|
+
|
|
155
|
+
## Licence
|
|
156
|
+
|
|
157
|
+
Code MIT. Bundled data CC0-1.0. Independent and non-commercial; not affiliated
|
|
158
|
+
with, endorsed by or speaking for any crawler operator named in the table.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# GENERATED by playbooks/package_lane.py from lane.json. Do not edit:
|
|
2
|
+
# every field below has a single source of truth in that file.
|
|
3
|
+
[build-system]
|
|
4
|
+
requires = ["setuptools>=68"]
|
|
5
|
+
build-backend = "setuptools.build_meta"
|
|
6
|
+
|
|
7
|
+
[project]
|
|
8
|
+
name = "ai-crawler-robots"
|
|
9
|
+
version = "1.0.0"
|
|
10
|
+
description = "Lint a robots.txt and audit it against 56 AI crawlers: which ones it really blocks, which rules do nothing, and which fetchers robots.txt cannot stop at all. RFC 9309, zero dependencies, no network."
|
|
11
|
+
readme = "README.md"
|
|
12
|
+
requires-python = ">=3.8"
|
|
13
|
+
license = { text = "MIT" }
|
|
14
|
+
authors = [{ name = "Pathwren" }]
|
|
15
|
+
keywords = [
|
|
16
|
+
"robots.txt",
|
|
17
|
+
"robots",
|
|
18
|
+
"rfc9309",
|
|
19
|
+
"lint",
|
|
20
|
+
"linter",
|
|
21
|
+
"crawler",
|
|
22
|
+
"ai",
|
|
23
|
+
"gptbot",
|
|
24
|
+
"claudebot",
|
|
25
|
+
"seo",
|
|
26
|
+
"crawl",
|
|
27
|
+
"user-agent",
|
|
28
|
+
"offline",
|
|
29
|
+
]
|
|
30
|
+
classifiers = [
|
|
31
|
+
"Development Status :: 4 - Beta",
|
|
32
|
+
"Intended Audience :: Developers",
|
|
33
|
+
"Intended Audience :: System Administrators",
|
|
34
|
+
"License :: OSI Approved :: MIT License",
|
|
35
|
+
"Operating System :: OS Independent",
|
|
36
|
+
"Programming Language :: Python :: 3",
|
|
37
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
38
|
+
"Topic :: Internet :: WWW/HTTP",
|
|
39
|
+
"Topic :: Internet :: WWW/HTTP :: Indexing/Search",
|
|
40
|
+
"Topic :: Software Development :: Quality Assurance",
|
|
41
|
+
"Topic :: Text Processing :: Linguistic",
|
|
42
|
+
"Typing :: Typed",
|
|
43
|
+
]
|
|
44
|
+
dependencies = []
|
|
45
|
+
|
|
46
|
+
[project.scripts]
|
|
47
|
+
ai-crawler-robots = "ai_crawler_robots:_main"
|
|
48
|
+
|
|
49
|
+
[project.urls]
|
|
50
|
+
"Homepage" = "https://www.pathwren.workers.dev/c/pypi-registry/ai-crawler-robots/"
|
|
51
|
+
"Documentation" = "https://www.pathwren.workers.dev/c/pypi-registry/ai-crawler-robots/"
|
|
52
|
+
"Data source" = "https://www.pathwren.workers.dev/c/pypi-registry/ai-crawler-robots/data.json"
|
|
53
|
+
"Companion package" = "https://pypi.org/project/ai-crawler-index/"
|
|
54
|
+
|
|
55
|
+
[tool.setuptools]
|
|
56
|
+
package-dir = { "" = "src" }
|
|
57
|
+
packages = ["ai_crawler_robots"]
|
|
58
|
+
|
|
59
|
+
[tool.setuptools.package-data]
|
|
60
|
+
ai_crawler_robots = ["data.json", "py.typed"]
|