├── .gitignore ├── LICENSE ├── README.md ├── __init__.py ├── alchemyapi.py ├── example.py ├── pigeon.jpg └── tests.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | 3 | # C extensions 4 | *.so 5 | 6 | # Packages 7 | *.egg 8 | *.egg-info 9 | dist 10 | build 11 | eggs 12 | parts 13 | bin 14 | var 15 | sdist 16 | develop-eggs 17 | .installed.cfg 18 | lib 19 | lib64 20 | 21 | # Installer logs 22 | pip-log.txt 23 | 24 | # Unit test / coverage reports 25 | .coverage 26 | .tox 27 | nosetests.xml 28 | 29 | # Translations 30 | *.mo 31 | 32 | # Mr Developer 33 | .mr.developer.cfg 34 | .project 35 | .pydevproject 36 | 37 | # API Key (This is secret so it should not go in the git repo!!!) 38 | api_key.txt 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # alchemyapi_python # 2 | 3 | A sdk for AlchemyAPI using Python - **_Please note that this legacy AlchemyAPI SDK is no longer supported by IBM. Please use the Watson SDKs https://github.com/watson-developer-cloud?utf8=✓&query=sdk_** 4 | 5 | 6 | ## AlchemyAPI ## 7 | 8 | AlchemyAPI offers artificial intelligence as a service. We teach computers to learn how to read and see, and apply our technology to text analysis and image recognition through a cloud-based API. Our customers use AlchemyAPI to transform their unstructured content such as blog posts, news articles, social media posts and images into much more useful structured data. 9 | 10 | AlchemyAPI is a tech startup located in downtown Denver, Colorado. As the world’s most popular text analysis service, AlchemyAPI serves over 3.5 billion monthly API requests to over 35,000 developers. To enable our services, we use artificial intelligence, machine learning, neural networks, natural language processing and massive-scale web crawling. Our technology powers use cases in a variety of industry verticals, including social media monitoring, business intelligence, content recommendations, financial trading and targeted advertising. 11 | 12 | More information at: http://www.alchemyapi.com 13 | 14 | 15 | 16 | ## API Key ## 17 | 18 | To use AlchemyAPI, you'll need to obtain an API key and attach that key to all requests. If you do not already have a key, please visit: http://www.alchemyapi.com/api/register.html 19 | 20 | 21 | 22 | ## Requirements ## 23 | 24 | The Python SDK requires that you install the [Requests Python module](http://docs.python-requests.org/en/latest/user/install/#install). 25 | 26 | 27 | 28 | ## Getting Started with the Python SDK ## 29 | 30 | To get started and run the example, simply: 31 | 32 | git clone https://github.com/AlchemyAPI/alchemyapi_python.git 33 | cd alchemyapi_python 34 | python alchemyapi.py YOUR_API_KEY 35 | python example.py 36 | 37 | 38 | Just replace YOUR_API_KEY with your 40 character API key from AlchemyAPI, and you should be good to go. 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlchemyAPI/alchemyapi_python/f63716a1b08a67361f40a904f1514f97ace44ca6/__init__.py -------------------------------------------------------------------------------- /alchemyapi.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright 2013 AlchemyAPI 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | from __future__ import print_function 18 | 19 | import requests 20 | 21 | try: 22 | from urllib.request import urlopen 23 | from urllib.parse import urlparse 24 | from urllib.parse import urlencode 25 | except ImportError: 26 | from urlparse import urlparse 27 | from urllib2 import urlopen 28 | from urllib import urlencode 29 | 30 | try: 31 | import json 32 | except ImportError: 33 | # Older versions of Python (i.e. 2.4) require simplejson instead of json 34 | import simplejson as json 35 | 36 | 37 | if __name__ == '__main__': 38 | """ 39 | Writes the API key to api_key.txt file. It will create the file if it doesn't exist. 40 | This function is intended to be called from the Python command line using: python alchemyapi YOUR_API_KEY 41 | If you don't have an API key yet, register for one at: http://www.alchemyapi.com/api/register.html 42 | 43 | INPUT: 44 | argv[1] -> Your API key from AlchemyAPI. Should be 40 hex characters 45 | 46 | OUTPUT: 47 | none 48 | """ 49 | 50 | import sys 51 | if len(sys.argv) == 2 and sys.argv[1]: 52 | if len(sys.argv[1]) == 40: 53 | # write the key to the file 54 | f = open('api_key.txt', 'w') 55 | f.write(sys.argv[1]) 56 | f.close() 57 | print('Key: ' + sys.argv[1] + ' was written to api_key.txt') 58 | print( 59 | 'You are now ready to start using AlchemyAPI. For an example, run: python example.py') 60 | else: 61 | print( 62 | 'The key appears to invalid. Please make sure to use the 40 character key assigned by AlchemyAPI') 63 | 64 | 65 | class AlchemyAPI: 66 | # Setup the endpoints 67 | ENDPOINTS = {} 68 | ENDPOINTS['sentiment'] = {} 69 | ENDPOINTS['sentiment']['url'] = '/url/URLGetTextSentiment' 70 | ENDPOINTS['sentiment']['text'] = '/text/TextGetTextSentiment' 71 | ENDPOINTS['sentiment']['html'] = '/html/HTMLGetTextSentiment' 72 | ENDPOINTS['sentiment_targeted'] = {} 73 | ENDPOINTS['sentiment_targeted']['url'] = '/url/URLGetTargetedSentiment' 74 | ENDPOINTS['sentiment_targeted']['text'] = '/text/TextGetTargetedSentiment' 75 | ENDPOINTS['sentiment_targeted']['html'] = '/html/HTMLGetTargetedSentiment' 76 | ENDPOINTS['author'] = {} 77 | ENDPOINTS['author']['url'] = '/url/URLGetAuthor' 78 | ENDPOINTS['author']['html'] = '/html/HTMLGetAuthor' 79 | ENDPOINTS['keywords'] = {} 80 | ENDPOINTS['keywords']['url'] = '/url/URLGetRankedKeywords' 81 | ENDPOINTS['keywords']['text'] = '/text/TextGetRankedKeywords' 82 | ENDPOINTS['keywords']['html'] = '/html/HTMLGetRankedKeywords' 83 | ENDPOINTS['concepts'] = {} 84 | ENDPOINTS['concepts']['url'] = '/url/URLGetRankedConcepts' 85 | ENDPOINTS['concepts']['text'] = '/text/TextGetRankedConcepts' 86 | ENDPOINTS['concepts']['html'] = '/html/HTMLGetRankedConcepts' 87 | ENDPOINTS['entities'] = {} 88 | ENDPOINTS['entities']['url'] = '/url/URLGetRankedNamedEntities' 89 | ENDPOINTS['entities']['text'] = '/text/TextGetRankedNamedEntities' 90 | ENDPOINTS['entities']['html'] = '/html/HTMLGetRankedNamedEntities' 91 | ENDPOINTS['category'] = {} 92 | ENDPOINTS['category']['url'] = '/url/URLGetCategory' 93 | ENDPOINTS['category']['text'] = '/text/TextGetCategory' 94 | ENDPOINTS['category']['html'] = '/html/HTMLGetCategory' 95 | ENDPOINTS['relations'] = {} 96 | ENDPOINTS['relations']['url'] = '/url/URLGetRelations' 97 | ENDPOINTS['relations']['text'] = '/text/TextGetRelations' 98 | ENDPOINTS['relations']['html'] = '/html/HTMLGetRelations' 99 | ENDPOINTS['language'] = {} 100 | ENDPOINTS['language']['url'] = '/url/URLGetLanguage' 101 | ENDPOINTS['language']['text'] = '/text/TextGetLanguage' 102 | ENDPOINTS['language']['html'] = '/html/HTMLGetLanguage' 103 | ENDPOINTS['text'] = {} 104 | ENDPOINTS['text']['url'] = '/url/URLGetText' 105 | ENDPOINTS['text']['html'] = '/html/HTMLGetText' 106 | ENDPOINTS['text_raw'] = {} 107 | ENDPOINTS['text_raw']['url'] = '/url/URLGetRawText' 108 | ENDPOINTS['text_raw']['html'] = '/html/HTMLGetRawText' 109 | ENDPOINTS['title'] = {} 110 | ENDPOINTS['title']['url'] = '/url/URLGetTitle' 111 | ENDPOINTS['title']['html'] = '/html/HTMLGetTitle' 112 | ENDPOINTS['feeds'] = {} 113 | ENDPOINTS['feeds']['url'] = '/url/URLGetFeedLinks' 114 | ENDPOINTS['feeds']['html'] = '/html/HTMLGetFeedLinks' 115 | ENDPOINTS['microformats'] = {} 116 | ENDPOINTS['microformats']['url'] = '/url/URLGetMicroformatData' 117 | ENDPOINTS['microformats']['html'] = '/html/HTMLGetMicroformatData' 118 | ENDPOINTS['combined'] = {} 119 | ENDPOINTS['combined']['url'] = '/url/URLGetCombinedData' 120 | ENDPOINTS['combined']['text'] = '/text/TextGetCombinedData' 121 | ENDPOINTS['image'] = {} 122 | ENDPOINTS['image']['url'] = '/url/URLGetImage' 123 | ENDPOINTS['imagetagging'] = {} 124 | ENDPOINTS['imagetagging']['url'] = '/url/URLGetRankedImageKeywords' 125 | ENDPOINTS['imagetagging']['image'] = '/image/ImageGetRankedImageKeywords' 126 | ENDPOINTS['facetagging'] = {} 127 | ENDPOINTS['facetagging']['url'] = '/url/URLGetRankedImageFaceTags' 128 | ENDPOINTS['facetagging']['image'] = '/image/ImageGetRankedImageFaceTags' 129 | ENDPOINTS['taxonomy'] = {} 130 | ENDPOINTS['taxonomy']['url'] = '/url/URLGetRankedTaxonomy' 131 | ENDPOINTS['taxonomy']['html'] = '/html/HTMLGetRankedTaxonomy' 132 | ENDPOINTS['taxonomy']['text'] = '/text/TextGetRankedTaxonomy' 133 | 134 | # The base URL for all endpoints 135 | BASE_URL = 'http://access.alchemyapi.com/calls' 136 | 137 | s = requests.Session() 138 | 139 | def __init__(self): 140 | """ 141 | Initializes the SDK so it can send requests to AlchemyAPI for analysis. 142 | It loads the API key from api_key.txt and configures the endpoints. 143 | """ 144 | 145 | import sys 146 | try: 147 | # Open the key file and read the key 148 | f = open("api_key.txt", "r") 149 | key = f.read().strip() 150 | 151 | if key == '': 152 | # The key file should't be blank 153 | print( 154 | 'The api_key.txt file appears to be blank, please run: python alchemyapi.py YOUR_KEY_HERE') 155 | print( 156 | 'If you do not have an API Key from AlchemyAPI, please register for one at: http://www.alchemyapi.com/api/register.html') 157 | sys.exit(0) 158 | elif len(key) != 40: 159 | # Keys should be exactly 40 characters long 160 | print( 161 | 'It appears that the key in api_key.txt is invalid. Please make sure the file only includes the API key, and it is the correct one.') 162 | sys.exit(0) 163 | else: 164 | # setup the key 165 | self.apikey = key 166 | 167 | # Close file 168 | f.close() 169 | except IOError: 170 | # The file doesn't exist, so show the message and create the file. 171 | print( 172 | 'API Key not found! Please run: python alchemyapi.py YOUR_KEY_HERE') 173 | print( 174 | 'If you do not have an API Key from AlchemyAPI, please register for one at: http://www.alchemyapi.com/api/register.html') 175 | 176 | # create a blank key file 177 | open('api_key.txt', 'a').close() 178 | sys.exit(0) 179 | except Exception as e: 180 | print(e) 181 | 182 | def entities(self, flavor, data, options={}): 183 | """ 184 | Extracts the entities for text, a URL or HTML. 185 | For an overview, please refer to: http://www.alchemyapi.com/products/features/entity-extraction/ 186 | For the docs, please refer to: http://www.alchemyapi.com/api/entity-extraction/ 187 | 188 | INPUT: 189 | flavor -> which version of the call, i.e. text, url or html. 190 | data -> the data to analyze, either the text, the url or html code. 191 | options -> various parameters that can be used to adjust how the API works, see below for more info on the available options. 192 | 193 | Available Options: 194 | disambiguate -> disambiguate entities (i.e. Apple the company vs. apple the fruit). 0: disabled, 1: enabled (default) 195 | linkedData -> include linked data on disambiguated entities. 0: disabled, 1: enabled (default) 196 | coreference -> resolve coreferences (i.e. the pronouns that correspond to named entities). 0: disabled, 1: enabled (default) 197 | quotations -> extract quotations by entities. 0: disabled (default), 1: enabled. 198 | sentiment -> analyze sentiment for each entity. 0: disabled (default), 1: enabled. Requires 1 additional API transction if enabled. 199 | showSourceText -> 0: disabled (default), 1: enabled 200 | maxRetrieve -> the maximum number of entities to retrieve (default: 50) 201 | 202 | OUTPUT: 203 | The response, already converted from JSON to a Python object. 204 | """ 205 | 206 | # Make sure this request supports this flavor 207 | if flavor not in AlchemyAPI.ENDPOINTS['entities']: 208 | return {'status': 'ERROR', 'statusInfo': 'entity extraction for ' + flavor + ' not available'} 209 | 210 | # add the data to the options and analyze 211 | options[flavor] = data 212 | return self.__analyze(AlchemyAPI.ENDPOINTS['entities'][flavor], {}, options) 213 | 214 | def keywords(self, flavor, data, options={}): 215 | """ 216 | Extracts the keywords from text, a URL or HTML. 217 | For an overview, please refer to: http://www.alchemyapi.com/products/features/keyword-extraction/ 218 | For the docs, please refer to: http://www.alchemyapi.com/api/keyword-extraction/ 219 | 220 | INPUT: 221 | flavor -> which version of the call, i.e. text, url or html. 222 | data -> the data to analyze, either the text, the url or html code. 223 | options -> various parameters that can be used to adjust how the API works, see below for more info on the available options. 224 | 225 | Available Options: 226 | keywordExtractMode -> normal (default), strict 227 | sentiment -> analyze sentiment for each keyword. 0: disabled (default), 1: enabled. Requires 1 additional API transaction if enabled. 228 | showSourceText -> 0: disabled (default), 1: enabled. 229 | maxRetrieve -> the max number of keywords returned (default: 50) 230 | 231 | OUTPUT: 232 | The response, already converted from JSON to a Python object. 233 | """ 234 | 235 | # Make sure this request supports this flavor 236 | if flavor not in AlchemyAPI.ENDPOINTS['keywords']: 237 | return {'status': 'ERROR', 'statusInfo': 'keyword extraction for ' + flavor + ' not available'} 238 | 239 | # add the data to the options and analyze 240 | options[flavor] = data 241 | return self.__analyze(AlchemyAPI.ENDPOINTS['keywords'][flavor], {}, options) 242 | 243 | def concepts(self, flavor, data, options={}): 244 | """ 245 | Tags the concepts for text, a URL or HTML. 246 | For an overview, please refer to: http://www.alchemyapi.com/products/features/concept-tagging/ 247 | For the docs, please refer to: http://www.alchemyapi.com/api/concept-tagging/ 248 | 249 | Available Options: 250 | maxRetrieve -> the maximum number of concepts to retrieve (default: 8) 251 | linkedData -> include linked data, 0: disabled, 1: enabled (default) 252 | showSourceText -> 0:disabled (default), 1: enabled 253 | 254 | OUTPUT: 255 | The response, already converted from JSON to a Python object. 256 | """ 257 | 258 | # Make sure this request supports this flavor 259 | if flavor not in AlchemyAPI.ENDPOINTS['concepts']: 260 | return {'status': 'ERROR', 'statusInfo': 'concept tagging for ' + flavor + ' not available'} 261 | 262 | # add the data to the options and analyze 263 | options[flavor] = data 264 | return self.__analyze(AlchemyAPI.ENDPOINTS['concepts'][flavor], {}, options) 265 | 266 | def sentiment(self, flavor, data, options={}): 267 | """ 268 | Calculates the sentiment for text, a URL or HTML. 269 | For an overview, please refer to: http://www.alchemyapi.com/products/features/sentiment-analysis/ 270 | For the docs, please refer to: http://www.alchemyapi.com/api/sentiment-analysis/ 271 | 272 | INPUT: 273 | flavor -> which version of the call, i.e. text, url or html. 274 | data -> the data to analyze, either the text, the url or html code. 275 | options -> various parameters that can be used to adjust how the API works, see below for more info on the available options. 276 | 277 | Available Options: 278 | showSourceText -> 0: disabled (default), 1: enabled 279 | 280 | OUTPUT: 281 | The response, already converted from JSON to a Python object. 282 | """ 283 | 284 | # Make sure this request supports this flavor 285 | if flavor not in AlchemyAPI.ENDPOINTS['sentiment']: 286 | return {'status': 'ERROR', 'statusInfo': 'sentiment analysis for ' + flavor + ' not available'} 287 | 288 | # add the data to the options and analyze 289 | options[flavor] = data 290 | return self.__analyze(AlchemyAPI.ENDPOINTS['sentiment'][flavor], {}, options) 291 | 292 | def sentiment_targeted(self, flavor, data, target, options={}): 293 | """ 294 | Calculates the targeted sentiment for text, a URL or HTML. 295 | For an overview, please refer to: http://www.alchemyapi.com/products/features/sentiment-analysis/ 296 | For the docs, please refer to: http://www.alchemyapi.com/api/sentiment-analysis/ 297 | 298 | INPUT: 299 | flavor -> which version of the call, i.e. text, url or html. 300 | data -> the data to analyze, either the text, the url or html code. 301 | target -> the word or phrase to run sentiment analysis on. 302 | options -> various parameters that can be used to adjust how the API works, see below for more info on the available options. 303 | 304 | Available Options: 305 | showSourceText -> 0: disabled, 1: enabled 306 | 307 | OUTPUT: 308 | The response, already converted from JSON to a Python object. 309 | """ 310 | 311 | # Make sure the target is valid 312 | if target is None or target == '': 313 | return {'status': 'ERROR', 'statusInfo': 'targeted sentiment requires a non-null target'} 314 | 315 | # Make sure this request supports this flavor 316 | if flavor not in AlchemyAPI.ENDPOINTS['sentiment_targeted']: 317 | return {'status': 'ERROR', 'statusInfo': 'targeted sentiment analysis for ' + flavor + ' not available'} 318 | 319 | # add the URL encoded data and target to the options and analyze 320 | options[flavor] = data 321 | options['target'] = target 322 | return self.__analyze(AlchemyAPI.ENDPOINTS['sentiment_targeted'][flavor], {}, options) 323 | 324 | def text(self, flavor, data, options={}): 325 | """ 326 | Extracts the cleaned text (removes ads, navigation, etc.) for text, a URL or HTML. 327 | For an overview, please refer to: http://www.alchemyapi.com/products/features/text-extraction/ 328 | For the docs, please refer to: http://www.alchemyapi.com/api/text-extraction/ 329 | 330 | INPUT: 331 | flavor -> which version of the call, i.e. text, url or html. 332 | data -> the data to analyze, either the text, the url or html code. 333 | options -> various parameters that can be used to adjust how the API works, see below for more info on the available options. 334 | 335 | Available Options: 336 | useMetadata -> utilize meta description data, 0: disabled, 1: enabled (default) 337 | extractLinks -> include links, 0: disabled (default), 1: enabled. 338 | 339 | OUTPUT: 340 | The response, already converted from JSON to a Python object. 341 | """ 342 | 343 | # Make sure this request supports this flavor 344 | if flavor not in AlchemyAPI.ENDPOINTS['text']: 345 | return {'status': 'ERROR', 'statusInfo': 'clean text extraction for ' + flavor + ' not available'} 346 | 347 | # add the data to the options and analyze 348 | options[flavor] = data 349 | return self.__analyze(AlchemyAPI.ENDPOINTS['text'][flavor], options) 350 | 351 | def text_raw(self, flavor, data, options={}): 352 | """ 353 | Extracts the raw text (includes ads, navigation, etc.) for a URL or HTML. 354 | For an overview, please refer to: http://www.alchemyapi.com/products/features/text-extraction/ 355 | For the docs, please refer to: http://www.alchemyapi.com/api/text-extraction/ 356 | 357 | INPUT: 358 | flavor -> which version of the call, i.e. text, url or html. 359 | data -> the data to analyze, either the text, the url or html code. 360 | options -> various parameters that can be used to adjust how the API works, see below for more info on the available options. 361 | 362 | Available Options: 363 | none 364 | 365 | OUTPUT: 366 | The response, already converted from JSON to a Python object. 367 | """ 368 | 369 | # Make sure this request supports this flavor 370 | if flavor not in AlchemyAPI.ENDPOINTS['text_raw']: 371 | return {'status': 'ERROR', 'statusInfo': 'raw text extraction for ' + flavor + ' not available'} 372 | 373 | # add the data to the options and analyze 374 | options[flavor] = data 375 | return self.__analyze(AlchemyAPI.ENDPOINTS['text_raw'][flavor], {}, options) 376 | 377 | def author(self, flavor, data, options={}): 378 | """ 379 | Extracts the author from a URL or HTML. 380 | For an overview, please refer to: http://www.alchemyapi.com/products/features/author-extraction/ 381 | For the docs, please refer to: http://www.alchemyapi.com/api/author-extraction/ 382 | 383 | INPUT: 384 | flavor -> which version of the call, i.e. text, url or html. 385 | data -> the data to analyze, either the text, the url or html code. 386 | options -> various parameters that can be used to adjust how the API works, see below for more info on the available options. 387 | 388 | Availble Options: 389 | none 390 | 391 | OUTPUT: 392 | The response, already converted from JSON to a Python object. 393 | """ 394 | 395 | # Make sure this request supports this flavor 396 | if flavor not in AlchemyAPI.ENDPOINTS['author']: 397 | return {'status': 'ERROR', 'statusInfo': 'author extraction for ' + flavor + ' not available'} 398 | 399 | # add the data to the options and analyze 400 | options[flavor] = data 401 | return self.__analyze(AlchemyAPI.ENDPOINTS['author'][flavor], {}, options) 402 | 403 | def language(self, flavor, data, options={}): 404 | """ 405 | Detects the language for text, a URL or HTML. 406 | For an overview, please refer to: http://www.alchemyapi.com/api/language-detection/ 407 | For the docs, please refer to: http://www.alchemyapi.com/products/features/language-detection/ 408 | 409 | INPUT: 410 | flavor -> which version of the call, i.e. text, url or html. 411 | data -> the data to analyze, either the text, the url or html code. 412 | options -> various parameters that can be used to adjust how the API works, see below for more info on the available options. 413 | 414 | Available Options: 415 | none 416 | 417 | OUTPUT: 418 | The response, already converted from JSON to a Python object. 419 | """ 420 | 421 | # Make sure this request supports this flavor 422 | if flavor not in AlchemyAPI.ENDPOINTS['language']: 423 | return {'status': 'ERROR', 'statusInfo': 'language detection for ' + flavor + ' not available'} 424 | 425 | # add the data to the options and analyze 426 | options[flavor] = data 427 | return self.__analyze(AlchemyAPI.ENDPOINTS['language'][flavor], {}, options) 428 | 429 | def title(self, flavor, data, options={}): 430 | """ 431 | Extracts the title for a URL or HTML. 432 | For an overview, please refer to: http://www.alchemyapi.com/products/features/text-extraction/ 433 | For the docs, please refer to: http://www.alchemyapi.com/api/text-extraction/ 434 | 435 | INPUT: 436 | flavor -> which version of the call, i.e. text, url or html. 437 | data -> the data to analyze, either the text, the url or html code. 438 | options -> various parameters that can be used to adjust how the API works, see below for more info on the available options. 439 | 440 | Available Options: 441 | useMetadata -> utilize title info embedded in meta data, 0: disabled, 1: enabled (default) 442 | 443 | OUTPUT: 444 | The response, already converted from JSON to a Python object. 445 | """ 446 | 447 | # Make sure this request supports this flavor 448 | if flavor not in AlchemyAPI.ENDPOINTS['title']: 449 | return {'status': 'ERROR', 'statusInfo': 'title extraction for ' + flavor + ' not available'} 450 | 451 | # add the data to the options and analyze 452 | options[flavor] = data 453 | return self.__analyze(AlchemyAPI.ENDPOINTS['title'][flavor], {}, options) 454 | 455 | def relations(self, flavor, data, options={}): 456 | """ 457 | Extracts the relations for text, a URL or HTML. 458 | For an overview, please refer to: http://www.alchemyapi.com/products/features/relation-extraction/ 459 | For the docs, please refer to: http://www.alchemyapi.com/api/relation-extraction/ 460 | 461 | INPUT: 462 | flavor -> which version of the call, i.e. text, url or html. 463 | data -> the data to analyze, either the text, the url or html code. 464 | options -> various parameters that can be used to adjust how the API works, see below for more info on the available options. 465 | 466 | Available Options: 467 | sentiment -> 0: disabled (default), 1: enabled. Requires one additional API transaction if enabled. 468 | keywords -> extract keywords from the subject and object. 0: disabled (default), 1: enabled. Requires one additional API transaction if enabled. 469 | entities -> extract entities from the subject and object. 0: disabled (default), 1: enabled. Requires one additional API transaction if enabled. 470 | requireEntities -> only extract relations that have entities. 0: disabled (default), 1: enabled. 471 | sentimentExcludeEntities -> exclude full entity name in sentiment analysis. 0: disabled, 1: enabled (default) 472 | disambiguate -> disambiguate entities (i.e. Apple the company vs. apple the fruit). 0: disabled, 1: enabled (default) 473 | linkedData -> include linked data with disambiguated entities. 0: disabled, 1: enabled (default). 474 | coreference -> resolve entity coreferences. 0: disabled, 1: enabled (default) 475 | showSourceText -> 0: disabled (default), 1: enabled. 476 | maxRetrieve -> the maximum number of relations to extract (default: 50, max: 100) 477 | 478 | OUTPUT: 479 | The response, already converted from JSON to a Python object. 480 | """ 481 | 482 | # Make sure this request supports this flavor 483 | if flavor not in AlchemyAPI.ENDPOINTS['relations']: 484 | return {'status': 'ERROR', 'statusInfo': 'relation extraction for ' + flavor + ' not available'} 485 | 486 | # add the data to the options and analyze 487 | options[flavor] = data 488 | return self.__analyze(AlchemyAPI.ENDPOINTS['relations'][flavor], {}, options) 489 | 490 | def category(self, flavor, data, options={}): 491 | """ 492 | Categorizes the text for text, a URL or HTML. 493 | For an overview, please refer to: http://www.alchemyapi.com/products/features/text-categorization/ 494 | For the docs, please refer to: http://www.alchemyapi.com/api/text-categorization/ 495 | 496 | INPUT: 497 | flavor -> which version of the call, i.e. text, url or html. 498 | data -> the data to analyze, either the text, the url or html code. 499 | options -> various parameters that can be used to adjust how the API works, see below for more info on the available options. 500 | 501 | Available Options: 502 | showSourceText -> 0: disabled (default), 1: enabled 503 | 504 | OUTPUT: 505 | The response, already converted from JSON to a Python object. 506 | """ 507 | 508 | # Make sure this request supports this flavor 509 | if flavor not in AlchemyAPI.ENDPOINTS['category']: 510 | return {'status': 'ERROR', 'statusInfo': 'text categorization for ' + flavor + ' not available'} 511 | 512 | # add the data to the options and analyze 513 | options[flavor] = data 514 | 515 | return self.__analyze(AlchemyAPI.ENDPOINTS['category'][flavor], {}, options) 516 | 517 | def feeds(self, flavor, data, options={}): 518 | """ 519 | Detects the RSS/ATOM feeds for a URL or HTML. 520 | For an overview, please refer to: http://www.alchemyapi.com/products/features/feed-detection/ 521 | For the docs, please refer to: http://www.alchemyapi.com/api/feed-detection/ 522 | 523 | INPUT: 524 | flavor -> which version of the call, i.e. url or html. 525 | data -> the data to analyze, either the the url or html code. 526 | options -> various parameters that can be used to adjust how the API works, see below for more info on the available options. 527 | 528 | Available Options: 529 | none 530 | 531 | OUTPUT: 532 | The response, already converted from JSON to a Python object. 533 | """ 534 | 535 | # Make sure this request supports this flavor 536 | if flavor not in AlchemyAPI.ENDPOINTS['feeds']: 537 | return {'status': 'ERROR', 'statusInfo': 'feed detection for ' + flavor + ' not available'} 538 | 539 | # add the data to the options and analyze 540 | options[flavor] = data 541 | return self.__analyze(AlchemyAPI.ENDPOINTS['feeds'][flavor], {}, options) 542 | 543 | def microformats(self, flavor, data, options={}): 544 | """ 545 | Parses the microformats for a URL or HTML. 546 | For an overview, please refer to: http://www.alchemyapi.com/products/features/microformats-parsing/ 547 | For the docs, please refer to: http://www.alchemyapi.com/api/microformats-parsing/ 548 | 549 | INPUT: 550 | flavor -> which version of the call, i.e. url or html. 551 | data -> the data to analyze, either the the url or html code. 552 | options -> various parameters that can be used to adjust how the API works, see below for more info on the available options. 553 | 554 | Available Options: 555 | none 556 | 557 | OUTPUT: 558 | The response, already converted from JSON to a Python object. 559 | """ 560 | 561 | # Make sure this request supports this flavor 562 | if flavor not in AlchemyAPI.ENDPOINTS['microformats']: 563 | return {'status': 'ERROR', 'statusInfo': 'microformat extraction for ' + flavor + ' not available'} 564 | 565 | # add the data to the options and analyze 566 | options[flavor] = data 567 | return self.__analyze(AlchemyAPI.ENDPOINTS['microformats'][flavor], {}, options) 568 | 569 | def imageExtraction(self, flavor, data, options={}): 570 | """ 571 | Extracts main image from a URL 572 | 573 | INPUT: 574 | flavor -> which version of the call (url only currently). 575 | data -> URL to analyze 576 | options -> various parameters that can be used to adjust how the API works, 577 | see below for more info on the available options. 578 | 579 | Available Options: 580 | extractMode -> 581 | trust-metadata : (less CPU intensive, less accurate) 582 | always-infer : (more CPU intensive, more accurate) 583 | OUTPUT: 584 | The response, already converted from JSON to a Python object. 585 | """ 586 | if flavor not in AlchemyAPI.ENDPOINTS['image']: 587 | return {'status': 'ERROR', 'statusInfo': 'image extraction for ' + flavor + ' not available'} 588 | options[flavor] = data 589 | return self.__analyze(AlchemyAPI.ENDPOINTS['image'][flavor], {}, options) 590 | 591 | def taxonomy(self, flavor, data, options={}): 592 | """ 593 | Taxonomy classification operations. 594 | 595 | INPUT: 596 | flavor -> which version of the call, i.e. url or html. 597 | data -> the data to analyze, either the the url or html code. 598 | options -> various parameters that can be used to adjust how the API works, see below for more info on the available options. 599 | 600 | 601 | Available Options: 602 | showSourceText -> 603 | include the original 'source text' the taxonomy categories were extracted from within the API response 604 | Possible values: 605 | 1 - enabled 606 | 0 - disabled (default) 607 | 608 | sourceText -> 609 | where to obtain the text that will be processed by this API call. 610 | 611 | AlchemyAPI supports multiple modes of text extraction: 612 | web page cleaning (removes ads, navigation links, etc.), raw text extraction 613 | (processes all web page text, including ads / nav links), visual constraint queries, and XPath queries. 614 | 615 | Possible values: 616 | cleaned_or_raw : cleaning enabled, fallback to raw when cleaning produces no text (default) 617 | cleaned : operate on 'cleaned' web page text (web page cleaning enabled) 618 | raw : operate on raw web page text (web page cleaning disabled) 619 | cquery : operate on the results of a visual constraints query 620 | Note: The 'cquery' http argument must also be set to a valid visual constraints query. 621 | xpath : operate on the results of an XPath query 622 | Note: The 'xpath' http argument must also be set to a valid XPath query. 623 | 624 | cquery -> 625 | a visual constraints query to apply to the web page. 626 | 627 | xpath -> 628 | an XPath query to apply to the web page. 629 | 630 | baseUrl -> 631 | rel-tag output base http url (must be uri-argument encoded) 632 | 633 | OUTPUT: 634 | The response, already converted from JSON to a Python object. 635 | 636 | """ 637 | if flavor not in AlchemyAPI.ENDPOINTS['taxonomy']: 638 | return {'status': 'ERROR', 'statusInfo': 'taxonomy for ' + flavor + ' not available'} 639 | options[flavor] = data 640 | return self.__analyze(AlchemyAPI.ENDPOINTS['taxonomy'][flavor], {}, options) 641 | 642 | def combined(self, flavor, data, options={}): 643 | """ 644 | Combined call for page-image, entity, keyword, title, author, taxonomy, concept. 645 | 646 | INPUT: 647 | flavor -> which version of the call, i.e. url or html. 648 | data -> the data to analyze, either the the url or html code. 649 | options -> various parameters that can be used to adjust how the API works, see below for more info on the available options. 650 | 651 | Available Options: 652 | extract -> 653 | Possible values: page-image, entity, keyword, title, author, taxonomy, concept 654 | default : entity, keyword, taxonomy, concept 655 | 656 | disambiguate -> 657 | disambiguate detected entities 658 | Possible values: 659 | 1 : enabled (default) 660 | 0 : disabled 661 | 662 | linkedData -> 663 | include Linked Data content links with disambiguated entities 664 | Possible values : 665 | 1 : enabled (default) 666 | 0 : disabled 667 | 668 | coreference -> 669 | resolve he/she/etc coreferences into detected entities 670 | Possible values: 671 | 1 : enabled (default) 672 | 0 : disabled 673 | 674 | quotations -> 675 | enable quotations extraction 676 | Possible values: 677 | 1 : enabled 678 | 0 : disabled (default) 679 | 680 | sentiment -> 681 | enable entity-level sentiment analysis 682 | Possible values: 683 | 1 : enabled 684 | 0 : disabled (default) 685 | 686 | showSourceText -> 687 | include the original 'source text' the entities were extracted from within the API response 688 | Possible values: 689 | 1 : enabled 690 | 0 : disabled (default) 691 | 692 | maxRetrieve -> 693 | maximum number of named entities to extract 694 | default : 50 695 | 696 | baseUrl -> 697 | rel-tag output base http url 698 | 699 | 700 | OUTPUT: 701 | The response, already converted from JSON to a Python object. 702 | """ 703 | if flavor not in AlchemyAPI.ENDPOINTS['combined']: 704 | return {'status': 'ERROR', 'statusInfo': 'combined for ' + flavor + ' not available'} 705 | options[flavor] = data 706 | return self.__analyze(AlchemyAPI.ENDPOINTS['combined'][flavor], {}, options) 707 | 708 | def imageTagging(self, flavor, data, options={}): 709 | """ 710 | 711 | INPUT: 712 | flavor -> which version of the call only url or image. 713 | data -> the data to analyze, either the the url or path to image. 714 | options -> various parameters that can be used to adjust how the API works, see below for more info on the available options. 715 | """ 716 | if flavor not in AlchemyAPI.ENDPOINTS['imagetagging']: 717 | return {'status': 'ERROR', 'statusInfo': 'imagetagging for ' + flavor + ' not available'} 718 | elif 'image' == flavor: 719 | image = open(data, 'rb').read() 720 | options['imagePostMode'] = 'raw' 721 | return self.__analyze(AlchemyAPI.ENDPOINTS['imagetagging'][flavor], options, image) 722 | 723 | options[flavor] = data 724 | return self.__analyze(AlchemyAPI.ENDPOINTS['imagetagging'][flavor], {}, options) 725 | 726 | def faceTagging(self, flavor, data, options={}): 727 | """ 728 | 729 | INPUT: 730 | flavor -> which version of the call only url or image. 731 | data -> the data to analyze, either the the url or path to image. 732 | options -> various parameters that can be used to adjust how the API works, see below for more info on the available options. 733 | """ 734 | if flavor not in AlchemyAPI.ENDPOINTS['facetagging']: 735 | return {'status': 'ERROR', 'statusInfo': 'facetagging for ' + flavor + ' not available'} 736 | elif 'image' == flavor: 737 | image = open(data, 'rb').read() 738 | options['imagePostMode'] = 'raw' 739 | return self.__analyze(AlchemyAPI.ENDPOINTS['facetagging'][flavor], options, image) 740 | 741 | options[flavor] = data 742 | return self.__analyze(AlchemyAPI.ENDPOINTS['facetagging'][flavor], {}, options) 743 | 744 | def __analyze(self, endpoint, params, post_data=bytearray()): 745 | """ 746 | HTTP Request wrapper that is called by the endpoint functions. This function is not intended to be called through an external interface. 747 | It makes the call, then converts the returned JSON string into a Python object. 748 | 749 | INPUT: 750 | url -> the full URI encoded url 751 | 752 | OUTPUT: 753 | The response, already converted from JSON to a Python object. 754 | """ 755 | 756 | # Add the API Key and set the output mode to JSON 757 | params['apikey'] = self.apikey 758 | params['outputMode'] = 'json' 759 | # Insert the base url 760 | 761 | post_url = "" 762 | try: 763 | post_url = AlchemyAPI.BASE_URL + endpoint + \ 764 | '?' + urlencode(params).encode('utf-8') 765 | except TypeError: 766 | post_url = AlchemyAPI.BASE_URL + endpoint + '?' + urlencode(params) 767 | 768 | results = "" 769 | try: 770 | results = self.s.post(url=post_url, data=post_data) 771 | except Exception as e: 772 | print(e) 773 | return {'status': 'ERROR', 'statusInfo': 'network-error'} 774 | try: 775 | return results.json() 776 | except Exception as e: 777 | if results != "": 778 | print(results) 779 | print(e) 780 | return {'status': 'ERROR', 'statusInfo': 'parse-error'} 781 | -------------------------------------------------------------------------------- /example.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright 2013 AlchemyAPI 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | 18 | from __future__ import print_function 19 | from alchemyapi import AlchemyAPI 20 | import json 21 | 22 | 23 | demo_text = 'Yesterday dumb Bob destroyed my fancy iPhone in beautiful Denver, Colorado. I guess I will have to head over to the Apple Store and buy a new one.' 24 | demo_url = 'http://www.npr.org/2013/11/26/247336038/dont-stuff-the-turkey-and-other-tips-from-americas-test-kitchen' 25 | demo_html = 'Python Demo | AlchemyAPI

Did you know that AlchemyAPI works on HTML?

Well, you do now.

' 26 | image_url = 'http://demo1.alchemyapi.com/images/vision/football.jpg' 27 | 28 | print('') 29 | print('') 30 | print( 31 | ' , ') 32 | print( 33 | ' .I7777~ ') 34 | print( 35 | ' .I7777777 ') 36 | print( 37 | ' +. 77777777 ') 38 | print( 39 | ' =???, I7777777= ') 40 | print( 41 | '=?????? 7777777? ,:::===? ') 42 | print( 43 | '=???????. 777777777777777777~ .77: ?? :7 =$, :$$$$$$+ =$? ') 44 | print( 45 | ' ????????: .777777777777777777 II77 ?? :7 $$7 :$? 7$7 =$? ') 46 | print( 47 | ' .???????= +7777777777777777 .7 =7: ?? :7777+ :7:I777? ?777I= 77~777? ,777I I7 77 +$?$: :$? $$ =$? ') 48 | print( 49 | ' ???????+ ~777???+===::: :7+ ~7 ?? .77 +7 :7?. II 7~ ,I7 77+ I77 ~7 ?7 =7: .$, =$ :$? ,$$? =$? ') 50 | print( 51 | ' ,???????~ 77 7: ?? ?I. 7 :7 :7 ~7 7 77 =7: 7 7 7~ 7$ $= :$$$$$$~ =$? ') 52 | print( 53 | ' .??????? ,???I77777777777~ :77777777~ ?? 7: :7 :7 777777777:77 =7 7 +7 ~7 $$$$$$$$I :$? =$? ') 54 | print( 55 | ' .??????? ,7777777777777777 7= 77 ?? I+ 7 :7 :7 ?? 7,77 =7 7 7~ 7, =$7 $$, :$? =$? ') 56 | print( 57 | ' .???????. I77777777777777777 +7 ,7??? 77 I7 :7 :7 7~ .?7 77 =7 7 ,77I $+ 7$ :$? =$? ') 58 | print( 59 | ' ,???????= :77777777777777777~ 7= ~7?? ~I77777 :7 :7 ,777777. 77 =7 7 77, +$ .$::$? =$? ') 60 | print( 61 | ',??????? :7777777 77 ') 62 | print( 63 | ' =????? ,7777777 77= ') 64 | print( 65 | ' +?+ 7777777? ') 66 | print( 67 | ' + ~7777777 ') 68 | print( 69 | ' I777777 ') 70 | print( 71 | ' :~ ') 72 | 73 | 74 | # Create the AlchemyAPI Object 75 | alchemyapi = AlchemyAPI() 76 | 77 | print('') 78 | print('') 79 | print('############################################') 80 | print('# Entity Extraction Example #') 81 | print('############################################') 82 | print('') 83 | print('') 84 | 85 | print('Processing text: ', demo_text) 86 | print('') 87 | 88 | response = alchemyapi.entities('text', demo_text, {'sentiment': 1}) 89 | 90 | if response['status'] == 'OK': 91 | print('## Response Object ##') 92 | print(json.dumps(response, indent=4)) 93 | 94 | print('') 95 | print('## Entities ##') 96 | for entity in response['entities']: 97 | print('text: ', entity['text'].encode('utf-8')) 98 | print('type: ', entity['type']) 99 | print('relevance: ', entity['relevance']) 100 | print('sentiment: ', entity['sentiment']['type']) 101 | if 'score' in entity['sentiment']: 102 | print('sentiment score: ' + entity['sentiment']['score']) 103 | print('') 104 | else: 105 | print('Error in entity extraction call: ', response['statusInfo']) 106 | 107 | 108 | print('') 109 | print('') 110 | print('') 111 | print('############################################') 112 | print('# Keyword Extraction Example #') 113 | print('############################################') 114 | print('') 115 | print('') 116 | 117 | print('Processing text: ', demo_text) 118 | print('') 119 | 120 | response = alchemyapi.keywords('text', demo_text, {'sentiment': 1}) 121 | 122 | if response['status'] == 'OK': 123 | print('## Response Object ##') 124 | print(json.dumps(response, indent=4)) 125 | 126 | print('') 127 | print('## Keywords ##') 128 | for keyword in response['keywords']: 129 | print('text: ', keyword['text'].encode('utf-8')) 130 | print('relevance: ', keyword['relevance']) 131 | print('sentiment: ', keyword['sentiment']['type']) 132 | if 'score' in keyword['sentiment']: 133 | print('sentiment score: ' + keyword['sentiment']['score']) 134 | print('') 135 | else: 136 | print('Error in keyword extaction call: ', response['statusInfo']) 137 | 138 | 139 | print('') 140 | print('') 141 | print('') 142 | print('############################################') 143 | print('# Concept Tagging Example #') 144 | print('############################################') 145 | print('') 146 | print('') 147 | 148 | print('Processing text: ', demo_text) 149 | print('') 150 | 151 | response = alchemyapi.concepts('text', demo_text) 152 | 153 | if response['status'] == 'OK': 154 | print('## Object ##') 155 | print(json.dumps(response, indent=4)) 156 | 157 | print('') 158 | print('## Concepts ##') 159 | for concept in response['concepts']: 160 | print('text: ', concept['text']) 161 | print('relevance: ', concept['relevance']) 162 | print('') 163 | else: 164 | print('Error in concept tagging call: ', response['statusInfo']) 165 | 166 | 167 | print('') 168 | print('') 169 | print('') 170 | print('############################################') 171 | print('# Sentiment Analysis Example #') 172 | print('############################################') 173 | print('') 174 | print('') 175 | 176 | print('Processing html: ', demo_html) 177 | print('') 178 | 179 | response = alchemyapi.sentiment('html', demo_html) 180 | 181 | if response['status'] == 'OK': 182 | print('## Response Object ##') 183 | print(json.dumps(response, indent=4)) 184 | 185 | print('') 186 | print('## Document Sentiment ##') 187 | print('type: ', response['docSentiment']['type']) 188 | 189 | if 'score' in response['docSentiment']: 190 | print('score: ', response['docSentiment']['score']) 191 | else: 192 | print('Error in sentiment analysis call: ', response['statusInfo']) 193 | 194 | 195 | print('') 196 | print('') 197 | print('') 198 | print('############################################') 199 | print('# Targeted Sentiment Analysis Example #') 200 | print('############################################') 201 | print('') 202 | print('') 203 | 204 | print('Processing text: ', demo_text) 205 | print('') 206 | 207 | response = alchemyapi.sentiment_targeted('text', demo_text, 'Denver') 208 | 209 | if response['status'] == 'OK': 210 | print('## Response Object ##') 211 | print(json.dumps(response, indent=4)) 212 | 213 | print('') 214 | print('## Targeted Sentiment ##') 215 | print('type: ', response['docSentiment']['type']) 216 | 217 | if 'score' in response['docSentiment']: 218 | print('score: ', response['docSentiment']['score']) 219 | else: 220 | print('Error in targeted sentiment analysis call: ', 221 | response['statusInfo']) 222 | 223 | 224 | print('') 225 | print('') 226 | print('') 227 | print('############################################') 228 | print('# Text Extraction Example #') 229 | print('############################################') 230 | print('') 231 | print('') 232 | 233 | print('Processing url: ', demo_url) 234 | print('') 235 | 236 | response = alchemyapi.text('url', demo_url) 237 | 238 | if response['status'] == 'OK': 239 | print('## Response Object ##') 240 | print(json.dumps(response, indent=4)) 241 | 242 | print('') 243 | print('## Text ##') 244 | print('text: ', response['text'].encode('utf-8')) 245 | print('') 246 | else: 247 | print('Error in text extraction call: ', response['statusInfo']) 248 | 249 | 250 | print('') 251 | print('') 252 | print('') 253 | print('############################################') 254 | print('# Author Extraction Example #') 255 | print('############################################') 256 | print('') 257 | print('') 258 | 259 | print('Processing url: ', demo_url) 260 | print('') 261 | 262 | response = alchemyapi.author('url', demo_url) 263 | 264 | if response['status'] == 'OK': 265 | print('## Response Object ##') 266 | print(json.dumps(response, indent=4)) 267 | 268 | print('') 269 | print('## Author ##') 270 | print('author: ', response['author'].encode('utf-8')) 271 | print('') 272 | else: 273 | print('Error in author extraction call: ', response['statusInfo']) 274 | 275 | 276 | print('') 277 | print('') 278 | print('') 279 | print('############################################') 280 | print('# Language Detection Example #') 281 | print('############################################') 282 | print('') 283 | print('') 284 | 285 | print('Processing text: ', demo_text) 286 | print('') 287 | 288 | response = alchemyapi.language('text', demo_text) 289 | 290 | if response['status'] == 'OK': 291 | print('## Response Object ##') 292 | print(json.dumps(response, indent=4)) 293 | 294 | print('') 295 | print('## Language ##') 296 | print('language: ', response['language']) 297 | print('iso-639-1: ', response['iso-639-1']) 298 | print('native speakers: ', response['native-speakers']) 299 | print('') 300 | else: 301 | print('Error in language detection call: ', response['statusInfo']) 302 | 303 | 304 | print('') 305 | print('') 306 | print('') 307 | print('############################################') 308 | print('# Title Extraction Example #') 309 | print('############################################') 310 | print('') 311 | print('') 312 | 313 | print('Processing url: ', demo_url) 314 | print('') 315 | 316 | response = alchemyapi.title('url', demo_url) 317 | 318 | if response['status'] == 'OK': 319 | print('## Response Object ##') 320 | print(json.dumps(response, indent=4)) 321 | 322 | print('') 323 | print('## Title ##') 324 | print('title: ', response['title'].encode('utf-8')) 325 | print('') 326 | else: 327 | print('Error in title extraction call: ', response['statusInfo']) 328 | 329 | 330 | print('') 331 | print('') 332 | print('') 333 | print('############################################') 334 | print('# Relation Extraction Example #') 335 | print('############################################') 336 | print('') 337 | print('') 338 | 339 | print('Processing text: ', demo_text) 340 | print('') 341 | 342 | response = alchemyapi.relations('text', demo_text) 343 | 344 | if response['status'] == 'OK': 345 | print('## Object ##') 346 | print(json.dumps(response, indent=4)) 347 | 348 | print('') 349 | print('## Relations ##') 350 | for relation in response['relations']: 351 | if 'subject' in relation: 352 | print('Subject: ', relation['subject']['text'].encode('utf-8')) 353 | 354 | if 'action' in relation: 355 | print('Action: ', relation['action']['text'].encode('utf-8')) 356 | 357 | if 'object' in relation: 358 | print('Object: ', relation['object']['text'].encode('utf-8')) 359 | 360 | print('') 361 | else: 362 | print('Error in relation extaction call: ', response['statusInfo']) 363 | 364 | 365 | print('') 366 | print('') 367 | print('') 368 | print('############################################') 369 | print('# Text Categorization Example #') 370 | print('############################################') 371 | print('') 372 | print('') 373 | 374 | print('Processing text: ', demo_text) 375 | print('') 376 | 377 | response = alchemyapi.category('text', demo_text) 378 | 379 | if response['status'] == 'OK': 380 | print('## Response Object ##') 381 | print(json.dumps(response, indent=4)) 382 | 383 | print('') 384 | print('## Category ##') 385 | print('text: ', response['category']) 386 | print('score: ', response['score']) 387 | print('') 388 | else: 389 | print('Error in text categorization call: ', response['statusInfo']) 390 | 391 | 392 | print('') 393 | print('') 394 | print('') 395 | print('############################################') 396 | print('# Feed Detection Example #') 397 | print('############################################') 398 | print('') 399 | print('') 400 | 401 | print('Processing url: ', demo_url) 402 | print('') 403 | 404 | response = alchemyapi.feeds('url', demo_url) 405 | 406 | if response['status'] == 'OK': 407 | print('## Response Object ##') 408 | print(json.dumps(response, indent=4)) 409 | 410 | print('') 411 | print('## Feeds ##') 412 | for feed in response['feeds']: 413 | print('feed: ', feed['feed']) 414 | else: 415 | print('Error in feed detection call: ', response['statusInfo']) 416 | 417 | print('') 418 | print('') 419 | 420 | 421 | print('') 422 | print('') 423 | print('') 424 | print('############################################') 425 | print('# Microformats Parsing Example #') 426 | print('############################################') 427 | print('') 428 | print('') 429 | 430 | print('Processing url: ', demo_url) 431 | print('') 432 | 433 | response = alchemyapi.microformats('url', demo_url) 434 | 435 | if response['status'] == 'OK': 436 | print('## Response Object ##') 437 | print(json.dumps(response, indent=4)) 438 | 439 | print('') 440 | print('## Microformats ##') 441 | for microformat in response['microformats']: 442 | print('Field: ', microformat['field'].encode('utf-8')) 443 | print('Data: ', microformat['data']) 444 | print('') 445 | 446 | else: 447 | print('Error in microformats parsing call: ', response['statusInfo']) 448 | 449 | print('') 450 | print('') 451 | 452 | 453 | print('') 454 | print('') 455 | print('') 456 | print('############################################') 457 | print('# Image Extraction Example #') 458 | print('############################################') 459 | print('') 460 | print('') 461 | 462 | print('Processing url: ', demo_url) 463 | print('') 464 | 465 | response = alchemyapi.imageExtraction('url', demo_url) 466 | 467 | if response['status'] == 'OK': 468 | print('## Response Object ##') 469 | print(json.dumps(response, indent=4)) 470 | 471 | print('') 472 | print('## Image ##') 473 | print('Image: ', response['image']) 474 | print('') 475 | 476 | else: 477 | print('Error in image extraction call: ', response['statusInfo']) 478 | 479 | print('') 480 | print('') 481 | 482 | 483 | print('') 484 | print('') 485 | print('') 486 | print('############################################') 487 | print('# Image tagging Example #') 488 | print('############################################') 489 | print('') 490 | print('') 491 | 492 | print('Processing url: ', image_url) 493 | print('') 494 | 495 | response = alchemyapi.imageTagging('url', image_url) 496 | 497 | if response['status'] == 'OK': 498 | print('## Response Object ##') 499 | print(json.dumps(response, indent=4)) 500 | 501 | print('') 502 | print('## Keywords ##') 503 | for keyword in response['imageKeywords']: 504 | print(keyword['text'], ' : ', keyword['score']) 505 | print('') 506 | else: 507 | print('Error in image tagging call: ', response['statusInfo']) 508 | 509 | print('') 510 | print('') 511 | 512 | 513 | print('') 514 | print('') 515 | print('') 516 | print('############################################') 517 | print('# Taxonomy Example #') 518 | print('############################################') 519 | print('') 520 | print('') 521 | 522 | print('Processing text: ', demo_text) 523 | print('') 524 | 525 | response = alchemyapi.taxonomy('text', demo_text) 526 | 527 | if response['status'] == 'OK': 528 | print('## Response Object ##') 529 | print(json.dumps(response, indent=4)) 530 | 531 | print('') 532 | print('## Categories ##') 533 | for category in response['taxonomy']: 534 | print(category['label'], ' : ', category['score']) 535 | print('') 536 | 537 | else: 538 | print('Error in taxonomy call: ', response['statusInfo']) 539 | 540 | print('') 541 | print('') 542 | 543 | 544 | print('') 545 | print('') 546 | print('') 547 | print('############################################') 548 | print('# Combined Example #') 549 | print('############################################') 550 | print('') 551 | print('') 552 | 553 | print('Processing text: ', demo_text) 554 | print('') 555 | 556 | response = alchemyapi.combined('text', demo_text) 557 | 558 | if response['status'] == 'OK': 559 | print('## Response Object ##') 560 | print(json.dumps(response, indent=4)) 561 | 562 | print('') 563 | 564 | print('## Keywords ##') 565 | for keyword in response['keywords']: 566 | print(keyword['text'], ' : ', keyword['relevance']) 567 | print('') 568 | 569 | print('## Concepts ##') 570 | for concept in response['concepts']: 571 | print(concept['text'], ' : ', concept['relevance']) 572 | print('') 573 | 574 | print('## Entities ##') 575 | for entity in response['entities']: 576 | print(entity['type'], ' : ', entity['text'], ', ', entity['relevance']) 577 | print(' ') 578 | 579 | else: 580 | print('Error in combined call: ', response['statusInfo']) 581 | 582 | print('') 583 | print('') 584 | -------------------------------------------------------------------------------- /pigeon.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlchemyAPI/alchemyapi_python/f63716a1b08a67361f40a904f1514f97ace44ca6/pigeon.jpg -------------------------------------------------------------------------------- /tests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright 2013 AlchemyAPI 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | 18 | from __future__ import print_function 19 | from alchemyapi import AlchemyAPI 20 | 21 | 22 | test_text = 'Bob broke my heart, and then made up this silly sentence to test the PHP SDK' 23 | test_html = 'The best SDK Test | AlchemyAPI

Hello World!

My favorite language is PHP

' 24 | test_url = 'http://www.nytimes.com/2013/07/13/us/politics/a-day-of-friction-notable-even-for-a-fractious-congress.html?_r=0' 25 | test_jpg = 'pigeon.jpg' 26 | 27 | 28 | alchemyapi = AlchemyAPI() 29 | 30 | 31 | # Entities 32 | print('Checking entities . . . ') 33 | response = alchemyapi.entities('text', test_text) 34 | assert(response['status'] == 'OK') 35 | response = alchemyapi.entities('html', test_html) 36 | assert(response['status'] == 'OK') 37 | response = alchemyapi.entities('url', test_url) 38 | assert(response['status'] == 'OK') 39 | response = alchemyapi.entities('random', test_url) 40 | assert(response['status'] == 'ERROR') # invalid flavor 41 | print('Entity tests complete!') 42 | print('') 43 | 44 | 45 | # Keywords 46 | print('Checking keywords . . . ') 47 | response = alchemyapi.keywords('text', test_text) 48 | assert(response['status'] == 'OK') 49 | response = alchemyapi.keywords('html', test_html) 50 | assert(response['status'] == 'OK') 51 | response = alchemyapi.keywords('url', test_url) 52 | assert(response['status'] == 'OK') 53 | response = alchemyapi.keywords('random', test_url) 54 | assert(response['status'] == 'ERROR') # invalid flavor 55 | print('Keyword tests complete!') 56 | print('') 57 | 58 | 59 | # Concepts 60 | print('Checking concepts . . . ') 61 | response = alchemyapi.concepts('text', test_text) 62 | assert(response['status'] == 'OK') 63 | response = alchemyapi.concepts('html', test_html) 64 | assert(response['status'] == 'OK') 65 | response = alchemyapi.concepts('url', test_url) 66 | assert(response['status'] == 'OK') 67 | response = alchemyapi.concepts('random', test_url) 68 | assert(response['status'] == 'ERROR') # invalid flavor 69 | print('Concept tests complete!') 70 | print('') 71 | 72 | 73 | # Sentiment 74 | print('Checking sentiment . . . ') 75 | response = alchemyapi.sentiment('text', test_text) 76 | assert(response['status'] == 'OK') 77 | response = alchemyapi.sentiment('html', test_html) 78 | assert(response['status'] == 'OK') 79 | response = alchemyapi.sentiment('url', test_url) 80 | assert(response['status'] == 'OK') 81 | response = alchemyapi.sentiment('random', test_url) 82 | assert(response['status'] == 'ERROR') # invalid flavor 83 | print('Sentiment tests complete!') 84 | print('') 85 | 86 | 87 | # Targeted Sentiment 88 | print('Checking targeted sentiment . . . ') 89 | response = alchemyapi.sentiment_targeted('text', test_text, 'heart') 90 | assert(response['status'] == 'OK') 91 | response = alchemyapi.sentiment_targeted('html', test_html, 'language') 92 | assert(response['status'] == 'OK') 93 | response = alchemyapi.sentiment_targeted('url', test_url, 'Congress') 94 | assert(response['status'] == 'OK') 95 | response = alchemyapi.sentiment_targeted('random', test_url, 'Congress') 96 | assert(response['status'] == 'ERROR') # invalid flavor 97 | response = alchemyapi.sentiment_targeted('text', test_text, None) 98 | assert(response['status'] == 'ERROR') # missing target 99 | print('Targeted sentiment tests complete!') 100 | print('') 101 | 102 | 103 | # Text 104 | print('Checking text . . . ') 105 | response = alchemyapi.text('text', test_text) 106 | assert(response['status'] == 'ERROR') # only works for html and url content 107 | response = alchemyapi.text('html', test_html) 108 | assert(response['status'] == 'OK') 109 | response = alchemyapi.text('url', test_url) 110 | assert(response['status'] == 'OK') 111 | print('Text tests complete!') 112 | print('') 113 | 114 | 115 | # Text Raw 116 | print('Checking raw text . . . ') 117 | response = alchemyapi.text_raw('text', test_text) 118 | assert(response['status'] == 'ERROR') # only works for html and url content 119 | response = alchemyapi.text_raw('html', test_html) 120 | assert(response['status'] == 'OK') 121 | response = alchemyapi.text_raw('url', test_url) 122 | assert(response['status'] == 'OK') 123 | print('Raw text tests complete!') 124 | print('') 125 | 126 | 127 | # Author 128 | print('Checking author . . . ') 129 | response = alchemyapi.author('text', test_text) 130 | assert(response['status'] == 'ERROR') # only works for html and url content 131 | response = alchemyapi.author('html', test_html) 132 | assert(response['status'] == 'ERROR') # there's no author in the test HTML 133 | response = alchemyapi.author('url', test_url) 134 | assert(response['status'] == 'OK') 135 | print('Author tests complete!') 136 | print('') 137 | 138 | 139 | # Language 140 | print('Checking language . . . ') 141 | response = alchemyapi.language('text', test_text) 142 | assert(response['status'] == 'OK') 143 | response = alchemyapi.language('html', test_html) 144 | assert(response['status'] == 'OK') 145 | response = alchemyapi.language('url', test_url) 146 | assert(response['status'] == 'OK') 147 | response = alchemyapi.language('random', test_url) 148 | assert(response['status'] == 'ERROR') # invalid flavor 149 | print('Language tests complete!') 150 | print('') 151 | 152 | 153 | # Title 154 | print('Checking title . . . ') 155 | response = alchemyapi.title('text', test_text) 156 | assert(response['status'] == 'ERROR') # only works for html and url content 157 | response = alchemyapi.title('html', test_html) 158 | assert(response['status'] == 'OK') 159 | response = alchemyapi.title('url', test_url) 160 | assert(response['status'] == 'OK') 161 | print('Title tests complete!') 162 | print('') 163 | 164 | 165 | # Relations 166 | print('Checking relations . . . ') 167 | response = alchemyapi.relations('text', test_text) 168 | assert(response['status'] == 'OK') 169 | response = alchemyapi.relations('html', test_html) 170 | assert(response['status'] == 'OK') 171 | response = alchemyapi.relations('url', test_url) 172 | assert(response['status'] == 'OK') 173 | response = alchemyapi.relations('random', test_url) 174 | assert(response['status'] == 'ERROR') # invalid flavor 175 | print('Relation tests complete!') 176 | print('') 177 | 178 | 179 | # Category 180 | print('Checking category . . . ') 181 | response = alchemyapi.category('text', test_text) 182 | assert(response['status'] == 'OK') 183 | response = alchemyapi.category('html', test_html, {'url': 'test'}) 184 | assert(response['status'] == 'OK') 185 | response = alchemyapi.category('url', test_url) 186 | assert(response['status'] == 'OK') 187 | response = alchemyapi.category('random', test_url) 188 | assert(response['status'] == 'ERROR') # invalid flavor 189 | print('Category tests complete!') 190 | print('') 191 | 192 | 193 | # Feeds 194 | print('Checking feeds . . . ') 195 | response = alchemyapi.feeds('text', test_text) 196 | assert(response['status'] == 'ERROR') # only works for html and url content 197 | response = alchemyapi.feeds('html', test_html, {'url': 'test'}) 198 | assert(response['status'] == 'OK') 199 | response = alchemyapi.feeds('url', test_url) 200 | assert(response['status'] == 'OK') 201 | print('Feed tests complete!') 202 | print('') 203 | 204 | 205 | # Microformats 206 | print('Checking microformats . . . ') 207 | response = alchemyapi.microformats('text', test_text) 208 | assert(response['status'] == 'ERROR') # only works for html and url content 209 | response = alchemyapi.microformats('html', test_html, {'url': 'test'}) 210 | assert(response['status'] == 'OK') 211 | response = alchemyapi.microformats('url', test_url) 212 | assert(response['status'] == 'OK') 213 | print('Microformat tests complete!') 214 | print('') 215 | print('') 216 | 217 | # imagetagging 218 | print('Checking imagetagging . . . ') 219 | response = alchemyapi.imageTagging('text', test_text) 220 | assert(response['status'] == 'ERROR') 221 | response = alchemyapi.imageTagging('html', test_html) 222 | assert(response['status'] == 'ERROR') 223 | response = alchemyapi.imageTagging('url', test_url) 224 | assert(response['status'] == 'OK') 225 | response = alchemyapi.imageTagging('image', test_jpg) 226 | assert(response['status'] == 'OK') 227 | print('Image tagging tests complete!') 228 | print('') 229 | print('') 230 | 231 | # combined 232 | print('Checking combined . . . ') 233 | response = alchemyapi.combined('text', test_text) 234 | assert(response['status'] == 'OK') 235 | response = alchemyapi.combined('html', test_html) 236 | assert(response['status'] == 'ERROR') 237 | response = alchemyapi.combined('url', test_url) 238 | assert(response['status'] == 'OK') 239 | print('Combined tests complete!') 240 | print('') 241 | print('') 242 | 243 | # taxonomy 244 | print('Checking taxonomy . . . ') 245 | response = alchemyapi.taxonomy('text', test_text) 246 | assert(response['status'] == 'OK') 247 | response = alchemyapi.taxonomy('html', test_html, {'url': 'test'}) 248 | assert(response['status'] == 'OK') 249 | response = alchemyapi.taxonomy('url', test_url) 250 | assert(response['status'] == 'OK') 251 | print('Taxonomy tests complete!') 252 | print('') 253 | print('') 254 | 255 | # image 256 | print('Checking image extraction . . . ') 257 | response = alchemyapi.imageExtraction('text', test_text) 258 | assert(response['status'] == 'ERROR') 259 | response = alchemyapi.imageExtraction('html', test_html) 260 | assert(response['status'] == 'ERROR') 261 | response = alchemyapi.imageExtraction('url', test_url) 262 | assert(response['status'] == 'OK') 263 | print('Image Extraction tests complete!') 264 | print('') 265 | print('') 266 | 267 | 268 | print('**** All tests complete! ****') 269 | --------------------------------------------------------------------------------