various methods to parse pages from thingiverse
[skdb.git] / octopart.py
blob149aae6b9489ae3664e8c4fa95255b82e6cd70c0
1 #!/usr/bin/python
2 #author: Bryan Bishop <kanzure@gmail.com>
3 #date: 2010-01-13
4 #license: GPL2+
5 #purpose: an attempt at implementing the octopart api v2
6 #url: http://octopart.com/api/documentation
7 #skdb api key: 476188c7
8 import optfunc
9 import simplejson
10 import unittest
11 import pycurl
12 from urllib import urlencode
13 from StringIO import StringIO
15 octopart_api_key = "476188c7"
16 bryan_message = "bryan hasn't got this far yet"
18 class Octopart:
19 '''a wrapper to Octopart.com'''
20 timeout = 15 #dunno what to put here (seconds)
21 base_url = "http://octopart.com/api/v2/"
22 filters = "case_package, category_id, color, conductor_material, contact_material, contacts_type, dielectric_material, flammability_rating, gender, glow_wire_compliant, halogen_free_status, housing_color, housing_material, insulation_material, jacket_material, lead_free_status, lens_color, lens_type, lifecycle_status, logic_type, manufacturer, material, mounting_type, orientation, packaging, polarity, processor_type, rohs, shielding, shrouded, supplier, termination_style, thermal_shutdown"
23 ranged_filters = "access_time, avg_authavail, avg_authprice, avg_avail, avg_price, breakdown_voltage, cable_length, capacitance, carry_current, character_size_height, clock_speed, coil_resistance, contact_resistance, cord_length, current_rating, data_rate, dropout_voltage, equivalent_series_resistance_esr, forward_voltage, frequency, gain, inductance, input_bias_current, input_current, input_power, input_voltage_dc, load_capacitance, luminous_intensity, mated_height, number_of_channels, number_of_circuits, number_of_conductors, number_of_detents, number_of_gates, number_of_i_o_pins, number_of_outlets, number_of_outputs, number_of_pins, number_of_positions, number_of_rows, operating_temperature, output_current, output_power, output_voltage, peak_wavelength, pin_pitch, power_consumption, power_rating, q_factor, quiescent_current, resistance, resistance_tolerance, sample_rate, size_diameter, size_height, size_inner_diameter, size_length, size_thickness, size_width, slew_rate, supply_voltage_dc, switching_current, switching_frequency, switching_voltage, temperature_coefficient, threshold_voltage, voltage_rating_ac, voltage_rating_dc, voltage_rating_transient, wavelength, weight"
24 def __init__(self, api_key=None):
25 self.api_key = api_key
26 def web_fetch(self, url):
27 buffer = StringIO()
28 curl = pycurl.Curl()
29 curl.setopt(curl.URL, url)
30 curl.setopt(curl.TIMEOUT, self.timeout)
31 curl.setopt(curl.WRITEFUNCTION, buffer.write)
32 curl.perform()
33 curl.close()
34 response = buffer.getvalue().strip()
35 return response
36 def get_categories(self, id=4179, attach_ancestors=0):
37 if isinstance(id, list):
38 specific_url = "categories/get_multi"
39 #url: http://octopart.com/api/v2/categories/get_multi?ids=[5432,692,2344]
40 id_variable = "ids"
41 else: #it's just a single number
42 specific_url = "categories/get"
43 #url: http://octopart.com/api/v2/categories/get?id=533642
44 id_variable = "id"
46 id = str(id)
47 attach_ancestors = str(attach_ancestors)
49 url = self.base_url + specific_url + "?" + id_variable + "=" + id + "&attach_ancestors=" + attach_ancestors + "&apikey=" + self.api_key
50 response_json = self.web_fetch(url)
52 #results
53 #The response is a list of category objects that match the ids requested.
54 #If a match is not found for a given id, the response will not include that object.
55 #In other words, if no categories are found the reponse will be an empty list.
56 #raise NotImplementedError, bryan_message
58 return simplejson.loads(response_json)
59 def get_whitepapers(self, id):
60 '''returns a whitepaper object
61 id: the whitepaper object id'''
62 if isinstance(id, list):
63 specific_url = "whitepapers/get_multi"
64 #url: http://octopart.com/api/v2/whitepapers/get_multi
65 id_variable = "ids"
66 else:
67 specific_url = "whitepapers/get"
68 #url: http://octopart.com/api/v2/whitepapers/get
69 id_variable = "id"
71 id = str(id)
72 url = self.base_url + specific_url + "?" + id_variable + "=" + id
73 response_json = self.web_fetch(url)
75 #results
76 #a whitepaper object
77 #url: http://octopart.com/api/documentation#whitepaper
79 return simplejson.loads(response_json)
80 def search_categories(self, query="", start=0, limit=10, ancestor_id=None, attach_ancestors=0):
81 '''query: query string (optional)
82 start: ordinal position of the first result (default is 0)
83 limit: maximum number of results to return (default is 10)
84 ancestor_id: if specified, limit search to all descendants of the specified ancestor (optional)
85 attach_ancestors: if specified, attach ancestors to category objects (optional)'''
86 specific_url = "categories/search"
88 if not ancestor_id: ancestor_id = ""
89 if not attach_ancestors: anttach_ancestors = ""
90 start = str(start)
91 limit = str(limit)
92 ancestor_id = str(ancestor_id)
93 attach_ancestors = str(attach_ancestors)
95 url = self.base_url + specific_url + "?" + "q=" + query + "&start=" + start + "&limit=" + limit + "&ancestor_id=" + ancestor_id + "&attach_ancestors=" + attach_ancestors + "&apikey=" + self.api_key
96 response_json = self.web_fetch(url)
98 #results
99 # * results[]{} - The sorted list of matched items
100 # o item{} - A matched category object
101 # o highlight - A short snippet of text highlighting matched keywords
102 # * request{} - The request parameters (from the arguments above)
103 # o q
104 # o start
105 # o limit
106 # o ancestor_id
107 # * hits - The total number of matched objects
108 # * time - The amount of time it took to process the entire request (in seconds)
109 return simplejson.loads(response_json)
110 def search_parts(self, query="", start=0, limit=10, filters=None, ranged_filters=None, sort_by=None):
111 '''query: query string (optional)
112 start: ordinal position of the first result (default is 0, max is 1000)
113 limit: number of results to return (default is 10, maximum is 100)
114 filter: JSON encoded list of (fieldname, values) pairs (optional)
115 example: filters=[["color",["Red"]], ["material",["Tantalum","Ceramic"]]]
116 ranged_filters: JSON encoded list of (fieldname, min/max values) pairs, using null as wildcard. (optional)
117 example: ranged_filters=[["resistance",[[100,1000],[2000,null]]]]
118 sort_by: JSON encoded list of (fieldname,sort-order) pairs, default is [["score","desc"]] (optional)
119 example: sort_by=[["resistance","desc"],["avg_price","asc"]]'''
120 specific_url = "parts/search"
122 #some preliminary checks
123 if start < 0: raise ValueError, "Octopart.search_parts: start must be greater than 0"
124 if start > 1000: raise ValueError, "Octopart.search_parts: start must be less than or equal to 1000"
125 if limit <= 0: limit = 100 #set it to the maximum
126 if limit > 100: raise ValueError, "Octopart.search_parts: limit must be between 0 and 100 (inclusive)"
127 if not query: query = ""
128 if not filters: filters = ""
129 if not ranged_filters: ranged_filters = ""
130 if not sort_by: sort_by = ""
132 start = str(start)
133 limit = str(limit)
135 url = self.base_url + specific_url + "?" + "q=" + query + "&start=" + start + "&apikey=" + self.api_key
136 #do not include filters and rangedfilters if they aren't available
137 if ranged_filters != "": url = url + "&rangedfilters=" + ranged_filters
138 if filters != "": url = url + "&filters=" + filters
139 if sort_by != "": url = url + "&sortby=" + sort_by
141 response_json = self.web_fetch(url)
142 response = simplejson.loads(response_json)
144 #results
145 # * results[]{} - The sorted list of matched items
146 # o item{} - A matched part object
147 # o highlight - A short snippet of text highlighting matched keywords
148 # * request{} - The request parameters (from the arguments above)
149 # o q
150 # o start
151 # o limit
152 # o filters
153 # o rangedfilters
154 # o sortby
155 # * hits - The total number of matched objects
156 # * time - The amount of time it took to process the entire request (in seconds)
157 hits = response["hits"]
158 time = response["time"] #in seconds
160 for part in response["results"]:
161 part = part["item"]
162 specs = {}
163 for attribute in part["specs"]:
164 specs[attribute["attribute"]["fieldname"]] = attribute["values"]
165 print "part id: ", part["id"]
167 for spec in specs:
168 print "\t" + spec + "\t" + str(specs[spec])
170 return response
171 def search_whitepapers(self, query="", start=0, limit=10):
172 '''execute a search over all whitepapers
173 query: query string (optional)
174 start: ordinal position of the first result where the first position is 0 (default is 0, max is 1000) (optional)
175 limit: maximum number of results to return (default is 10, max is 100) (optional)
177 specific_url = "whitepapers/search"
179 #some preliminary checks
180 if start<0: raise ValueError, "Octopart.search_whitepapers: start must be greater than or equal to 0"
181 if start>1000: raise ValueError, "Octopart.search_whitepapers: start must be less than or equal to 1000"
182 start = str(start)
183 limit = str(limit)
184 url = self.base_url + specific_url + "?q=" + query + "&start=" + start + "&limit=" + limit + "&apikey=" + self.api_key
185 response_json = self.web_fetch(url)
187 #results
188 # * results[]{} - The sorted list of matched items
189 # o item{} - A matched whitepaper object
190 # o highlight - A short snippet of text highlighting matched keywords
191 # * request{} - The request parameters (from the arguments above)
192 # o q
193 # o start
194 # o limit
195 # * hits - The total number of matched objects
196 # * time - The amount of time it took to process the entire request (in seconds)
197 return simplejson.loads(response_json)
198 def suggest_part_query(self, query, limit=1):
199 '''suggest a part search query string, optimized for speed and useful for auto-complete features
200 query: query string with minimum length of 2 characters (required)
201 limit: maximum number of results to return (default is 10, max is 10)
203 specific_url = "parts/suggest"
205 #some preliminary checks
206 if len(query)<2: raise ValueError, "Octopart.suggest_part_query: length of query string must be at least 2 characters"
207 if limit>10 or limit<1: raise ValueError, "Octopart.suggest_part_query: limit must be between 1 and 10"
208 limit = str(limit)
210 url = self.base_url + specific_url + "?q=" + query + "&limit=" + limit + "&apikey=" + self.api_key
211 response_json = self.web_fetch(url)
213 #results
214 # * results[] - The sorted list of search suggestions
215 # * request{} - The request parameters (from the arguments above)
216 # o q
217 # o limit
218 # * hits - The total number of matched suggestions
219 # * time - The amount of time it took to process the entire request (in seconds)
220 return simplejson.loads(response_json)
222 def octopart_search(query):
223 '''searches octopart with the string'''
224 octopart = Octopart(octopart_api_key)
225 #categories = octopart.get_categories(id=4179)
226 #print "categories: %s" % (categories)
227 parts = octopart.search_parts(query=query, limit=1)
228 #print "parts: %s" % (parts)
229 print parts.keys()
231 class OctopartTests(unittest.TestCase):
232 def test_octopart_get_category(self):
233 octopart = Octopart(octopart_api_key)
234 categories = octopart.get_category(id=4179)
235 pass
237 if __name__ == "__main__":
238 optfunc.run(octopart_search)