def _do_upload(self, file_obj, url, filename, content_type): if filename: encoder = rtb.MultipartEncoder({"file": (filename, file_obj)}) else: encoder = rtb.MultipartEncoder({"file": file_obj}) headers = {} if self.set_content_type: headers["Content-Type"] = content_type or encoder.content_type res = self._session.put(url, data=encoder, headers=headers) res.raise_for_status()
def api_upload(service, encData, encMeta, keys): ''' Uploads data to Send. Caution! Data is uploaded as given, this function will not encrypt it for you ''' service += 'api/upload' files = requests_toolbelt.MultipartEncoder( fields={'file': ('blob', encData, 'application/octet-stream')}) pbar = progbar(files.len) monitor = requests_toolbelt.MultipartEncoderMonitor( files, lambda files: pbar.update(monitor.bytes_read - pbar.n)) headers = { 'X-File-Metadata': unpadded_urlsafe_b64encode(encMeta), 'Authorization': 'send-v1 ' + unpadded_urlsafe_b64encode(keys.authKey), 'Content-type': monitor.content_type } r = requests.post(service, data=monitor, headers=headers, stream=True) r.raise_for_status() pbar.close() body_json = r.json() secretUrl = body_json['url'] + '#' + unpadded_urlsafe_b64encode( keys.secretKey) fileId = body_json['id'] fileNonce = unpadded_urlsafe_b64decode( r.headers['WWW-Authenticate'].replace('send-v1 ', '')) delete_token = body_json['delete'] return secretUrl, fileId, fileNonce, delete_token
def _import_file(self, filename): if not self.api_key: key = self.device.keygen() else: key = self.api_key params = {'type': 'import', 'category': 'configuration', 'key': key} path = os.path.basename(filename) mef = requests_toolbelt.MultipartEncoder(fields={ 'file': (path, open(filename, 'rb'), 'application/octet-stream') }) requests.packages.urllib3.disable_warnings(InsecureRequestWarning) url = 'https://{0}/api/'.format(self.hostname) request = requests.post(url, verify=False, params=params, headers={'Content-Type': mef.content_type}, data=mef) # if something goes wrong just raise an exception request.raise_for_status() response = xml.etree.ElementTree.fromstring(request.content) if response.attrib['status'] == 'error': return False else: return path
def multipart_encoder(data, boundary=BOUNDARY): data = dict((k, str(v)) for k, v in data.items()) data = requests_toolbelt.MultipartEncoder(boundary=boundary, fields=data) headers = {"content-type": data.content_type} data = data.to_string().decode() return headers, data
def upload_child_file(self, name, local_path, existing_node=None): logging.info("Uploading %s to %s", local_path, self.node["name"]) mime_type = _get_mimetype(name) m = requests_toolbelt.MultipartEncoder([ ( "metadata", json.dumps({ "name": name, # Здесь можно задать имя файлу, которое будет у него в облаке "kind": "FILE", "parents": [self.node["id"]] })), ("content", (name, open(local_path, "rb"), mime_type)) ]) if existing_node: """ # TODO: this is under-documented and currently 500s on Amazon's side node = CloudNode(DriveSink.instance().request_content( "%%snodes/%s/content" % existing_node.node["id"], method="put", data=m, headers={"Content-Type": m.content_type})) """ old_info = DriveSink.instance().request_metadata( "%%s/trash/%s" % existing_node.node["id"], method="put") node = CloudNode(DriveSink.instance().request_content( "%snodes", method="post", data=m, headers={"Content-Type": m.content_type})) self._children[name] = node
def post(self, url, content='', files=None, params=None, extra_headers={}, upload_callback=None): 'HTTP Post files[] or content (unicode string) to url' if not url.startswith('http'): # relative url url = self.rootpath + url log.debug('posting content (len %s) to url %s', len(content) if content is not None else '?', url) headers = self.session.headers.copy() headers.update(**extra_headers) if not files is None: m = requests_toolbelt.MultipartEncoder(fields=files) if upload_callback is not None: m_len = m.len # compute value for callback closure def callback(monitor): upload_callback(monitor, m_len) m = requests_toolbelt.MultipartEncoderMonitor(m, callback) headers['content-type'] = m.content_type else: m = content url = self.escapeUrl(url) r = self.session.post(url, data=m, params=params, headers=headers) if not r.ok: log.warning('HTTP POST failed: %s', r.text) raise JFSError(r.reason) return self.getObject(r) # return a JFS* class
def upload(args, upload_url, file_info): ''' The long-running upload request. This runs in a separate process for concurrency reasons. ''' with open(file_info[0], 'rb') as image_file: files = [ ('file', (file_info[1], image_file, 'application/x-tar')), ] transloadit_auth_info = { 'auth': { 'key': args.transloadit_account_id, }, 'template_id': args.transloadit_template, } params = json.dumps(transloadit_auth_info) logging.debug('About to start the upload.') m = requests_toolbelt.MultipartEncoder({ 'params': params, 'file': files[0][1], }) response = requests.post(upload_url, data=m, headers={'Content-Type': m.content_type}) logging.debug('Upload complete... code: %s %s', response.status_code, response.text)
def import_file(self, filename: str, file_contents: (str, bytes), category: str) -> bool: """ Import the given file into this device :param filename: :param file_contents: :param category: 'configuration' :return: bool True on success """ params = {'type': 'import', 'category': category, 'key': self.key} mef = requests_toolbelt.MultipartEncoder(fields={ 'file': (filename, file_contents, 'application/octet-stream') }) r = requests.post(f'https://{self.hostname}:{self.port}/api/', verify=False, params=params, headers={'Content-Type': mef.content_type}, data=mef) # if something goes wrong just raise an exception r.raise_for_status() resp = ElementTree.fromstring(r.content) if resp.attrib['status'] == 'error': raise SkilletLoaderException(r.content) return True
def import_file(xapi, module, ip_address, file_, category): xapi.keygen() params = {'type': 'import', 'category': category, 'key': xapi.api_key} filename = os.path.basename(file_) mef = requests_toolbelt.MultipartEncoder(fields={ 'file': (filename, open(file_, 'rb'), 'application/octet-stream') }) r = requests.post('https://' + ip_address + '/api/', verify=module.params['validate_certs'], params=params, headers={'Content-Type': mef.content_type}, data=mef) # if something goes wrong just raise an exception r.raise_for_status() resp = xml.etree.ElementTree.fromstring(r.content) if resp.attrib['status'] == 'error': module.fail_json(msg=r.content) return True, filename
def post_file(url, path): if requests_toolbelt is None: raise ImportError(REQUESTS_TOOLBELT_UNAVAILABLE_MESSAGE) __ensure_requests() m = requests_toolbelt.MultipartEncoder( fields={'file': ('filename', open(path, 'rb'))}) requests.post(url, data=m, headers={'Content-Type': m.content_type})
def _send_mmp_stream(self, method, rest_path_list, fields, **kwargs): url = self._prep_url(rest_path_list) kwargs = self._prep_request_kwargs(kwargs) mmp_stream = requests_toolbelt.MultipartEncoder(fields=fields) kwargs['data'] = mmp_stream kwargs['headers'].update({ 'Content-Type': mmp_stream.content_type, 'Content-Length': str(mmp_stream.len), }) return self._session.request(method, url, **kwargs)
def upload_blob(self, fd): url = self.servers['upload'] m = requests_toolbelt.MultipartEncoder( fields={'file': ('filename', fd)}) response = self.session.post(url, params={'cloud_domain': '2'}, data=m, headers={'Content-Type': m.content_type}) assert response.status_code == 200, response.status_code result = response.text.split(';') assert len(result) == 2, result return {'hash': result[0], 'size': int(result[1])}
def _create_mmp_stream(self, large_sparse_stream, pid, sysmeta_pyxb): mmp_stream = requests_toolbelt.MultipartEncoder( fields={ "pid": pid.encode("utf-8"), "object": ("content.bin", large_sparse_stream), "sysmeta": ( "sysmeta.xml", d1_common.xml.serialize_to_xml_str(sysmeta_pyxb), ), } ) return mmp_stream
def attach_iso(self, iso): url = os.path.join(self.url, 'api', 'push-iso', '%s.iso' % self.name) # And now we wait. m = requests_toolbelt.MultipartEncoder(fields={ 'file': ('file', open(iso, 'rb'), ' application/iso-image'), }) requests.post(url, auth=self.auth, data=m, headers={'content-type': m.content_type}) return self._query('attach-iso', self.name, '%s.iso' % self.name)
def test_1000(self): """Parse and normalize multipart str.""" field_dict = { "bcd": "333", "abc": "111", "cde": "444", "efg": "555", "def": "222", } mmp_stream = requests_toolbelt.MultipartEncoder(fields=field_dict) body_part_tup = d1_common.multipart.parse_str(mmp_stream.read(), mmp_stream.content_type) body_str = d1_common.multipart.normalize(body_part_tup) self.sample.assert_equals(body_str, "parse_and_normalize")
def upload_file(self, file_path, folder_id=None, sha1=None, httponly=False): """Calls upload_link request to get valid url, then it makes a post request with given file to be uploaded. No need to call upload_link explicitly since upload_file calls it. Note: If folder_id is not provided, the file will be uploaded to ``Home`` folder. Args: file_path (str): full path of the file to be uploaded. folder_id (:obj:`str`, optional): folder-ID to upload to. sha1 (:obj:`str`, optional): expected sha1 If sha1 of uploaded file doesn't match this value, upload fails. httponly (:obj:`bool`, optional): If this is set to true, use only http upload links. Returns: dict: dictionary containing uploaded file info. :: { "content_type": "application/zip", "id": "0yiQTPzi4Y4", "name": 'favicons.zip', "sha1": 'f2cb05663563ec1b7e75dbcd5b96d523cb78d80c', "size": '24160', "url": 'https://openload.co/f/0yiQTPzi4Y4/favicons.zip' } """ upload_url_response_json = self.upload_link(folder_id=folder_id, sha1=sha1, httponly=httponly) upload_url = upload_url_response_json['url'] _, file_name = os.path.split(file_path) with open(file_path, 'rb') as f: data = requests_toolbelt.MultipartEncoder({ "files": (file_name, f, "application/octet-stream"), }) headers = {"Content-Type": data.content_type} response_json = requests.post(upload_url, data=data, headers=headers).json() self._check_status(response_json) return response_json['result']
def _send_mmp_stream(self, method, rest_path_list, fields, **kwargs): url = self._prep_url(rest_path_list) mmp_stream = requests_toolbelt.MultipartEncoder( fields=fields, boundary=(kwargs.get('headers', None) or {}).pop("mmp_boundary", self._mmp_boundary_str), ) kwargs = self._prep_request_kwargs(kwargs) kwargs["data"] = mmp_stream kwargs["headers"].update({ "Content-Type": mmp_stream.content_type, "Content-Length": str(mmp_stream.len), }) return self._session.request(method, url, **kwargs)
def register(self, package: package_file.PackageFile) -> requests.Response: data = package.metadata_dictionary() data.update({":action": "submit", "protocol_version": "1"}) print(f"Registering {package.basefilename}") data_to_send = self._convert_data_to_list_of_tuples(data) encoder = requests_toolbelt.MultipartEncoder(data_to_send) resp = self.session.post( self.url, data=encoder, allow_redirects=False, headers={"Content-Type": encoder.content_type}, ) # Bug 28. Try to silence a ResourceWarning by releasing the socket. resp.close() return resp
def upload(self, filename=None, url=None, progress=True): """Upload a local or remote file.""" if filename and url: raise ValueError('Ambiguous call, both filename and url provided') if not filename or url: raise ValueError( 'Missing keyword argument, either filename or url required') file_multipart = { 'file': (os.path.basename(filename), open(filename, 'rb'), 'application/octet-stream') } encoder = requests_toolbelt.MultipartEncoder(fields=file_multipart) print('Uploading ' + os.path.basename(filename)) if not progress: monitor = requests_toolbelt.MultipartEncoderMonitor( encoder, upload_callback_nobar) else: monitor = requests_toolbelt.MultipartEncoderMonitor( encoder, upload_callback) headers = { 'Authorization': 'Bearer ' + self.api.token, 'Origin': 'cloudrun.co', 'Content-Type': monitor.content_type } _url = API_URL + '/runs/' + self.id + '/input' r = requests.post(_url, headers=headers, data=monitor) if progress: sys.stdout.write('\n') sys.stdout.flush() if r.status_code == 200: self.get() else: raise ValueError('Server responded with ' + str(r.status_code))
def upload(dest, filename, userpass, tags=None): files = [] if tags: files.append( ('file_resource', (None, tags, "text/xml") ) ) files.append( ("file", (os.path.basename (filename), open(filename, "rb"), 'application/octet-stream') )) fields = dict (files) # Crazy way to speed up read speed. # https://github.com/requests/toolbelt/issues/75 m = requests_toolbelt.MultipartEncoder (fields = dict (files) ) m._read = m.read m.read = lambda size: m._read (1024*1024) response = requests.post (dest, data=m, auth = requests.auth.HTTPBasicAuth(*userpass),verify=False, headers={'Content-Type': m.content_type}) if response.status_code != 200: print "error while copying %s: Server response %s" % (filename, response.headers) print "saving error information to ", filename , "-transfer.err" open(filename + "-transfer.err",'wb').write(response.content) return return response.content
def login(self): #获取cookies cookies = self.session.get(originurl).cookies for cookie in cookies: if cookie.name == 'csrftoken': self.csrftoken = cookie.value break #提交的data params_data = { 'csrfmiddlewaretoken': self.csrftoken, 'login': username, 'password': password, 'next': 'problems' } #模拟浏览器 headers = { 'User-Agent': user_agent, 'Connection': 'keep-alive', 'Referer': loginurl, 'origin': originurl } #数据处理 m = requests_toolbelt.MultipartEncoder(params_data) headers['Content-Type'] = m.content_type #post请求 self.session.post(loginurl, headers=headers, data=m, timeout=10, allow_redirects=False) #print(self.session.cookies.get('LEETCODE_SESSION') is None) #返回登录成功标识 print('登录是否成功:' + self.session.cookies.get('LEETCODE_SESSION') is not None) return self.session.cookies.get('LEETCODE_SESSION') is not None
def _upload(self, package: package_file.PackageFile) -> requests.Response: data = package.metadata_dictionary() data.update( { # action ":action": "file_upload", "protocol_version": "1", } ) data_to_send = self._convert_data_to_list_of_tuples(data) print(f"Uploading {package.basefilename}") with open(package.filename, "rb") as fp: data_to_send.append( ("content", (package.basefilename, fp, "application/octet-stream")) ) encoder = requests_toolbelt.MultipartEncoder(data_to_send) with ProgressBar( total=encoder.len, unit="B", unit_scale=True, unit_divisor=1024, miniters=1, file=sys.stdout, disable=self.disable_progress_bar, ) as bar: monitor = requests_toolbelt.MultipartEncoderMonitor( encoder, lambda monitor: bar.update_to(monitor.bytes_read) ) resp = self.session.post( self.url, data=monitor, allow_redirects=False, headers={"Content-Type": monitor.content_type}, ) return resp
def __call__(self, *args, **kargs): if len(args): raise TypeError('Only keyword arguments are allowed') headers = dict() fields = dict() fields['api_key'] = self._api.key fields['api_secret'] = self._api.secret for (k, v) in kargs.items(): if isinstance(v, File): fields[k] = (v.get_filename(), v.get_content(), 'multipart/form-data') else: fields[k] = str(v) multipart = requests_toolbelt.MultipartEncoder(fields=fields) headers['Content-Type'] = multipart.content_type retry = self._api.max_retries while True: retry -= 1 try: ret = requests.post(self._urlbase, data=multipart, timeout=self._api.timeout, headers=headers).content break except urllib.error.HTTPError as e: raise APIError(e.code, self._urlbase, e.read()) except (socket.error, urllib.error.URLError) as e: if retry < 0: raise e _print_debug('caught error: {}; retrying'.format(e)) time.sleep(self._api.retry_delay) if self._api.decode_result: try: ret = json.loads(ret.decode("utf-8")) except Exception as e: raise APIError(-1, self._urlbase, 'json decode error, value={0!r}'.format(ret)) return ret
def post(self, url, content='', files=None, params=None, extra_headers={}, upload_callback=None): 'HTTP Post files[] or content (unicode string) to url' if not url.startswith('http'): # relative url url = self.rootpath + url # TODO: Re-enable cache after making it work with MultipartEncoder #logging.debug('yanking url from cache: %s', url) #cache = requests_cache.core.get_cache() #cache.delete_url(url) logging.debug('posting content (len %s) to url %s', content is not None and len(content) or '?', url) headers = self.session.headers.copy() headers.update(**extra_headers) if not files is None: m = requests_toolbelt.MultipartEncoder(fields=files) if upload_callback is not None: m_len = len(m) def callback(monitor): upload_callback(monitor, m_len) m = requests_toolbelt.MultipartEncoderMonitor(m, callback) headers['content-type'] = m.content_type else: m = content r = self.session.post(url, data=m, params=params, headers=headers) if r.status_code in (500, 404, 401, 403, 400): logging.warning('HTTP POST failed: %s', r.text) raise JFSError(r.reason) return self.getObject(r) # return a JFS* class
def ul(self, fpath: str, tpath: str = '') -> str: if not os.path.isabs(fpath): fpath = os.path.join(os.getcwd(), fpath) if not tpath: tpath = os.path.basename(fpath) if not os.path.isfile(fpath): return '' tpath = os.path.join(self.path, tpath) fname = list(os.path.splitext(tpath)) if self.__isfile(''.join(fname)): i = 1 while self.__isfile(fname[0]+'_'+str(i)+fname[1]): i += 1 fname[0] = fname[0]+'_'+str(i) pb = misc.ProgressBar(os.path.getsize(fpath), title='Uploading "{}"'.format(os.path.basename(fpath))) e = reqt.MultipartEncoder(fields=dict(file=(os.path.basename(''.join(fname)), open(fpath, 'rb'),))) def up(mon: reqt.MultipartEncoderMonitor) -> None: pb.update(mon.bytes_read) m = reqt.MultipartEncoderMonitor(e, up) res = self.sess.post(self.url()+'u/'+self.__benc(''.join(fname)), data=m, headers={'Content-Type': m.content_type,}) if res.status_code != 200: return '' return ''.join(fname)
def upload_file( self, file_name: str, file: BinaryIO, mime_type: Optional[str], text: Optional[str] = None, ignore_warnings: bool = True ) -> None: """Upload file.""" if self.csrf_token is None: self.csrf_token = self.get_token('csrf') params: Dict[str, Any] = { 'action': 'upload', 'filename': file_name, 'token': self.csrf_token, 'format': 'json', 'async': '1', # TODO 'file': (file_name, file, mime_type), } if ignore_warnings: params['ignorewarnings'] = '1' if text is not None: params['text'] = text encoder = requests_toolbelt.MultipartEncoder(fields=params) r = self.session.post( self.api_url, data=encoder, headers={ 'Content-Type': encoder.content_type, } ) if r.status_code != 200: raise MediaWikiAPIError('Status code is {}'.format(r.status_code)) data = r.json() if 'error' in data: raise MediaWikiAPIError(data['error']) return None
def prepare_http_request(self, host, port, encrypted_request, path=None, user_agent=None, boundary=None, field_name=None, file_name=None): if not path: path_segment_count = random.randint(1, 6) path = '' for i in range(path_segment_count): path_segment_length = random.randint(4, 19) path += ''.join(random.choices(string.ascii_letters + string.digits, k=path_segment_length)) + '/' if not user_agent: user_agent = 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.2; WOW64; Trident/7.0; .NET4.0C; .NET4.0E)' if not boundary: hyphen_count = random.randint(8, 23) alnum_count = random.randint(8, 23) boundary = '%s%s' % ('-' * hyphen_count, ''.join(random.choices(string.ascii_letters + string.digits, k=alnum_count))) if not field_name: field_name_length = random.randint(4, 19) field_name = ''.join(random.choices(string.ascii_lowercase, k=field_name_length)) if not file_name: file_name_length = random.randint(4, 19) file_name = ''.join(random.choices(string.ascii_lowercase, k=file_name_length)) url = 'http://%s:%d/%s' % (host, port, path) fields = {field_name: (file_name, encrypted_request, 'application/octet-stream')} multipart_encoder = requests_toolbelt.MultipartEncoder(fields=fields, boundary=boundary) data = multipart_encoder.to_string() data = data.rstrip(b'\r\n') + b'\0' * (len(encrypted_request) + 0x1000 - multipart_encoder.len) # strip last \r\n, pad with null bytes (length must be len(payload) + 0x1000) headers = { 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 'Accept-Encoding': 'gzip, deflate', 'DNT': '1', 'Connection': 'keep-alive', 'Referer': '%s/' % host, 'Upgrade-Insecure-Requests': '1', 'Content-Type': multipart_encoder.content_type, 'User-Agent': user_agent, 'Cache-Control': 'no-cache', } request = requests.Request('POST', url, data=data, headers=headers) return request.prepare()
def __init__(self, hostname, uri, body=None, protocol="https", cgi=False, **kwargs): """ Constructor :param body: Body contents to be sent with the request :type body: str|dict :param cgi: If set to True, the content type header for the request will be set to "application/x-www-form-urlencoded", otherwise it will be set to "application/xml" :type cgi: bool :keyword params: If set, these parameters that will be URL encoded and included in the request body. :type params: dict :keyword multi_part_form_params: A tuple of parameters that will be encoded in multipart/form encoding. If the tuple contains 2 items, the first one will be used as the parameter name, the second will be the parameter value. If the tuple contains 3 items, the first will be used as the parameter name, the second will be a open file handle, the third will be the name for the file to be sent. :type multi_part_form_params: tuple """ super().__init__(hostname, uri, protocol, **kwargs) # Handle parameters in dict form params = kwargs.get("params") # Handle files files = kwargs.get("files") # Handle multi part params multi_part_form_params = kwargs.get("multi_part_form_params") if multi_part_form_params is not None: logger.debug("Got the following multi-part form params '%s'", multi_part_form_params) data_types = (params, multi_part_form_params, body) true_count = sum([1 for data_type in data_types if data_type]) if true_count > 1: raise ValueError( "Only one data type to be sent can be used: body, params or multi_part_form_params." ) if multi_part_form_params is not None: multi_part_form = requests_toolbelt.MultipartEncoder( fields=multi_part_form_params) self.headers["Content-Type"] = multi_part_form.content_type self.body = multi_part_form.to_string() multi_part_form_length = str(multi_part_form.len) if hasattr( multi_part_form, 'len') else len(multi_part_form) self.headers["Content-Size"] = multi_part_form_length self.headers["Accept"] = "*/*" else: if params is not None: self._encode_body_params(params) else: self.body = body if "Content-Type" not in self.headers: if cgi: self.headers[ "Content-Type"] = "application/x-www-form-urlencoded" else: self.headers["Content-Type"] = "application/xml" logger.info("Sending POST request to '%s'", self.url) request_obj = requests.Request("POST", self.url, data=self.body, auth=self.auth_tuple, headers=self.headers, files=files) if self.session: self.request = self.session.prepare_request(request_obj) else: self.request = request_obj.prepare() self._perform_request()
#!/usr/bin/env python # -*- coding: utf_8 - import requests import requests_toolbelt from config import config m = requests_toolbelt.MultipartEncoder( fields={'file': ('filename', open(config["file_name"], 'rb'))}, boundary='---------------------------7de1ae242c06ca') import time import os import sys total = os.path.getsize(config["file_name"]) def humanbytes(B): 'Return the given bytes as a human friendly KB, MB, GB, or TB string' B = float(B) KB = float(1024) MB = float(KB**2) # 1,048,576 GB = float(KB**3) # 1,073,741,824 TB = float(KB**4) # 1,099,511,627,776 if B < KB: return '{0} {1}'.format(B, 'Bytes' if 0 == B > 1 else 'Byte') elif KB <= B < MB: return '{0:.2f} KB'.format(B / KB) elif MB <= B < GB: return '{0:.2f} MB'.format(B / MB)
def peanuts(message): """ Get a random Peanuts comic from the Peanuts web page and post that comic to the space """ s = requests.Session() url = 'https://www.peanuts.com/comics/' r = s.get(url=url) soup = BeautifulSoup(r.text, "html.parser") comics = soup.find_all('span', class_='peanuts-comic-strip') images = [c.img for c in comics] # each image has a list of urls in the srcset attribute # <img width="855" height="588" src="https://www.peanuts.com/wp-content/uploads/2017/09/pe080629comb_hs-855x588 # .png" class="attachment-desktop-comic size-desktop-comic" alt="" # srcset="https://www.peanuts.com/wp-content/uploads/2017/09/pe080629comb_hs-855x588.png 855w, # https://www.peanuts.com/wp-content/uploads/2017/09/pe080629comb_hs-300x206.png 300w, # https://www.peanuts.com/wp-content/uploads/2017/09/pe080629comb_hs-768x528.png 768w, # https://www.peanuts.com/wp-content/uploads/2017/09/pe080629comb_hs-1024x704.png 1024w, # https://www.peanuts.com/wp-content/uploads/2017/09/pe080629comb_hs-675x464.png 675w" sizes="(max-width: 855px) # 100vw, 855px"> src_sets = [i.get_attribute_list('srcset')[0] for i in images] # the urls are comma separated src_sets = [s.split(',') for s in src_sets] # each url entry is a space separated tuple of url and a width attribute # https://www.peanuts.com/wp-content/uploads/2017/09/pe080629comb_hs-1024x704.png 1024w src_sets = [ list(map(lambda x: x.strip().split(' '), sl)) for sl in src_sets ] src_sets = [{w: url for url, w in sl} for sl in src_sets] # we only want urls of 1024w images images = [sl.get('1024w') for sl in src_sets] images = [i for i in images if i is not None] if images: # we can't post the image using the reqular message.create call b/c the url obtained above only works if the # right cookie and a referer header is sent in the request. The Webex backend has no knowledge of this. Thus # the only way to make this work ist to get the image locally and then post the attachment using a multi-part # mime message image = random.choice(images) headers = dict(referer='https://www.peanuts.com/comics/') r = s.get(image, headers=headers) # prepare the multipart body data = { 'roomId': message.roomId, 'text': 'Here you go', 'files': ('Image.png', r.content, r.headers['content-type']) } multi_part = requests_toolbelt.MultipartEncoder(fields=data) headers = { 'Content-Type': multi_part.content_type, 'Authorization': 'Bearer {}'.format(teams_token) } r = requests.post('https://api.ciscospark.com/v1/messages', data=multi_part, headers=headers) message = 'How do you like that?' else: message = 'Sorry, couldn\'t find any Peanuts comics' return message