如何使用Python、Selenium和PhantomJS下载文件

如何使用Python、Selenium和PhantomJS下载文件,python,csv,selenium,phantomjs,Python,Csv,Selenium,Phantomjs,以下是我的情况:我必须登录到一个网站并从那里下载一个CSV,从linux服务器无头下载。页面使用JS,没有它就无法工作 经过一些研究,我选择了硒和幻影。 登录、设置CSV参数以及使用Selenium/PhantomJS/Py3查找下载按钮都没有问题,实际上令人惊讶地愉快 但是点击下载按钮没有任何作用。经过一些研究,我发现PhantomJS似乎不支持下载对话框和下载,但它已经在即将推出的功能列表中 因此,在我发现下载按钮只是在调用RESTAPI Url之后,我想我使用了一种解决方法来解决urlli

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

经过一些研究,我选择了硒和幻影。 登录、设置CSV参数以及使用Selenium/PhantomJS/Py3查找下载按钮都没有问题,实际上令人惊讶地愉快

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

因此,在我发现下载按钮只是在调用RESTAPI 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代码测试下载,因为PhantonJs本身不支持下载。因此,如果您的下载按钮不提供文件链接,则无法进行测试

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


您可以尝试以下方法:

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)

我最近使用Selenium利用ChromeDriver从web下载了一个文件。这是因为Chrome会自动下载文件并将其存储在下载文件中。这比使用PhantomJS更容易

我建议您考虑使用含硒的ChromeDriver,并遵循以下路线:

编辑-正如下面指出的,我忽略了如何设置ChromeDriver以无头模式运行。以下是更多信息:

或:

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


您需要的是:

pip安装selenium pyvirtualdisplay

apt get install xvfb

下载


我使用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)

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

OP需要无头访问targetwebsite@Andersson-铬和硒可实现无头。我将更新案例以反映这一点。我将此标记为正确答案。对我来说,这主要是为了完成工作。使用Chrome驱动程序,它可以很好地进入页面,在那里登录,设置CSV参数并单击下载按钮。我甚至可以设置下载位置。剩下的就是让它无头了。可惜人们已经等了5年才开始使用PhantomJS的下载功能。经过快速研究,使用
xvfb
PyVirtualDisplay
在Linux中无头运行它会更容易。这实际上是无头的。@rikaidekinai-我也用
xvfb
PyVirtualDisplay
做到了这一点。我甚至使用Cygwin和新的Bash for Windows在Windows 10上实现了这一点,因此它是跨平台的。祝你好运不幸的是,这不起作用。仍然是相同的JSON响应{“success”:false,“session”:“expired”}。但值得一试,我有其他网站从他们那里获取数据,他们实际上提供了一个带有头身份验证的API。问题是我不知道到底发生了什么。该按钮触发发送CSV的AngularJS数据ng点击。我所看到的记录请求的方式是,它触发了一个RESTURL,只要我在浏览器中登录,加载时总是向我发送CSV。也许问题在于,使用PhantomJS/urllib时,我得到了一个错误的参考URL。@Jordan Lewis,这适用于Linux系统。你能告诉我如何在Windows10上使用无头chrome和selenium以及python下载文件吗?简直是天才。我想到可以用phantomjs下载,真是一场噩梦!出于好奇。。。你为什么需要
显示器
之类的东西?在我的例子中,我正在单击本地网页中的一个按钮,该按钮通过嵌入式
js
code下载一个文件。我注释掉了
显示
的内容,它仍然有效…啊。我想我明白了。我使用
chromium
作为浏览器。我把它放在一个脚本中,而不是放在
jupyter
(当然是在
chromium
中运行!),没有
显示
代码,我看到一个新的浏览器窗口打开来保存我的文件。使用
显示
代码时,不会发生这种情况。