def submit(self, submit_name=None, make_request=True, url=None, extra_post=None): """ Submit default form. :param submit_name: name of button which should be "clicked" to submit form :param make_request: if `False` then grab instance will be configured with form post data but request will not be performed :param url: explicitly specify form action url :param extra_post: (dict or list of pairs) additional form data which will override data automatically extracted from the form. Following input elements are automatically processed: * input[type="hidden"] - default value * select: value of last option * radio - ??? * checkbox - ??? Multipart forms are correctly recognized by grab library. Example:: # Assume that we going to some page with some form g.go('some url') # Fill some fields g.set_input('username', 'bob') g.set_input('pwd', '123') # Submit the form g.submit() # or we can just fill the form # and do manual submission g.set_input('foo', 'bar') g.submit(make_request=False) g.request() # for multipart forms we can specify files from grab import UploadFile g.set_input('img', UploadFile('/path/to/image.png')) g.submit() """ # TODO: add .x and .y items # if submit element is image post = self.form_fields() # Build list of submit buttons which have a name submit_controls = {} for elem in self.form.inputs: if (elem.tag == 'input' and elem.type == 'submit' and elem.get('name') is not None): submit_controls[elem.name] = elem # All this code need only for one reason: # to not send multiple submit keys in form data # in real life only this key is submitted whose button # was pressed if len(submit_controls): # If name of submit control is not given then # use the name of first submit control if submit_name is None or submit_name not in submit_controls: controls = sorted(submit_controls.values(), key=lambda x: x.name) submit_name = controls[0].name # Form data should contain only one submit control for name in submit_controls: if name != submit_name: if name in post: del post[name] if url: action_url = urljoin(self.url, url) else: action_url = urljoin(self.url, self.form.action) # Values from `extra_post` should override values in form # `extra_post` allows multiple value of one key # Process saved values of file fields if self.form.method == 'POST': if 'multipart' in self.form.get('enctype', ''): for key, obj in self._file_fields.items(): post[key] = obj post_items = list(post.items()) del post if extra_post: if isinstance(extra_post, dict): extra_post_items = extra_post.items() else: extra_post_items = extra_post # Drop existing post items with such key keys_to_drop = set([x for x, y in extra_post_items]) for key in keys_to_drop: post_items = [(x, y) for x, y in post_items if x != key] for key, value in extra_post_items: post_items.append((key, value)) if self.form.method == 'POST': if 'multipart' in self.form.get('enctype', ''): self.grab.setup(multipart_post=post_items) else: self.grab.setup(post=post_items) self.grab.setup(url=action_url) else: url = action_url.split('?')[0] + '?' + smart_urlencode(post_items) self.grab.setup(url=url) if make_request: return self.grab.request() else: return None
def submit(self, submit_name=None, make_request=True, url=None, extra_post=None): """ Submit default form. :param submit_name: name of button which should be "clicked" to submit form :param make_request: if `False` then grab instance will be configured with form post data but request will not be performed :param url: explicitly specify form action url :param extra_post: (dict or list of pairs) additional form data which will override data automatically extracted from the form. Following input elements are automatically processed: * input[type="hidden"] - default value * select: value of last option * radio - ??? * checkbox - ??? Multipart forms are correctly recognized by grab library. Example:: # Assume that we going to some page with some form g.go('some url') # Fill some fields g.set_input('username', 'bob') g.set_input('pwd', '123') # Submit the form g.submit() # or we can just fill the form # and do manual submission g.set_input('foo', 'bar') g.submit(make_request=False) g.request() # for multipart forms we can specify files from grab import UploadFile g.set_input('img', UploadFile('/path/to/image.png')) g.submit() """ # TODO: add .x and .y items # if submit element is image post = self.form_fields() # Build list of submit buttons which have a name submit_controls = {} for elem in self.form.inputs: if (elem.tag == 'input' and elem.type == 'submit' and elem.get('name') is not None): submit_controls[elem.name] = elem # All this code need only for one reason: # to not send multiple submit keys in form data # in real life only this key is submitted whose button # was pressed if len(submit_controls): # If name of submit control is not given then # use the name of first submit control if submit_name is None or submit_name not in submit_controls: controls = sorted(submit_controls.values(), key=lambda x: x.name) submit_name = controls[0].name # Form data should contain only one submit control for name in submit_controls: if name != submit_name: if name in post: del post[name] if url: action_url = urljoin(self.url, url) else: action_url = urljoin(self.url, self.form.action) # Values from `extra_post` should override values in form # `extra_post` allows multiple value of one key # Process saved values of file fields if self.form.method == 'POST': if 'multipart' in self.form.get('enctype', ''): for key, obj in self._file_fields.items(): post[key] = obj post_items = list(post.items()) del post if extra_post: if isinstance(extra_post, dict): extra_post_items = extra_post.items() else: extra_post_items = extra_post # Drop existing post items with such key keys_to_drop = set([x for x, y in extra_post_items]) for key in keys_to_drop: post_items = [(x, y) for x, y in post_items if x != key] for key, value in extra_post_items: post_items.append((key, value)) if self.form.method == 'POST': if 'multipart' in self.form.get('enctype', ''): self.grab.setup(multipart_post=post_items) else: self.grab.setup(post=post_items) self.grab.setup(url=action_url) else: url = action_url.split('?')[0] + '?' + smart_urlencode(post_items) self.grab.setup(url=url) if make_request: return self.grab.request() else: return None
def get_form_request( self, submit_name=None, url=None, extra_post=None, remove_from_post=None): """ Submit default form. :param submit_name: name of button which should be "clicked" to submit form :param url: explicitly specify form action url :param extra_post: (dict or list of pairs) additional form data which will override data automatically extracted from the form. :param remove_from_post: list of keys to remove from the submitted data Following input elements are automatically processed: * input[type="hidden"] - default value * select: value of last option * radio - ??? * checkbox - ??? Multipart forms are correctly recognized by grab library. """ # pylint: disable=no-member post = self.form_fields() # Build list of submit buttons which have a name submit_controls = {} for elem in self.form.inputs: if (elem.tag == 'input' and elem.type == 'submit' and elem.get('name') is not None): submit_controls[elem.name] = elem # All this code need only for one reason: # to not send multiple submit keys in form data # in real life only this key is submitted whose button # was pressed if submit_controls: # If name of submit control is not given then # use the name of first submit control if submit_name is None or submit_name not in submit_controls: controls = sorted(submit_controls.values(), key=lambda x: x.name) submit_name = controls[0].name # Form data should contain only one submit control for name in submit_controls: if name != submit_name: if name in post: del post[name] if url: action_url = urljoin(self.url, url) else: action_url = urljoin(self.url, self.form.action) # Values from `extra_post` should override values in form # `extra_post` allows multiple value of one key # Process saved values of file fields if self.form.method == 'POST': if 'multipart' in self.form.get('enctype', ''): for key, obj in self._file_fields.items(): post[key] = obj post_items = list(post.items()) del post if extra_post: if isinstance(extra_post, dict): extra_post_items = extra_post.items() else: extra_post_items = extra_post # Drop existing post items with such key keys_to_drop = set([x for x, y in extra_post_items]) for key in keys_to_drop: post_items = [(x, y) for x, y in post_items if x != key] for key, value in extra_post_items: post_items.append((key, value)) if remove_from_post: post_items = [(x, y) for x, y in post_items if x not in remove_from_post] result = { 'multipart_post': None, 'post': None, 'url': None, } if self.form.method == 'POST': if 'multipart' in self.form.get('enctype', ''): result['multipart_post'] = post_items #self.grab.setup(multipart_post=post_items) else: result['post'] = post_items #self.grab.setup(post=post_items) result['url'] = action_url #self.grab.setup(url=action_url) else: url = action_url.split('?')[0] + '?' + smart_urlencode(post_items) result['url'] = url #self.grab.setup(url=url) return result