June 19, 2020

How to change download directory in Chrome driver with etaoin

If you ever had to do web browser automation in Clojure, you know of etaoin. Overall, it’s an excellant example of what a utility library should look like. Anyway, let’s get to the point. If you try to use etaoin with Chromium webdriver, and try to save a file to a specific location of your computer, you are in for a surprise. The officially recommended way of changing download directory is to pass :download-dir parameter while building the driver. Like this -

;; This is buggy.
(require '[etaoin.api :as e])
(def driver (e/chrome {:download-dir "./my/download/dir"}))

Unfortunately, this does not work (at least it did not work for me in Ubuntu Linux 20.04, with ChromeDriver 83.0.4103.39).

After painstackingly glueing information from web, I came up with a function which correctly changes the download directory. As a bonus, the download directory can be changed for the same driver on ad-hoc basis. Take a look -

(require '[etaoin.api :as e])

(defn change-chrome-download-dir
  "Changes download directory of chrome web driver."
  [driver download-dir]
  ;; NOTE: Need to do some black magic to circumvent chrome download dir bug.
  ;; Resources:
  ;; - https://bugs.chromium.org/p/chromium/issues/detail?id=696481#c164
  ;; - http://etaoin.grishaev.me/etaoin.api-api.html#etaoin.api/execute
  ;; - https://selenium.dev/selenium/docs/api/rb/Selenium/WebDriver/Chrome/Bridge.html#send_command-instance_method
  (etaoin.api/execute {:driver driver
                       :method :post
                       :path   [:session (:session @driver) "goog/cdp/execute"]
                       :data   {:cmd    "Page.setDownloadBehavior"
                                :params {:behavior     "allow"
                                         :downloadPath download-dir}}}))

(def driver (e/chrome))
(change-chrome-download-dir driver "./my/download/dir")
(e/click driver :download-link-id)

Hope this post saves some of your frustration.

Tags: Workaround , Bug , Clojure , Programming