【问题标题】:How to download a file with Python, Selenium and PhantomJS如何使用 Python、Selenium 和 PhantomJS 下载文件
【发布时间】:2017-04-12 23:55:46
【问题描述】:

这是我的情况:我必须登录一个网站并从那里下载一个 CSV,从 linux 服务器无头。页面使用JS,没有它就无法工作。

经过一些研究,我选择了 Selenium 和 PhantomJS。 登录、设置 CSV 的参数、找到 Selenium/PhantomJS/Py3 的下载按钮都没有问题,实际上非常愉快。

但是点击下载按钮并没有做任何事情。经过一番研究,我发现 PhantomJS 似乎不支持下载对话框和下载,但它在即将推出的功能列表中。

所以在我发现下载按钮只是调用 REST API Url 之后,我想我使用 urllib 的解决方法。问题是,它仅在您登录该站点时才有效。 所以第一次尝试失败了,因为它返回了:b'{"success":false,"session":"expired"}',这是有道理的,因为我希望 Selenium 和 urllib 使用不同的会话。 所以我想我在 urrlib 中使用 Seleniums 驱动程序的标头尝试这个:

...
url = 'http://www.foo.com/api/index'
data = urllib.parse.urlencode({
        'foopara': 'cadbrabar',
    }).encode('utf-8')
headers = {}
for cookie in driver.get_cookies():
    headers[cookie['name']] = cookie['value']
req = urllib.request.Request(url, data, headers)
with urllib.request.urlopen(req) as response:
    page = response.read()
driver.close()

不幸的是,这产生了与过期会话相同的结果。我做错了什么,有没有办法解决这个问题,其他建议还是我陷入了死胡同?提前致谢。

【问题讨论】:

    标签: python csv selenium phantomjs


    【解决方案1】:

    我找到了一个解决方案并想分享它。 一个要求发生了变化,我不再使用PhantomJS,而是使用chromedriver,它与虚拟帧缓冲区无头工作。同样的结果,它完成了工作。


    你需要的是:

    pip install selenium pyvirtualdisplay

    apt-get install xvfb

    下载ChromeDriver


    我使用 Py3.5 和来自 ovh.net 的带有标签而不是按钮的测试文件。 脚本等待 出现在页面上,然后单击它。如果您不等待元素并且在异步站点上,则您尝试单击的元素可能还不存在。下载位置是相对于脚本位置的文件夹。如果文件已经下载了第二个延迟,脚本会检查该目录。如果我没记错的话,文件在下载过程中应该是 .part 并且一旦它变成filename 中指定的 .dat,脚本就会完成。如果在下载之前关闭虚拟帧缓冲区和驱动程序将无法完成。 完整的脚本如下所示:

    # !/usr/bin/python
    # coding: utf-8
    
    import os
    import sys
    import time
    from pyvirtualdisplay import Display
    from selenium import webdriver
    from selenium.webdriver.support.wait import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    from selenium.webdriver.common.by import By
    import glob
    
    
    def main(argv):
        url = 'http://ovh.net/files'
        dl_dir = 'downloads'
        filename = '1Mio.dat'
    
        display = Display(visible=0, size=(800, 600))
        display.start()
    
        chrome_options = webdriver.ChromeOptions()
        dl_location = os.path.join(os.getcwd(), dl_dir)
    
        prefs = {"download.default_directory": dl_location}
        chrome_options.add_experimental_option("prefs", prefs)
        chromedriver = "./chromedriver"
        driver = webdriver.Chrome(executable_path=chromedriver, chrome_options=chrome_options)
    
        driver.set_window_size(800, 600)
        driver.get(url)
        WebDriverWait(driver, 30).until(EC.presence_of_element_located((By.XPATH, '//a[@href="' + filename + '"]')))
    
        hyperlink = driver.find_element_by_xpath('//a[@href="' + filename + '"]')
        hyperlink.click()
    
        while not(glob.glob(os.path.join(dl_location, filename))):
            time.sleep(1)
    
        driver.close()
        display.stop()
    
    if __name__ == '__main__':
        main(sys.argv)
    

    我希望这对将来的某人有所帮助。

    【讨论】:

    • @Jordan Lewis,这适用于 Linux 系统。你能指导我如何在 Windows 10 上使用带有 selenium 和 python 的无头 chrome 下载文件吗?
    • 该死的天才。我以为我可以用phantomjs 下载真是一场噩梦!出于好奇......你为什么需要display 的东西?就我而言,我单击本地网页中的一个按钮,该按钮通过嵌入的js 代码下载文件。我注释掉了 display 的东西,它仍然有效......
    • 啊。我想我明白了。我使用 chromium 作为我的浏览器。我把它放在一个脚本中,而不是 jupyter 中(当然是在 chromium 中运行!)并且没有 display 代码,我看到一个新的浏览器窗口打开来保存我的文件。使用display 代码,这不会发生。
    【解决方案2】:

    如果您要下载的按钮有文件链接,您可以使用python代码测试下载它,因为PhantonJs本身不支持下载。因此,如果您的下载按钮未提供文件链接,则您无法进行测试。

    要使用文件链接和 phyton 进行测试(断言该文件存在),您可以关注此主题。由于我是 C# 开发人员和测试人员,我不知道用 python 编写代码没有错误的更好方法,但我相信你可以:

    Basic http file downloading and saving to disk in python?

    【讨论】:

    • 问题是我不知道到底发生了什么。该按钮触发发送 CSV 的 AngularJS data-ng-click。我所看到的记录请求是它触发了一个 REST URL,只要我在浏览器中登录,加载时总是向我发送 CSV。也许问题是使用 PhantomJS/urllib 我得到了错误的引用 URL。
    【解决方案3】:

    我最近使用 Selenium 来利用 ChromeDriver 从 Web 下载文件。这是有效的,因为 Chrome 会自动下载文件并将其存储在下载文件中。这比使用 PhantomJS 更容易。

    我建议考虑将 ChromeDriver 与 Selenium 一起使用并走这条路:https://github.com/SeleniumHQ/selenium/wiki/ChromeDriver

    编辑 - 如下所述,我忽略了如何设置 ChromeDriver 以在无头模式下运行。这里有更多信息:http://www.chrisle.me/2013/08/running-headless-selenium-with-chrome/

    或者: https://gist.github.com/chuckbutler/8030755

    【讨论】:

    • OP 需要 headless 访问目标网站
    • @Andersson - 使用 ChromeDriver 和 Selenium 可以实现无头。我会更新案例以反映这一点。
    • 我将此标记为正确答案。对我来说,主要是为了完成工作。使用 Chrome 驱动程序,它可以很好地转到页面,在那里登录,设置 CSV 参数并单击下载按钮。我什至可以设置下载位置。剩下的就是让它无头。太糟糕了,人们现在等待 PhantomJS 中的下载功能已经等了 5 年。
    • 经过快速研究,使用 xvfbPyVirtualDisplay 在 Linux 中无头运行会更容易。那时这几乎是无头的。
    • @rikaidekinai - 我也这样做了,xvfbPyVirtualDisplay。我什至在 Windows 10 上使用 Cygwin 和新的 Bash for Windows 完成了它,所以它是跨平台的。祝你好运!
    【解决方案4】:

    你可以试试这样的:

    from requests.auth import HTTPBasicAuth
    import requests
    
    url = "http://some_site/files?file=file.csv"  # URL used to download file
    #  GET-request to get file content using your web-site's credentials to access file
    r = requests.get(url, auth=HTTPBasicAuth("your_username", "your_password"))
    #  Saving response content to file on your computer
    with open("path/to/folder/to/save/file/filename.csv", 'w') as my_file:
        my_file.write(r.content)
    

    【讨论】:

    • 不幸的是,这不起作用。仍然是相同的 JSON 响应 {"success":false,"session":"expired"}。但值得一试,我有其他网站我从中获取数据,这些网站实际上提供了带有标头身份验证的 API。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-12
    • 2019-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-15
    相关资源
    最近更新 更多