0

I can use Selenium to upload a file as

from selenium import webdriver

driver = webdriver.Chrome()
driver.get(r'https://www.example.com')
a = driver.find_element_by_xpath("//input[@type='file']")
a.send_keys(r'C:\abc.jpg')
b =  driver.find_element_by_xpath("//output[@id='result']").text

The above code works well.

Now, I want to use Requests to the same job. I tried to search on the web and implement the code. But I cannot get the result.

import requests
from lxml import html

a = requests.get(r'https://www.example.com')
tree = html.fromstring(a.text)
b = tree.xpath("//input[@type='file']")
b.append(r'C:\abc.jpg')#Is it correct?

The html code is as follows:

<div id="test" class="abc def ghi">
    <div class="xyz def ghi">
        Drag or<br class="def ghi">Click to input file
    </div>
    <div class="pqr def ghi">
        Upload file
    </div>
    <label id="select-file" for="input" class="def ghi"></label>
    <input type="file" id="input" hidden="" class="def ghi">
</div>

There is no form in the code. How to solve the problem?

Chan
  • 3,605
  • 9
  • 29
  • 60
  • 1
    [this answer](https://stackoverflow.com/questions/15900338/python-request-post-with-param-data) may help. you'd neet to [`requests.post`](http://docs.python-requests.org/en/master/user/quickstart/#more-complicated-post-requests) your (encoded) image. – hiro protagonist Mar 20 '18 at 07:31
  • to send data whatever type to the server, you should use 'post' function. http://docs.python-requests.org/en/master/user/quickstart/#more-complicated-post-requests – Julio CamPlaz Mar 20 '18 at 07:36
  • The example writes: `requests.post(url, params=params, data=json.dumps(data), headers=headers)` and `data = {"eventType": "AAS_PORTAL_START", "data": {"uid": "hfe3hf45huf33545", "aid": "1", "vid": "1"}}`. But I don't know how to pass in the required dictionary in my case. Is it `data={"//input[@type='file']": r'C:\abc.jpg' }`? – Chan Mar 20 '18 at 07:48
  • Can anyone please help? – Chan Mar 20 '18 at 09:06
  • Assuming you want to [post a file](http://docs.python-requests.org/en/master/user/quickstart/#post-a-multipart-encoded-file), try something like this: `requests.post('https://www.example.com', files={b.attrib['name']: open(r'C:\abc.jpg', 'rb')})` – t.m.adam Mar 20 '18 at 17:17

1 Answers1

2

You need to use files parameter. Also form's action attribute can specify different upload url, so it's better to check it out.

Here's full example:

import requests
from lxml import html

host = r'https://www.example.com'
url = '/'
filename = r'C:\abc.jpg'


req = requests.get(host + url)

tree = html.fromstring(req.text)
field = tree.xpath("//input[@type='file']")
form = next(f[0].iterancestors("form"), None)
action = form.attrib['action'] if form else url

requests.post(host + action,
              files={filename: (open(filename, 'rb'), 'image/jpg')})
Nikita Malyavin
  • 1,868
  • 1
  • 12
  • 10
  • Thank you, Nikita. I tried to run your code. However, I got the error: `form = list(f[0].iterancestors("form"))[0] IndexError: list index out of range` because `ist(f[0].iterancestors("form"))` equals `[]` – Chan Mar 21 '18 at 02:52
  • I have included the html. Any suggestions? – Chan Mar 22 '18 at 09:03
  • Hi, Chan. It's not a common case when there's no form. There should be some script processing the field. Anyway, i've edited my answer to address your case more precisely – Nikita Malyavin Mar 22 '18 at 17:44