Search code examples
python-3.xherokudjango-wkhtmltopdf

How to get WKHTMLTOPDF working on Heroku?


I created a website which generates PDF using PDFKIT and I know how to install and setup environment variable path on Window. I managed to deploy my first website on Heroku but now I'm getting error "No wkhtmltopdf executable found: "b''" When trying to generate the PDF. I have no idea, How to install and setup WKHTMLTOPDF on Heroku because this is first time I'm dealing with Linux. I really tried everything before asking this but even following this not working for me. Python 3 flask install wkhtmltopdf on heroku

If possible, please guide me with step by step on how to install and setup this.

I followed all the resource and everything but couldn't make it work. Every time I get the same error. I'm using Django version 2. Python version 3.7.

This is what I get if I do heroku stack

Available Stacks cedar-14 container heroku-16 * heroku-18

Error, I'm getting when generating the PDF. No wkhtmltopdf executable found: "b''" If this file exists please check that this process can read it. Otherwise please install wkhtmltopdf - https://github.com/JazzCore/python-pdfkit/wiki/Installing-wkhtmltopdf

My website works very well on localhost without any problem and as far as I know, I'm sure that I have done something wrong in installing wkhtmltopdf.

Thank you


Solution

  • It's non-trivial. If you want to avoid all of the below's headache, you can just use my service, api2pdf: https://github.com/api2pdf/api2pdf.python. Otherwise, if you want to try and work through it, see below.

    1) Add this to your requirements.txt to install a special wkhtmltopdf pack for heroku as well as pdfkit.

    git+git://github.com/johnfraney/wkhtmltopdf-pack.git
    pdfkit==0.6.1
    

    2) I created a pdf_manager.py in my flask app. In pdf_manager.py I have a method:

    def _get_pdfkit_config():
         """wkhtmltopdf lives and functions differently depending on Windows or Linux. We
          need to support both since we develop on windows but deploy on Heroku.
    
         Returns:
             A pdfkit configuration
         """
         if platform.system() == 'Windows':
             return pdfkit.configuration(wkhtmltopdf=os.environ.get('WKHTMLTOPDF_BINARY', 'C:\\Program Files\\wkhtmltopdf\\bin\\wkhtmltopdf.exe'))
         else:
             WKHTMLTOPDF_CMD = subprocess.Popen(['which', os.environ.get('WKHTMLTOPDF_BINARY', 'wkhtmltopdf')], stdout=subprocess.PIPE).communicate()[0].strip()
             return pdfkit.configuration(wkhtmltopdf=WKHTMLTOPDF_CMD)
    

    The reason I have the platform statement in there is that I develop on a windows machine and I have the local wkhtmltopdf binary on my PC. But when I deploy to Heroku, it runs in their linux containers so I need to detect first which platform we're on before running the binary.

    3) Then I created two more methods - one to convert a url to pdf and another to convert raw html to pdf.

    def make_pdf_from_url(url, options=None):
        """Produces a pdf from a website's url.
        Args:
            url (str): A valid url
            options (dict, optional): for specifying pdf parameters like landscape
                mode and margins
        Returns:
            pdf of the website
        """
        return pdfkit.from_url(url, False, configuration=_get_pdfkit_config(), options=options)
    
    def make_pdf_from_raw_html(html, options=None):
        """Produces a pdf from raw html.
        Args:
            html (str): Valid html
            options (dict, optional): for specifying pdf parameters like landscape
                mode and margins
        Returns:
            pdf of the supplied html
        """
        return pdfkit.from_string(html, False, configuration=_get_pdfkit_config(), options=options)
    

    I use these methods to convert to PDF.