yandex-reverse-image-api 0.0.1__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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 wordstotech
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.
@@ -0,0 +1,2 @@
1
+ include README.md
2
+ include LICENSE
@@ -0,0 +1,222 @@
1
+ Metadata-Version: 2.4
2
+ Name: yandex-reverse-image-api
3
+ Version: 0.0.1
4
+ Summary: Yandex reverse image search API client: source pages, similar images, product matches and image OCR via ScrapingBee.
5
+ Author: wordstotech
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/ScrapingBee/yandex-reverse-image-api
8
+ Project-URL: Repository, https://github.com/ScrapingBee/yandex-reverse-image-api
9
+ Project-URL: Documentation, https://www.scrapingbee.com/documentation/
10
+ Keywords: yandex scraper,yandex reverse image search api,yandex scraper api,reverse image search api,yandex images api,scrapingbee
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.8
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Internet :: WWW/HTTP
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Classifier: Topic :: Text Processing :: Markup :: HTML
25
+ Requires-Python: >=3.8
26
+ Description-Content-Type: text/markdown
27
+ License-File: LICENSE
28
+ Requires-Dist: requests>=2.25.0
29
+ Dynamic: license-file
30
+
31
+ # yandex-reverse-image-api
32
+
33
+ A Python client for Yandex reverse image search through ScrapingBee. One method per result tab, plus the check that tells a bad input apart from a genuine no match.
34
+
35
+ **Verified live on 2026-09-10 against two real images.** Every return value below is the actual output of the sweep, including the two that came back empty and the reason each did.
36
+
37
+ ```bash
38
+ pip install yandex-reverse-image-api
39
+ ```
40
+
41
+ Requires Python 3.8 or newer and `requests`.
42
+
43
+ ## Read this before you budget
44
+
45
+ **Every call costs 75 credits, and the cheap request does not work.**
46
+
47
+ A 1 credit fetch of a reverse image URL returns HTTP 200 with a 14,885 byte page titled `Are you not a robot?`, carrying Yandex SmartCaptcha. Nothing in the status code tells you the scrape failed. `spb-initial-status-code` reads `302`.
48
+
49
+ Stealth clears it, and there is no working middle rung between 1 and 75. So reverse image search on Yandex is 75 credits per lookup, full stop. At the entry paid tier of 250,000 credits that is about 3,300 lookups a month.
50
+
51
+ ScrapingBee does not cache. Reverse image results for a fixed image change slowly, so cache them yourself.
52
+
53
+ ## Authentication
54
+
55
+ ```python
56
+ from yandex_reverse_image_api import YandexReverseImage
57
+
58
+ bee = YandexReverseImage("YOUR_API_KEY")
59
+ ```
60
+
61
+ Sent as `Authorization: Bearer YOUR_API_KEY`. Key and 1,000 free credits: [ScrapingBee](https://www.scrapingbee.com/). Landing page: [Yandex reverse image API](https://www.scrapingbee.com/scrapers/yandex-reverse-image-api/).
62
+
63
+ ## Where the data lives
64
+
65
+ Not in the DOM. Yandex renders its result grid client side and ships the payload in `data-state` attributes as HTML escaped JSON, so **`extract_rules` and CSS selectors both match nothing on this target**. There are no result nodes in the markup to select.
66
+
67
+ This client finds every `data-state` attribute, unescapes it, loads the JSON and reads the slice you asked for off `initialState`. Yandex calls the feature CBIR, content based image retrieval, and that acronym prefixes every slice name.
68
+
69
+ ---
70
+
71
+ ## Method reference
72
+
73
+ ### `sites(image_url)`
74
+
75
+ The main event. Every page where the image appears. Uses `cbir_page=sites`.
76
+
77
+ ```python
78
+ matches = bee.sites("https://upload.wikimedia.org/wikipedia/commons/3/3c/Shaki_waterfall.jpg")
79
+ len(matches) # 37
80
+ ```
81
+
82
+ ```python
83
+ {'domain': 'en.wikipedia.org',
84
+ 'title': 'Shaki Waterfall - Wikipedia',
85
+ 'description': 'Shaki Waterfall. ',
86
+ 'url': 'https://en.wikipedia.org/wiki/Shaki_Waterfall?utm_medium=organic&utm_source=yandexsmartcamera',
87
+ 'clean_url': 'https://en.wikipedia.org/wiki/Shaki_Waterfall',
88
+ 'thumb': 'https://avatars.mds.yandex.net/i?id=eb74556e...',
89
+ 'width': 960,
90
+ 'height': 719,
91
+ 'original_image': 'https://upload.wikimedia.org/.../960px-Shaki_waterfall.jpg'}
92
+ ```
93
+
94
+ Two normalisations the client applies, because both bite otherwise:
95
+
96
+ - **`clean_url`** strips the query string. Yandex appends `?utm_medium=organic&utm_source=yandexsmartcamera` to every result URL, which breaks deduplication if you compare raw URLs.
97
+ - **`thumb`** is made absolute. Yandex returns it protocol relative, starting with `//`.
98
+
99
+ `width` and `height` are the dimensions of the copy hosted on that page, not of your input, which is how you find the highest resolution copy of an image in the wild.
100
+
101
+ ### `domains(image_url)`
102
+
103
+ Match count per domain, deduplicated on `clean_url`.
104
+
105
+ ```python
106
+ bee.domains(image_url)
107
+ # {'bestofarmenia.com': 2, 'armeniantrip.com': 2, 'yandex.ru': 2,
108
+ # 'hotel.am': 2, 'eastroute.com': 2, 'ug-ideal.ru': 2, ...}
109
+ ```
110
+
111
+ The shape most brand protection and counterfeit detection work actually wants.
112
+
113
+ ### `similar(image_url)`
114
+
115
+ Visually similar images. Uses `cbir_page=similar`. Returned **40 thumbs** on the test image.
116
+
117
+ ### `products(image_url)`
118
+
119
+ Shopping matches for the object. Uses `cbir_page=products`. Returned **0** on the test image, which is correct: a landscape photograph has no shopping match. Expect real entries on product photos.
120
+
121
+ ### `ocr(image_url)`
122
+
123
+ Text recognised inside the image.
124
+
125
+ ```python
126
+ bee.ocr(image_url)
127
+ # {'hasText': False, 'plainText': '', 'blocks': [], 'entities': [], ...}
128
+ ```
129
+
130
+ `hasText` was `False` on the test image, because a waterfall photograph has no text in it. That is the right answer, not a failure.
131
+
132
+ **This costs no extra credits.** OCR arrives in the same response as the default tab, so one 75 credit call gives you reverse image matches and the text inside the image with no separate step.
133
+
134
+ ### `tags(image_url)`
135
+
136
+ Yandex's own category labels. Returned **5 tags** on the test image.
137
+
138
+ ### `other_sizes(image_url)`
139
+
140
+ The same image at other resolutions, grouped into buckets.
141
+
142
+ ```python
143
+ bee.other_sizes(image_url)
144
+ # {'small_dups': [...6...], 'medium_dups': [...6...], 'large_dups': [...6...]}
145
+ ```
146
+
147
+ ### `check_image(image_url)`
148
+
149
+ **Run this first on any image you have not searched before.**
150
+
151
+ ```python
152
+ bee.check_image("https://upload.wikimedia.org/wikipedia/commons/3/3c/Shaki_waterfall.jpg")
153
+ # {'expired': False, 'width': 1024, 'height': 767, 'usable': True}
154
+ ```
155
+
156
+ Yandex fetches your image from the URL before it searches. If its crawler cannot reach the file, or the URL is a short lived derivative, you get a valid page with an empty result set and **no error message at all**.
157
+
158
+ Three images, same configuration, same stealth tier:
159
+
160
+ | Image | `cbirPreview` | Result |
161
+ |---|---|---|
162
+ | Wikimedia Commons full size JPEG | `expired: False`, 1024x767 | 37 sites, 40 similar, 5 tags |
163
+ | A Wikimedia `thumb/` derivative URL | `expired: True` | 0 matches |
164
+ | A `nasa.gov` PNG | `expired: True`, width 0, height 0 | 0 matches, `pageSize: 0` |
165
+
166
+ So an empty `sites` list plus `usable: False` is an input problem. An empty `sites` list with real dimensions is a genuine no match. Without this check the two are indistinguishable, and you will record "no matches found" for images that were never searched.
167
+
168
+ Hand Yandex a stable, directly addressable, full size URL.
169
+
170
+ ### `tab_url(image_url, cbir_page=None)`
171
+
172
+ A static method. **0 credits, no request.** Builds the Yandex URL for one tab.
173
+
174
+ ```python
175
+ YandexReverseImage.tab_url(img, "sites")
176
+ # 'https://yandex.com/images/search?rpt=imageview&cbir_page=sites&url=https%3A%2F%2F...'
177
+ ```
178
+
179
+ The four tab forms were read out of the live page's own `cbirNavigation.menuItems`, not guessed:
180
+
181
+ | Tab | `cbir_page` |
182
+ |---|---|
183
+ | Search by image | omit it |
184
+ | Similar | `similar` |
185
+ | Sites | `sites` |
186
+ | Products | `products` |
187
+
188
+ Note the double encoding: the image URL is percent encoded inside the Yandex URL, which is then passed as the ScrapingBee `url` parameter. This is the most common place a hand rolled version breaks.
189
+
190
+ ### `usage()`
191
+
192
+ Free. Account credits, concurrency and renewal date.
193
+
194
+ ---
195
+
196
+ ## Credit cost
197
+
198
+ Measured from `spb-cost` headers. Available on `bee.last_cost`.
199
+
200
+ | Configuration | Credits | Outcome |
201
+ |---|---|---|
202
+ | `mode=auto` | 1 | SmartCaptcha page |
203
+ | `stealth_proxy=true` | 75 | Real results |
204
+ | Validation error | 0 | Nothing billed |
205
+
206
+ `stealth_proxy` forces JavaScript rendering, and `mode=auto` is incompatible with it. Sending both returns HTTP 400 and bills nothing, which fails quietly.
207
+
208
+ Every method here is one call, so nine methods on one image is 675 credits. If you need several tabs for the same image, note that `ocr`, `tags`, `other_sizes` and `check_image` all read the default tab, so fetching once and parsing four slices locally is a single 75 credit charge.
209
+
210
+ Plan tiers: [ScrapingBee pricing](https://www.scrapingbee.com/pricing).
211
+
212
+ ## Related
213
+
214
+ Other visual search landing pages: [Yandex images API](https://www.scrapingbee.com/scrapers/yandex-images-api/), [Yandex search API](https://www.scrapingbee.com/scrapers/yandex-search-api/), [Google reverse image API](https://www.scrapingbee.com/scrapers/google-reverse-image-api/), [Google Lens API](https://www.scrapingbee.com/scrapers/google-lens-api/), [Google image scraper](https://www.scrapingbee.com/scrapers/google-image-scraper/), [Bing reverse image search API](https://www.scrapingbee.com/scrapers/bing-reverse-image-search-api/), [Bing images API](https://www.scrapingbee.com/scrapers/bing-images-api/), [eBay image search API](https://www.scrapingbee.com/scrapers/ebay-image-search-api/), [Naver images API](https://www.scrapingbee.com/scrapers/naver-images-api/), [Yahoo images API](https://www.scrapingbee.com/scrapers/yahoo-images-api/), [Getty images scraper API](https://www.scrapingbee.com/scrapers/getty-images-scraper-api/), [website image API](https://www.scrapingbee.com/scrapers/website-image-api/), [images results API](https://www.scrapingbee.com/scrapers/images-results-api/), [Amazon image API](https://www.scrapingbee.com/scrapers/amazon-image-api/).
215
+
216
+ Features: [AI web scraping](https://www.scrapingbee.com/features/ai-web-scraping-api/), [JavaScript scenario](https://www.scrapingbee.com/features/javascript-scenario/) for driving the upload widget instead of passing a URL, [screenshots](https://www.scrapingbee.com/features/screenshot/), [markdown scraper](https://www.scrapingbee.com/features/markdown-scraper/), [data extraction](https://www.scrapingbee.com/features/data-extraction/).
217
+
218
+ The Yandex text search walkthrough is at [how to scrape Yandex search results](https://www.scrapingbee.com/blog/how-to-scrape-yandex-search-results/). Tab by tab guide: [github.com/ScrapingBee/yandex-reverse-image-api](https://github.com/ScrapingBee/yandex-reverse-image-api).
219
+
220
+ ## License
221
+
222
+ MIT
@@ -0,0 +1,192 @@
1
+ # yandex-reverse-image-api
2
+
3
+ A Python client for Yandex reverse image search through ScrapingBee. One method per result tab, plus the check that tells a bad input apart from a genuine no match.
4
+
5
+ **Verified live on 2026-09-10 against two real images.** Every return value below is the actual output of the sweep, including the two that came back empty and the reason each did.
6
+
7
+ ```bash
8
+ pip install yandex-reverse-image-api
9
+ ```
10
+
11
+ Requires Python 3.8 or newer and `requests`.
12
+
13
+ ## Read this before you budget
14
+
15
+ **Every call costs 75 credits, and the cheap request does not work.**
16
+
17
+ A 1 credit fetch of a reverse image URL returns HTTP 200 with a 14,885 byte page titled `Are you not a robot?`, carrying Yandex SmartCaptcha. Nothing in the status code tells you the scrape failed. `spb-initial-status-code` reads `302`.
18
+
19
+ Stealth clears it, and there is no working middle rung between 1 and 75. So reverse image search on Yandex is 75 credits per lookup, full stop. At the entry paid tier of 250,000 credits that is about 3,300 lookups a month.
20
+
21
+ ScrapingBee does not cache. Reverse image results for a fixed image change slowly, so cache them yourself.
22
+
23
+ ## Authentication
24
+
25
+ ```python
26
+ from yandex_reverse_image_api import YandexReverseImage
27
+
28
+ bee = YandexReverseImage("YOUR_API_KEY")
29
+ ```
30
+
31
+ Sent as `Authorization: Bearer YOUR_API_KEY`. Key and 1,000 free credits: [ScrapingBee](https://www.scrapingbee.com/). Landing page: [Yandex reverse image API](https://www.scrapingbee.com/scrapers/yandex-reverse-image-api/).
32
+
33
+ ## Where the data lives
34
+
35
+ Not in the DOM. Yandex renders its result grid client side and ships the payload in `data-state` attributes as HTML escaped JSON, so **`extract_rules` and CSS selectors both match nothing on this target**. There are no result nodes in the markup to select.
36
+
37
+ This client finds every `data-state` attribute, unescapes it, loads the JSON and reads the slice you asked for off `initialState`. Yandex calls the feature CBIR, content based image retrieval, and that acronym prefixes every slice name.
38
+
39
+ ---
40
+
41
+ ## Method reference
42
+
43
+ ### `sites(image_url)`
44
+
45
+ The main event. Every page where the image appears. Uses `cbir_page=sites`.
46
+
47
+ ```python
48
+ matches = bee.sites("https://upload.wikimedia.org/wikipedia/commons/3/3c/Shaki_waterfall.jpg")
49
+ len(matches) # 37
50
+ ```
51
+
52
+ ```python
53
+ {'domain': 'en.wikipedia.org',
54
+ 'title': 'Shaki Waterfall - Wikipedia',
55
+ 'description': 'Shaki Waterfall. ',
56
+ 'url': 'https://en.wikipedia.org/wiki/Shaki_Waterfall?utm_medium=organic&utm_source=yandexsmartcamera',
57
+ 'clean_url': 'https://en.wikipedia.org/wiki/Shaki_Waterfall',
58
+ 'thumb': 'https://avatars.mds.yandex.net/i?id=eb74556e...',
59
+ 'width': 960,
60
+ 'height': 719,
61
+ 'original_image': 'https://upload.wikimedia.org/.../960px-Shaki_waterfall.jpg'}
62
+ ```
63
+
64
+ Two normalisations the client applies, because both bite otherwise:
65
+
66
+ - **`clean_url`** strips the query string. Yandex appends `?utm_medium=organic&utm_source=yandexsmartcamera` to every result URL, which breaks deduplication if you compare raw URLs.
67
+ - **`thumb`** is made absolute. Yandex returns it protocol relative, starting with `//`.
68
+
69
+ `width` and `height` are the dimensions of the copy hosted on that page, not of your input, which is how you find the highest resolution copy of an image in the wild.
70
+
71
+ ### `domains(image_url)`
72
+
73
+ Match count per domain, deduplicated on `clean_url`.
74
+
75
+ ```python
76
+ bee.domains(image_url)
77
+ # {'bestofarmenia.com': 2, 'armeniantrip.com': 2, 'yandex.ru': 2,
78
+ # 'hotel.am': 2, 'eastroute.com': 2, 'ug-ideal.ru': 2, ...}
79
+ ```
80
+
81
+ The shape most brand protection and counterfeit detection work actually wants.
82
+
83
+ ### `similar(image_url)`
84
+
85
+ Visually similar images. Uses `cbir_page=similar`. Returned **40 thumbs** on the test image.
86
+
87
+ ### `products(image_url)`
88
+
89
+ Shopping matches for the object. Uses `cbir_page=products`. Returned **0** on the test image, which is correct: a landscape photograph has no shopping match. Expect real entries on product photos.
90
+
91
+ ### `ocr(image_url)`
92
+
93
+ Text recognised inside the image.
94
+
95
+ ```python
96
+ bee.ocr(image_url)
97
+ # {'hasText': False, 'plainText': '', 'blocks': [], 'entities': [], ...}
98
+ ```
99
+
100
+ `hasText` was `False` on the test image, because a waterfall photograph has no text in it. That is the right answer, not a failure.
101
+
102
+ **This costs no extra credits.** OCR arrives in the same response as the default tab, so one 75 credit call gives you reverse image matches and the text inside the image with no separate step.
103
+
104
+ ### `tags(image_url)`
105
+
106
+ Yandex's own category labels. Returned **5 tags** on the test image.
107
+
108
+ ### `other_sizes(image_url)`
109
+
110
+ The same image at other resolutions, grouped into buckets.
111
+
112
+ ```python
113
+ bee.other_sizes(image_url)
114
+ # {'small_dups': [...6...], 'medium_dups': [...6...], 'large_dups': [...6...]}
115
+ ```
116
+
117
+ ### `check_image(image_url)`
118
+
119
+ **Run this first on any image you have not searched before.**
120
+
121
+ ```python
122
+ bee.check_image("https://upload.wikimedia.org/wikipedia/commons/3/3c/Shaki_waterfall.jpg")
123
+ # {'expired': False, 'width': 1024, 'height': 767, 'usable': True}
124
+ ```
125
+
126
+ Yandex fetches your image from the URL before it searches. If its crawler cannot reach the file, or the URL is a short lived derivative, you get a valid page with an empty result set and **no error message at all**.
127
+
128
+ Three images, same configuration, same stealth tier:
129
+
130
+ | Image | `cbirPreview` | Result |
131
+ |---|---|---|
132
+ | Wikimedia Commons full size JPEG | `expired: False`, 1024x767 | 37 sites, 40 similar, 5 tags |
133
+ | A Wikimedia `thumb/` derivative URL | `expired: True` | 0 matches |
134
+ | A `nasa.gov` PNG | `expired: True`, width 0, height 0 | 0 matches, `pageSize: 0` |
135
+
136
+ So an empty `sites` list plus `usable: False` is an input problem. An empty `sites` list with real dimensions is a genuine no match. Without this check the two are indistinguishable, and you will record "no matches found" for images that were never searched.
137
+
138
+ Hand Yandex a stable, directly addressable, full size URL.
139
+
140
+ ### `tab_url(image_url, cbir_page=None)`
141
+
142
+ A static method. **0 credits, no request.** Builds the Yandex URL for one tab.
143
+
144
+ ```python
145
+ YandexReverseImage.tab_url(img, "sites")
146
+ # 'https://yandex.com/images/search?rpt=imageview&cbir_page=sites&url=https%3A%2F%2F...'
147
+ ```
148
+
149
+ The four tab forms were read out of the live page's own `cbirNavigation.menuItems`, not guessed:
150
+
151
+ | Tab | `cbir_page` |
152
+ |---|---|
153
+ | Search by image | omit it |
154
+ | Similar | `similar` |
155
+ | Sites | `sites` |
156
+ | Products | `products` |
157
+
158
+ Note the double encoding: the image URL is percent encoded inside the Yandex URL, which is then passed as the ScrapingBee `url` parameter. This is the most common place a hand rolled version breaks.
159
+
160
+ ### `usage()`
161
+
162
+ Free. Account credits, concurrency and renewal date.
163
+
164
+ ---
165
+
166
+ ## Credit cost
167
+
168
+ Measured from `spb-cost` headers. Available on `bee.last_cost`.
169
+
170
+ | Configuration | Credits | Outcome |
171
+ |---|---|---|
172
+ | `mode=auto` | 1 | SmartCaptcha page |
173
+ | `stealth_proxy=true` | 75 | Real results |
174
+ | Validation error | 0 | Nothing billed |
175
+
176
+ `stealth_proxy` forces JavaScript rendering, and `mode=auto` is incompatible with it. Sending both returns HTTP 400 and bills nothing, which fails quietly.
177
+
178
+ Every method here is one call, so nine methods on one image is 675 credits. If you need several tabs for the same image, note that `ocr`, `tags`, `other_sizes` and `check_image` all read the default tab, so fetching once and parsing four slices locally is a single 75 credit charge.
179
+
180
+ Plan tiers: [ScrapingBee pricing](https://www.scrapingbee.com/pricing).
181
+
182
+ ## Related
183
+
184
+ Other visual search landing pages: [Yandex images API](https://www.scrapingbee.com/scrapers/yandex-images-api/), [Yandex search API](https://www.scrapingbee.com/scrapers/yandex-search-api/), [Google reverse image API](https://www.scrapingbee.com/scrapers/google-reverse-image-api/), [Google Lens API](https://www.scrapingbee.com/scrapers/google-lens-api/), [Google image scraper](https://www.scrapingbee.com/scrapers/google-image-scraper/), [Bing reverse image search API](https://www.scrapingbee.com/scrapers/bing-reverse-image-search-api/), [Bing images API](https://www.scrapingbee.com/scrapers/bing-images-api/), [eBay image search API](https://www.scrapingbee.com/scrapers/ebay-image-search-api/), [Naver images API](https://www.scrapingbee.com/scrapers/naver-images-api/), [Yahoo images API](https://www.scrapingbee.com/scrapers/yahoo-images-api/), [Getty images scraper API](https://www.scrapingbee.com/scrapers/getty-images-scraper-api/), [website image API](https://www.scrapingbee.com/scrapers/website-image-api/), [images results API](https://www.scrapingbee.com/scrapers/images-results-api/), [Amazon image API](https://www.scrapingbee.com/scrapers/amazon-image-api/).
185
+
186
+ Features: [AI web scraping](https://www.scrapingbee.com/features/ai-web-scraping-api/), [JavaScript scenario](https://www.scrapingbee.com/features/javascript-scenario/) for driving the upload widget instead of passing a URL, [screenshots](https://www.scrapingbee.com/features/screenshot/), [markdown scraper](https://www.scrapingbee.com/features/markdown-scraper/), [data extraction](https://www.scrapingbee.com/features/data-extraction/).
187
+
188
+ The Yandex text search walkthrough is at [how to scrape Yandex search results](https://www.scrapingbee.com/blog/how-to-scrape-yandex-search-results/). Tab by tab guide: [github.com/ScrapingBee/yandex-reverse-image-api](https://github.com/ScrapingBee/yandex-reverse-image-api).
189
+
190
+ ## License
191
+
192
+ MIT
@@ -0,0 +1,38 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "yandex-reverse-image-api"
7
+ version = "0.0.1"
8
+ description = "Yandex reverse image search API client: source pages, similar images, product matches and image OCR via ScrapingBee."
9
+ readme = "README.md"
10
+ requires-python = ">=3.8"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "wordstotech" }]
13
+ keywords = ["yandex scraper", "yandex reverse image search api", "yandex scraper api", "reverse image search api", "yandex images api", "scrapingbee"]
14
+ dependencies = ["requests>=2.25.0"]
15
+ classifiers = [
16
+ "Development Status :: 4 - Beta",
17
+ "Intended Audience :: Developers",
18
+ "License :: OSI Approved :: MIT License",
19
+ "Operating System :: OS Independent",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.8",
22
+ "Programming Language :: Python :: 3.9",
23
+ "Programming Language :: Python :: 3.10",
24
+ "Programming Language :: Python :: 3.11",
25
+ "Programming Language :: Python :: 3.12",
26
+ "Programming Language :: Python :: 3.13",
27
+ "Topic :: Internet :: WWW/HTTP",
28
+ "Topic :: Software Development :: Libraries :: Python Modules",
29
+ "Topic :: Text Processing :: Markup :: HTML",
30
+ ]
31
+
32
+ [project.urls]
33
+ Homepage = "https://github.com/ScrapingBee/yandex-reverse-image-api"
34
+ Repository = "https://github.com/ScrapingBee/yandex-reverse-image-api"
35
+ Documentation = "https://www.scrapingbee.com/documentation/"
36
+
37
+ [tool.setuptools.packages.find]
38
+ where = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,6 @@
1
+ """Yandex reverse image search API client, built on ScrapingBee."""
2
+
3
+ from .client import YandexReverseImage, ScrapingBeeError
4
+
5
+ __all__ = ["YandexReverseImage", "ScrapingBeeError"]
6
+ __version__ = "0.0.1"
@@ -0,0 +1,254 @@
1
+ """ScrapingBee based Yandex reverse image search client.
2
+
3
+ Verified live on 2026-09-10 against two real images.
4
+
5
+ Yandex calls the feature CBIR, content based image retrieval, and that
6
+ acronym runs through the whole response payload.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import html as html_module
12
+ import json
13
+ import re
14
+ from typing import Any, Dict, List, Optional
15
+ from urllib.parse import quote, urlsplit, urlunsplit
16
+
17
+ import requests
18
+
19
+ __all__ = ["YandexReverseImage", "ScrapingBeeError"]
20
+
21
+ BASE_URL = "https://app.scrapingbee.com/api/v1/"
22
+ YANDEX_IMAGES = "https://yandex.com/images/search"
23
+
24
+ # Yandex renders its result grid client side and ships the data in
25
+ # data-state attributes as HTML escaped JSON. There are no result nodes in
26
+ # the markup, so extract_rules and CSS selectors both match nothing here.
27
+ _STATE = re.compile(r'data-state="([^"]{200,})"')
28
+
29
+
30
+ class ScrapingBeeError(RuntimeError):
31
+ def __init__(self, message: str, status: Optional[int] = None,
32
+ payload: Any = None) -> None:
33
+ super().__init__(message)
34
+ self.status = status
35
+ self.payload = payload
36
+
37
+
38
+ class YandexReverseImage:
39
+ """Yandex reverse image search, one method per result tab.
40
+
41
+ >>> bee = YandexReverseImage("YOUR_API_KEY")
42
+ >>> matches = bee.sites("https://example.com/photo.jpg")
43
+
44
+ Credit cost, measured live: 75 per call, every call. The cheap request
45
+ does not work. A 1 credit fetch returns HTTP 200 carrying a page titled
46
+ "Are you not a robot?" with Yandex SmartCaptcha inside it, so nothing
47
+ about the status code tells you the scrape failed. Stealth is what
48
+ clears it, and there is no working middle rung.
49
+
50
+ ScrapingBee does not cache, so cache results yourself. Reverse image
51
+ matches for a fixed image change slowly and every repeat costs full
52
+ price.
53
+ """
54
+
55
+ def __init__(self, api_key: str, base_url: str = BASE_URL,
56
+ timeout: int = 200, wait: int = 8000,
57
+ session: Optional[requests.Session] = None) -> None:
58
+ if not api_key:
59
+ raise ValueError("api_key is required")
60
+ self.api_key = api_key
61
+ self.base_url = base_url
62
+ self.timeout = timeout
63
+ self.wait = wait
64
+ self._session = session or requests.Session()
65
+ self.last_cost: Optional[int] = None
66
+
67
+ # ------------------------------------------------------------------ core
68
+
69
+ @staticmethod
70
+ def tab_url(image_url: str, cbir_page: Optional[str] = None) -> str:
71
+ """Build the Yandex URL for one tab.
72
+
73
+ These forms were read out of the live page's own cbirNavigation
74
+ menuItems rather than guessed. The image URL is percent encoded
75
+ inside the Yandex URL, which is then passed as the ScrapingBee url
76
+ parameter: two layers of encoding, and the usual place this breaks.
77
+ """
78
+ target = f"{YANDEX_IMAGES}?rpt=imageview"
79
+ if cbir_page:
80
+ target += f"&cbir_page={cbir_page}"
81
+ return target + f"&url={quote(image_url, safe='')}"
82
+
83
+ def _fetch(self, image_url: str, cbir_page: Optional[str] = None) -> str:
84
+ response = self._session.get(
85
+ self.base_url,
86
+ headers={"Authorization": f"Bearer {self.api_key}"},
87
+ params={
88
+ "url": self.tab_url(image_url, cbir_page),
89
+ # stealth_proxy forces JavaScript rendering, and mode=auto
90
+ # is incompatible with it. Sending both returns HTTP 400.
91
+ "stealth_proxy": "true",
92
+ "wait": self.wait,
93
+ },
94
+ timeout=self.timeout,
95
+ )
96
+ cost = response.headers.get("spb-cost")
97
+ self.last_cost = int(cost) if cost and cost.isdigit() else None
98
+
99
+ if response.status_code == 400:
100
+ raise ScrapingBeeError(
101
+ "API rejected the request", 400, response.text[:500]
102
+ )
103
+ response.raise_for_status()
104
+ return response.text
105
+
106
+ @staticmethod
107
+ def _states(page: str) -> List[Dict[str, Any]]:
108
+ out = []
109
+ for attr in _STATE.findall(page):
110
+ try:
111
+ obj = json.loads(html_module.unescape(attr))
112
+ except json.JSONDecodeError:
113
+ continue
114
+ state = obj.get("initialState")
115
+ if isinstance(state, dict):
116
+ out.append(state)
117
+ return out
118
+
119
+ @classmethod
120
+ def _slice(cls, page: str, key: str, field: str) -> List[Any]:
121
+ for state in cls._states(page):
122
+ value = state.get(key)
123
+ if isinstance(value, dict) and value.get(field):
124
+ return value[field]
125
+ return []
126
+
127
+ @staticmethod
128
+ def _clean(url: str) -> str:
129
+ """Yandex appends utm_medium and utm_source to every result URL."""
130
+ parts = urlsplit(url or "")
131
+ return urlunsplit((parts.scheme, parts.netloc, parts.path, "", ""))
132
+
133
+ @staticmethod
134
+ def _absolute(url: Optional[str]) -> Optional[str]:
135
+ """Thumbnail URLs are protocol relative, starting with a double slash."""
136
+ if url and url.startswith("//"):
137
+ return "https:" + url
138
+ return url
139
+
140
+ # ----------------------------------------------------------------- tabs
141
+
142
+ def sites(self, image_url: str) -> List[Dict[str, Any]]:
143
+ """Every page where the image appears. The main event.
144
+
145
+ A live call on a Wikimedia Commons full size JPEG returned 37
146
+ matches. Each entry carries the page title, its description, the
147
+ page URL, the domain, a Yandex thumbnail, and the dimensions of the
148
+ copy hosted on that page.
149
+ """
150
+ page = self._fetch(image_url, "sites")
151
+ rows = self._slice(page, "cbirSites", "sites")
152
+ out = []
153
+ for site in rows:
154
+ thumb = site.get("thumb") or {}
155
+ original = site.get("originalImage") or {}
156
+ out.append({
157
+ "domain": site.get("domain"),
158
+ "title": site.get("title"),
159
+ "description": site.get("description"),
160
+ "url": site.get("url"),
161
+ "clean_url": self._clean(site.get("url", "")),
162
+ "thumb": self._absolute(thumb.get("url")),
163
+ "width": original.get("width"),
164
+ "height": original.get("height"),
165
+ "original_image": original.get("url"),
166
+ })
167
+ return out
168
+
169
+ def similar(self, image_url: str) -> List[Any]:
170
+ """Visually similar images."""
171
+ return self._slice(self._fetch(image_url, "similar"), "cbirSimilar", "thumbs")
172
+
173
+ def products(self, image_url: str) -> List[Any]:
174
+ """Shopping matches for the object in the image."""
175
+ page = self._fetch(image_url, "products")
176
+ return self._slice(page, "cbirMarketProducts", "products")
177
+
178
+ def ocr(self, image_url: str) -> Dict[str, Any]:
179
+ """Text recognised inside the image, from the same call.
180
+
181
+ One request gives you reverse image matches and the text inside the
182
+ image, with no separate OCR step and no extra credits. Returns
183
+ plainText, hasText, blocks and entities.
184
+ """
185
+ for state in self._states(self._fetch(image_url)):
186
+ block = state.get("cbirOcr")
187
+ if isinstance(block, dict):
188
+ return block
189
+ return {}
190
+
191
+ def tags(self, image_url: str) -> List[Any]:
192
+ """Yandex's own category labels for the image."""
193
+ return self._slice(self._fetch(image_url), "cbirTags", "tags")
194
+
195
+ def other_sizes(self, image_url: str) -> Dict[str, Any]:
196
+ """The same image at other resolutions, grouped by size bucket."""
197
+ for state in self._states(self._fetch(image_url)):
198
+ block = state.get("cbirOtherSizes")
199
+ if isinstance(block, dict):
200
+ return block.get("items") or {}
201
+ return {}
202
+
203
+ # -------------------------------------------------------------- helpers
204
+
205
+ def check_image(self, image_url: str) -> Optional[Dict[str, Any]]:
206
+ """Tell an unusable image URL apart from a genuine no match result.
207
+
208
+ Yandex fetches the image from the URL you hand it before it
209
+ searches. If its crawler cannot reach the file, or the URL is a
210
+ short lived derivative, you get a valid page with an empty result
211
+ set and no error message.
212
+
213
+ Measured: a Wikimedia Commons full size JPEG returned 37 matches, a
214
+ Wikimedia thumb derivative returned 0 with imageExpired true, and a
215
+ nasa.gov PNG returned 0 with pageSize 0.
216
+
217
+ An empty sites array plus a zero width is an input problem. An
218
+ empty sites array with real dimensions is a genuine no match.
219
+ """
220
+ for state in self._states(self._fetch(image_url)):
221
+ preview = state.get("cbirPreview")
222
+ if isinstance(preview, dict):
223
+ return {
224
+ "expired": preview.get("imageExpired"),
225
+ "width": preview.get("imageWidth"),
226
+ "height": preview.get("imageHeight"),
227
+ "usable": (
228
+ not preview.get("imageExpired")
229
+ and bool(preview.get("imageWidth"))
230
+ ),
231
+ }
232
+ return None
233
+
234
+ def usage(self) -> Dict[str, Any]:
235
+ """Account credit usage. Free."""
236
+ response = self._session.get(
237
+ "https://app.scrapingbee.com/api/v1/usage",
238
+ headers={"Authorization": f"Bearer {self.api_key}"},
239
+ timeout=self.timeout,
240
+ )
241
+ response.raise_for_status()
242
+ return response.json()
243
+
244
+ def domains(self, image_url: str) -> Dict[str, int]:
245
+ """Match count per domain, deduplicated on the URL without its query."""
246
+ counts: Dict[str, int] = {}
247
+ seen = set()
248
+ for site in self.sites(image_url):
249
+ if site["clean_url"] in seen:
250
+ continue
251
+ seen.add(site["clean_url"])
252
+ domain = site["domain"] or "unknown"
253
+ counts[domain] = counts.get(domain, 0) + 1
254
+ return dict(sorted(counts.items(), key=lambda kv: -kv[1]))
@@ -0,0 +1,222 @@
1
+ Metadata-Version: 2.4
2
+ Name: yandex-reverse-image-api
3
+ Version: 0.0.1
4
+ Summary: Yandex reverse image search API client: source pages, similar images, product matches and image OCR via ScrapingBee.
5
+ Author: wordstotech
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/ScrapingBee/yandex-reverse-image-api
8
+ Project-URL: Repository, https://github.com/ScrapingBee/yandex-reverse-image-api
9
+ Project-URL: Documentation, https://www.scrapingbee.com/documentation/
10
+ Keywords: yandex scraper,yandex reverse image search api,yandex scraper api,reverse image search api,yandex images api,scrapingbee
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.8
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Internet :: WWW/HTTP
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Classifier: Topic :: Text Processing :: Markup :: HTML
25
+ Requires-Python: >=3.8
26
+ Description-Content-Type: text/markdown
27
+ License-File: LICENSE
28
+ Requires-Dist: requests>=2.25.0
29
+ Dynamic: license-file
30
+
31
+ # yandex-reverse-image-api
32
+
33
+ A Python client for Yandex reverse image search through ScrapingBee. One method per result tab, plus the check that tells a bad input apart from a genuine no match.
34
+
35
+ **Verified live on 2026-09-10 against two real images.** Every return value below is the actual output of the sweep, including the two that came back empty and the reason each did.
36
+
37
+ ```bash
38
+ pip install yandex-reverse-image-api
39
+ ```
40
+
41
+ Requires Python 3.8 or newer and `requests`.
42
+
43
+ ## Read this before you budget
44
+
45
+ **Every call costs 75 credits, and the cheap request does not work.**
46
+
47
+ A 1 credit fetch of a reverse image URL returns HTTP 200 with a 14,885 byte page titled `Are you not a robot?`, carrying Yandex SmartCaptcha. Nothing in the status code tells you the scrape failed. `spb-initial-status-code` reads `302`.
48
+
49
+ Stealth clears it, and there is no working middle rung between 1 and 75. So reverse image search on Yandex is 75 credits per lookup, full stop. At the entry paid tier of 250,000 credits that is about 3,300 lookups a month.
50
+
51
+ ScrapingBee does not cache. Reverse image results for a fixed image change slowly, so cache them yourself.
52
+
53
+ ## Authentication
54
+
55
+ ```python
56
+ from yandex_reverse_image_api import YandexReverseImage
57
+
58
+ bee = YandexReverseImage("YOUR_API_KEY")
59
+ ```
60
+
61
+ Sent as `Authorization: Bearer YOUR_API_KEY`. Key and 1,000 free credits: [ScrapingBee](https://www.scrapingbee.com/). Landing page: [Yandex reverse image API](https://www.scrapingbee.com/scrapers/yandex-reverse-image-api/).
62
+
63
+ ## Where the data lives
64
+
65
+ Not in the DOM. Yandex renders its result grid client side and ships the payload in `data-state` attributes as HTML escaped JSON, so **`extract_rules` and CSS selectors both match nothing on this target**. There are no result nodes in the markup to select.
66
+
67
+ This client finds every `data-state` attribute, unescapes it, loads the JSON and reads the slice you asked for off `initialState`. Yandex calls the feature CBIR, content based image retrieval, and that acronym prefixes every slice name.
68
+
69
+ ---
70
+
71
+ ## Method reference
72
+
73
+ ### `sites(image_url)`
74
+
75
+ The main event. Every page where the image appears. Uses `cbir_page=sites`.
76
+
77
+ ```python
78
+ matches = bee.sites("https://upload.wikimedia.org/wikipedia/commons/3/3c/Shaki_waterfall.jpg")
79
+ len(matches) # 37
80
+ ```
81
+
82
+ ```python
83
+ {'domain': 'en.wikipedia.org',
84
+ 'title': 'Shaki Waterfall - Wikipedia',
85
+ 'description': 'Shaki Waterfall. ',
86
+ 'url': 'https://en.wikipedia.org/wiki/Shaki_Waterfall?utm_medium=organic&utm_source=yandexsmartcamera',
87
+ 'clean_url': 'https://en.wikipedia.org/wiki/Shaki_Waterfall',
88
+ 'thumb': 'https://avatars.mds.yandex.net/i?id=eb74556e...',
89
+ 'width': 960,
90
+ 'height': 719,
91
+ 'original_image': 'https://upload.wikimedia.org/.../960px-Shaki_waterfall.jpg'}
92
+ ```
93
+
94
+ Two normalisations the client applies, because both bite otherwise:
95
+
96
+ - **`clean_url`** strips the query string. Yandex appends `?utm_medium=organic&utm_source=yandexsmartcamera` to every result URL, which breaks deduplication if you compare raw URLs.
97
+ - **`thumb`** is made absolute. Yandex returns it protocol relative, starting with `//`.
98
+
99
+ `width` and `height` are the dimensions of the copy hosted on that page, not of your input, which is how you find the highest resolution copy of an image in the wild.
100
+
101
+ ### `domains(image_url)`
102
+
103
+ Match count per domain, deduplicated on `clean_url`.
104
+
105
+ ```python
106
+ bee.domains(image_url)
107
+ # {'bestofarmenia.com': 2, 'armeniantrip.com': 2, 'yandex.ru': 2,
108
+ # 'hotel.am': 2, 'eastroute.com': 2, 'ug-ideal.ru': 2, ...}
109
+ ```
110
+
111
+ The shape most brand protection and counterfeit detection work actually wants.
112
+
113
+ ### `similar(image_url)`
114
+
115
+ Visually similar images. Uses `cbir_page=similar`. Returned **40 thumbs** on the test image.
116
+
117
+ ### `products(image_url)`
118
+
119
+ Shopping matches for the object. Uses `cbir_page=products`. Returned **0** on the test image, which is correct: a landscape photograph has no shopping match. Expect real entries on product photos.
120
+
121
+ ### `ocr(image_url)`
122
+
123
+ Text recognised inside the image.
124
+
125
+ ```python
126
+ bee.ocr(image_url)
127
+ # {'hasText': False, 'plainText': '', 'blocks': [], 'entities': [], ...}
128
+ ```
129
+
130
+ `hasText` was `False` on the test image, because a waterfall photograph has no text in it. That is the right answer, not a failure.
131
+
132
+ **This costs no extra credits.** OCR arrives in the same response as the default tab, so one 75 credit call gives you reverse image matches and the text inside the image with no separate step.
133
+
134
+ ### `tags(image_url)`
135
+
136
+ Yandex's own category labels. Returned **5 tags** on the test image.
137
+
138
+ ### `other_sizes(image_url)`
139
+
140
+ The same image at other resolutions, grouped into buckets.
141
+
142
+ ```python
143
+ bee.other_sizes(image_url)
144
+ # {'small_dups': [...6...], 'medium_dups': [...6...], 'large_dups': [...6...]}
145
+ ```
146
+
147
+ ### `check_image(image_url)`
148
+
149
+ **Run this first on any image you have not searched before.**
150
+
151
+ ```python
152
+ bee.check_image("https://upload.wikimedia.org/wikipedia/commons/3/3c/Shaki_waterfall.jpg")
153
+ # {'expired': False, 'width': 1024, 'height': 767, 'usable': True}
154
+ ```
155
+
156
+ Yandex fetches your image from the URL before it searches. If its crawler cannot reach the file, or the URL is a short lived derivative, you get a valid page with an empty result set and **no error message at all**.
157
+
158
+ Three images, same configuration, same stealth tier:
159
+
160
+ | Image | `cbirPreview` | Result |
161
+ |---|---|---|
162
+ | Wikimedia Commons full size JPEG | `expired: False`, 1024x767 | 37 sites, 40 similar, 5 tags |
163
+ | A Wikimedia `thumb/` derivative URL | `expired: True` | 0 matches |
164
+ | A `nasa.gov` PNG | `expired: True`, width 0, height 0 | 0 matches, `pageSize: 0` |
165
+
166
+ So an empty `sites` list plus `usable: False` is an input problem. An empty `sites` list with real dimensions is a genuine no match. Without this check the two are indistinguishable, and you will record "no matches found" for images that were never searched.
167
+
168
+ Hand Yandex a stable, directly addressable, full size URL.
169
+
170
+ ### `tab_url(image_url, cbir_page=None)`
171
+
172
+ A static method. **0 credits, no request.** Builds the Yandex URL for one tab.
173
+
174
+ ```python
175
+ YandexReverseImage.tab_url(img, "sites")
176
+ # 'https://yandex.com/images/search?rpt=imageview&cbir_page=sites&url=https%3A%2F%2F...'
177
+ ```
178
+
179
+ The four tab forms were read out of the live page's own `cbirNavigation.menuItems`, not guessed:
180
+
181
+ | Tab | `cbir_page` |
182
+ |---|---|
183
+ | Search by image | omit it |
184
+ | Similar | `similar` |
185
+ | Sites | `sites` |
186
+ | Products | `products` |
187
+
188
+ Note the double encoding: the image URL is percent encoded inside the Yandex URL, which is then passed as the ScrapingBee `url` parameter. This is the most common place a hand rolled version breaks.
189
+
190
+ ### `usage()`
191
+
192
+ Free. Account credits, concurrency and renewal date.
193
+
194
+ ---
195
+
196
+ ## Credit cost
197
+
198
+ Measured from `spb-cost` headers. Available on `bee.last_cost`.
199
+
200
+ | Configuration | Credits | Outcome |
201
+ |---|---|---|
202
+ | `mode=auto` | 1 | SmartCaptcha page |
203
+ | `stealth_proxy=true` | 75 | Real results |
204
+ | Validation error | 0 | Nothing billed |
205
+
206
+ `stealth_proxy` forces JavaScript rendering, and `mode=auto` is incompatible with it. Sending both returns HTTP 400 and bills nothing, which fails quietly.
207
+
208
+ Every method here is one call, so nine methods on one image is 675 credits. If you need several tabs for the same image, note that `ocr`, `tags`, `other_sizes` and `check_image` all read the default tab, so fetching once and parsing four slices locally is a single 75 credit charge.
209
+
210
+ Plan tiers: [ScrapingBee pricing](https://www.scrapingbee.com/pricing).
211
+
212
+ ## Related
213
+
214
+ Other visual search landing pages: [Yandex images API](https://www.scrapingbee.com/scrapers/yandex-images-api/), [Yandex search API](https://www.scrapingbee.com/scrapers/yandex-search-api/), [Google reverse image API](https://www.scrapingbee.com/scrapers/google-reverse-image-api/), [Google Lens API](https://www.scrapingbee.com/scrapers/google-lens-api/), [Google image scraper](https://www.scrapingbee.com/scrapers/google-image-scraper/), [Bing reverse image search API](https://www.scrapingbee.com/scrapers/bing-reverse-image-search-api/), [Bing images API](https://www.scrapingbee.com/scrapers/bing-images-api/), [eBay image search API](https://www.scrapingbee.com/scrapers/ebay-image-search-api/), [Naver images API](https://www.scrapingbee.com/scrapers/naver-images-api/), [Yahoo images API](https://www.scrapingbee.com/scrapers/yahoo-images-api/), [Getty images scraper API](https://www.scrapingbee.com/scrapers/getty-images-scraper-api/), [website image API](https://www.scrapingbee.com/scrapers/website-image-api/), [images results API](https://www.scrapingbee.com/scrapers/images-results-api/), [Amazon image API](https://www.scrapingbee.com/scrapers/amazon-image-api/).
215
+
216
+ Features: [AI web scraping](https://www.scrapingbee.com/features/ai-web-scraping-api/), [JavaScript scenario](https://www.scrapingbee.com/features/javascript-scenario/) for driving the upload widget instead of passing a URL, [screenshots](https://www.scrapingbee.com/features/screenshot/), [markdown scraper](https://www.scrapingbee.com/features/markdown-scraper/), [data extraction](https://www.scrapingbee.com/features/data-extraction/).
217
+
218
+ The Yandex text search walkthrough is at [how to scrape Yandex search results](https://www.scrapingbee.com/blog/how-to-scrape-yandex-search-results/). Tab by tab guide: [github.com/ScrapingBee/yandex-reverse-image-api](https://github.com/ScrapingBee/yandex-reverse-image-api).
219
+
220
+ ## License
221
+
222
+ MIT
@@ -0,0 +1,11 @@
1
+ LICENSE
2
+ MANIFEST.in
3
+ README.md
4
+ pyproject.toml
5
+ src/yandex_reverse_image_api/__init__.py
6
+ src/yandex_reverse_image_api/client.py
7
+ src/yandex_reverse_image_api.egg-info/PKG-INFO
8
+ src/yandex_reverse_image_api.egg-info/SOURCES.txt
9
+ src/yandex_reverse_image_api.egg-info/dependency_links.txt
10
+ src/yandex_reverse_image_api.egg-info/requires.txt
11
+ src/yandex_reverse_image_api.egg-info/top_level.txt