尝试下载文件时

时间:2018-02-05 19:56:30

标签: python python-3.x selenium-webdriver google-chrome-headless

我在Mac上使用Python,Jupyter,Selenium webdriver和无头镀铬(使用Canary)。

我写了一个脚本,它抓住了一个非常古老的网站, 为了从该网站下载文件,我需要点击几个按钮,最终将我带到一个按钮,一旦点击它就会下载一个CSV文件

问题是,当无头镀铬试图下载目标文件时,它暂停并且什么都不做(即不会下载所需的文件),即使脚本已经完成运行(是的,我确实在最后关闭它脚本)

我试过了:

  • 下载其他文件(来自不同的网站)和无头镀铬似乎下载它们没有任何问题(我启用无头chrome选项成功下载文件)
  • 拍摄网站快照以确保其正确导航到下载页面(是的,正确导航)
  • 修改用户代理(它似乎使用我期望的用户代理)
  • 运行完全相同的代码而不使用无头选项 - 它使用常规chrome
  • 成功下载文件
  • 使用driver.execute_script(js_that_changes_plugins_and_langs)在驱动程序上更改插件和语言JS脚本,但我不太确定如何检查它是否实际执行(并且仍然无效)

我面临的问题:

  • 我无法找到获取最后一个下载网址的方法,因为它似乎使用了一路上生成的一些唯一ID(当您转到主页时以及导航时会给出这些ID)在网站的页面之间)所以每次会议都要改变
  • 导航网址似乎来自主页内部的iframe(以及以下网址),而且我不太确定如何检查其生成的Javascript

我在提供网站网址时没有任何问题,但是:

  • 您必须在不同页面上进行约6次点击才能使用下载按钮进入最后一页。这些点击不直观,为了解释如何导航到我想要的地方
  • ,需要花费很多时间
  • 此网站不是英文版本,这将使解释如何导航更加困难

我需要它无头而不是普通的Chrome,因为我们想要运行代码的机器非常弱并且无法运行chrome GUI

所以我的问题是:有谁知道可能出现什么问题?或者至少,我该如何调试呢?

这或多或少是我使用的代码:

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

def enable_download_in_headless_chrome(driver, download_dir):
        """
        there is currently a "feature" in chrome where
        headless does not allow file download: https://bugs.chromium.org/p/chromium/issues/detail?id=696481
        This method is a hacky work-around until the official chromedriver support for this.
        Requires chrome version 62.0.3196.0 or above.
        """

        # add missing support for chrome "send_command"  to selenium webdriver
        driver.command_executor._commands["send_command"] = ("POST", '/session/' + driver.session_id + '/chromium/send_command')

        params = {'cmd': 'Page.setDownloadBehavior', 'params': {'behavior': 'allow', 'downloadPath': download_dir}}
        command_result = driver.execute("send_command", params)
        print("response from browser:")
        for key in command_result:
            print("result:" + key + ":" + str(command_result[key]))

chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('headless')
chrome_options.add_argument('no-sandbox')
chrome_options.add_argument('disable-gpu')
chrome_options.add_argument('remote-deubgging-port=9222')
chrome_options.add_argument('disable-popup-blocking')
chrome_options.add_argument('enable-logging')
download_dir = # some path here
driver = webdriver.Chrome(chrome_options=chrome_options)
enable_download_in_headless_chrome(driver, download_dir)
ok_button = driver.find_element_by_id('the-button-name')
ok_button.click()

感谢您的帮助

4 个答案:

答案 0 :(得分:0)

因为您没有提供下载其猜测工作的URL。目标很可能是安装了类似recapta的墙,以防止刮伤。所以一定要注意这一点" recapta"如果您确实实现了代码,通知您执行授予访问权限的手动任务。

对于js,这个解决方案由zavodnyuk here提供:

  

尝试使用兼容的用户代理设置自定义用户代理(例如,从您的真实浏览器)。   功能:{' browserName':' chrome',chromeOptions:{args:[" user-agent = Mozilla / 5.0(X11; Linux x86_64)AppleWebKit / 537.36(KHTML,像Gecko)Chrome / 60.0.3112.113 Safari / 537.36"," - headless"," - disable-gpu" ]}为js上的selenium / protractor工作

我希望这会向你提示正确的方向,因为在互联网上没有太多关于python的描述。

根据评论1编辑:

在基本调试模式中,我依赖于可能的候选defs开头的print-statements。在我说printstatement的地方,它也可以是写入行。不依赖于第三方喜欢的套餐,因为我想在大多数时间里从代码中学习,然后花费时间很长,但非常值得花费时间。例如我如何直接调试:

def header_inspect(self, ID, action, data):
    print  'header_inspect, ID : %s\n, action : %s\nprocess-data : %s' % (ID, action, data)

答案 1 :(得分:0)

我认为这里有太多活动部件。如果你真的需要硒,那么其他所有 - 嗯 - 这是可以的。但是,我会从尽可能简单的事情开始。

在Python 2.7上我使用mechanize - 这样我就可以模仿与服务器的整个通信。今天这不是最好的选择,因为python 3.X是要走的路。我将描述我是如何处理这类问题的。只是为了给你更好的画面,然后我会尝试描述可能的工具。

典型的情况是登录,浏览页面,转动一些开关,触发下载,或获取内容并使用beautiful soup处理它。首先,您需要查看交换的信息。转到Web浏览器中的开发工具,然后选择“网络”选项卡。 也许你知道这一点,但这一步是强制性的,我想写一般答案。然后做正常的工作 - 只需登录,然后再做其他步骤。必须传输服务器关注的所有内容,因此您可以将其视为网络请求。机械化很好,因为我能够准备dict,并将其作为post请求发送到页面。写关于post - 典型错误的是发布到页面地址。因此,如果您访问index.html,那么您正在该页面上执行post,而服务器希望将其发送到add_user_data.html,之后您可以重定向。像会话ID这样的东西可以通过标题条目或cookie来支持 - 只需查看模式的网络通信。

正如我写的那样,Python 2.7将会停止使用。 Mechanize不适用于Python 3.x,因此应使用其他工具。您可以寻找机械化的替代方案,并查看适合您的方法。典型答案是scrapy。这是一个有点不同的工具,用于废弃网页。因此,如果你计划更大的东西,也许这是最好的选择。如果你需要单个脚本 - 我会从httpie开始。命令行工具/ python包,良好的OSX支持,您也可以send formsession management。我每天都在使用它,但我的服务器是无状态的。

我会更乐意提供确切的示例,但没有服务器信息是不可能的。你能否附上你的样本会话的转储?对它进行匿名化,我会提供样本样本,或者其他工具可能会更加贴心吗?

答案 2 :(得分:0)

由于没有具体的信息,看起来我们可以给你的唯一建议将以某种方式与你如何理解正在发生的事情有关。

如何在 为首的模式 中逐步 进行调试?这里的赌注是你的问题在于自动执行任务而不是无头。

使用所有导入和函数定义(例如enable_download_in_headless_chrome)执行您的脚本,不使用这些定义。实际上,在download_dir = # some path here之前执行此操作,然后在Python Shell中键入

>>> driver = webdriver.Chrome(chrome_options=chrome_options)

现在,您可以手动与浏览器进行互动,然后打开Chrome DevTools并转到Console。确保错误will be displayed。让我们继续并输入其余的命令

>>> enable_download_in_headless_chrome(driver, download_dir)
>>> ...
>>> ok_button.click()

它说什么?

答案 3 :(得分:-1)

尝试字符串downloadFilepath =“ \\ sd-”;

chromePrefs.put(“ download.default_directory”,downloadFilepath);