有没有一种方法可以在Python中使用PhantomJS?

217

我想在Python中使用PhantomJS。我搜索了这个问题,但找不到合适的解决方案。

我发现os.popen()可能是一个不错的选择。但我无法向其传递一些参数。

目前使用subprocess.Popen()可能是一个合适的解决方案。我想知道是否有更好的解决方案。

是否有办法在Python中使用PhantomJS?


我的回答如下,告诉你如何做到这一点。仅仅看一眼你的问题,实际上这正是Selenium所做的,使用了subprocess.popen,但增加了一些扩展功能,使API无缝连接。 - Pykler
@flyer:你可能应该考虑更改接受的答案,请参见下文。谢谢。 - dotancohen
8个回答

389

在Python中使用PhantomJS最简单的方法是通过Selenium。最简单的安装方法是:

  1. 安装NodeJS
  2. 使用Node的软件包管理器安装phantomjs:npm -g install phantomjs-prebuilt
  3. 安装selenium(如果您正在使用虚拟环境,请在其中进行安装)

安装完成后,您可以像这样轻松地使用phantom:

from selenium import webdriver

driver = webdriver.PhantomJS() # or add to your PATH
driver.set_window_size(1024, 768) # optional
driver.get('https://google.com/')
driver.save_screenshot('screen.png') # save a screenshot to disk
sbtn = driver.find_element_by_css_selector('button.gbqfba')
sbtn.click()
如果您的系统路径环境变量设置不正确,那么您需要将确切路径作为参数传递给 webdriver.PhantomJS()。请将此替换为:

如果您的系统路径环境变量没有正确设置,您需要指定确切的路径作为参数传递给 webdriver.PhantomJS()。 将此内容替换为:

driver = webdriver.PhantomJS() # or add to your PATH

...随附以下内容:

driver = webdriver.PhantomJS(executable_path='/usr/local/lib/node_modules/phantomjs/lib/phantom/bin/phantomjs')

参考文献:


45
非常好,这可能节省了我数天的时间。谢谢。如果想要获得整个渲染后的页面源代码,可以使用driver.page_source - scharfmn
4
这确实起作用很好,我感到惊喜,因为http://phantomjs.org/faq.html上说“不是Node.js模块”,但https://npmjs.org/package/phantomjs的npm封装使它在这个目的上表现得很好。在我的情况下,我想做这个:`bodyStr = driver.find_element_by_tag_name("body").get_attribute("innerHTML")`,它起作用了! - MarkHu
8
我同意Ghost的依赖环境异常复杂,即使安装了数百个X11相关的库,我也没能让它正��运行。Ghost就像是一则恐怖故事。 - Pykler
5
你需要将PhantomJS的路径作为第一个参数传递给PhantomJS,或者修复你的Windows系统路径以便能够看到PhantomJS。 - Pykler
3
在Windows系统下,我不必通过nodenpm安装phantomJS。只需从http://phantomjs.org/download.html下载二进制文件,并将`phantomjs.exe`放置在我的PATH路径中的某个位置(例如`c:\Windows\System32`),或者反之亦然(将其放在任何位置并将该文件夹添加到PATH路径中),就足以让它在Python中工作。 - Dirk
显示剩余21条评论

85
PhantomJS最近完全放弃了Python支持。然而,PhantomJS现在嵌入了Ghost Driver
一个新项目已经站出来填补这个空白:ghost.py。你可能想使用它代替:
from ghost import Ghost
ghost = Ghost()

with ghost.start() as session:
    page, extra_resources = ghost.open("http://jeanphi.me")
    assert page.http_status==200 and 'jeanphix' in ghost.content

22
尽管支持已经停止,但我发现安装npm(node包管理器)并使用它来安装最新的phantomjs(带有webdriver支持)以及在python中安装selenium比试图让PyQT或PySide正常工作要容易得多。关于phantom的好处是它真正无头,并且不需要UI / X11相关库才能工作。 - Pykler
13
在尝试使用ghost.py后非常厌恶,我在下面添加了一条解释我的首选解决方案。 - Pykler
8
Pykler说“讨厌我的人生”并不是夸张。如果有人把这个问题的“正确答案”改成Pykler的话,我就可以省下一天的努力了。 - YPCrumble
2
@YPCrumble:不幸的是,只有原帖发布者可以这样做,更改已接受的答案。 - Martijn Pieters
3
今天早上尝试了许多不同的方法后,@Pykler的解决方案最终表现最流畅。 - andyzinsser
显示剩余6条评论

40

现在,由于GhostDriver已经与PhantomJS捆绑在一起,因此通过Selenium使用它变得更加方便。

我尝试了Pykler建议的PhantomJS Node安装方式,但实际上我发现它比独立安装的PhantomJS要慢。我猜独立安装版本之前可能没有提供这些功能,但从v1.9开始,它确实提供了这些功能。

  1. 安装PhantomJS (http://phantomjs.org/download.html) (如果您使用Linux,请按照以下说明进行操作https://dev59.com/WWoy5IYBdhLWcg3wFqNT#14267295
  2. 使用pip安装Selenium。

现在你可以像这样使用

import selenium.webdriver
driver = selenium.webdriver.PhantomJS()
driver.get('http://google.com')
# do some processing

driver.quit()

3
感谢您指出有关在Ubuntu上安装PhantomJS的SO答案,它对我很有帮助。 - Dennis Golomazov
我刚学会的一种快速安装Selenium的方法是,在Windows上输入:C:\Python34\Scripts\pip.exe install Selenium。 - ntk4

8

以下是我使用PhantomJS和Django测试JavaScript的方法:

mobile/test_no_js_errors.js

var page = require('webpage').create(),
    system = require('system'),
    url = system.args[1],
    status_code;

page.onError = function (msg, trace) {
    console.log(msg);
    trace.forEach(function(item) {
        console.log('  ', item.file, ':', item.line);
    });
};

page.onResourceReceived = function(resource) {
    if (resource.url == url) {
        status_code = resource.status;
    }
};

page.open(url, function (status) {
    if (status == "fail" || status_code != 200) {
        console.log("Error: " + status_code + " for url: " + url);
        phantom.exit(1);
    }
    phantom.exit(0);
});

mobile/tests.py:

import subprocess
from django.test import LiveServerTestCase

class MobileTest(LiveServerTestCase):
    def test_mobile_js(self):
        args = ["phantomjs", "mobile/test_no_js_errors.js", self.live_server_url]
        result = subprocess.check_output(args)
        self.assertEqual(result, "")  # No result means no error

Run tests:

manage.py test mobile


谢谢。我使用了 subprocess.Popen 调用了phantomjs脚本,它运行良好 :) - flyer
你看到这个有多么的局限性了吗?你所做的只是调用外壳来执行phantomjs - 你并没有使用“适当”的接口来处理异常、阻塞等。 - kamelkev
@kamelkev: 我明白这种方法的局限性。好处是,这种方法使我能够使用 Django 的引导功能为每个测试设置具有正确内容的测试数据库。是的,它可以与其他答案结合使用,以获得最佳效果。 - Emil Stenström

6

@Pykler的回答很棒,但是Node的要求已经过时了。那个答案中的评论提供了更简单的答案,我在这里列出来以节省其他人的时间:

  1. Install PhantomJS

    As @Vivin-Paliath points out, it's a standalone project, not part of Node.

    Mac:

    brew install phantomjs
    

    Ubuntu:

    sudo apt-get install phantomjs
    

    etc

  2. Set up a virtualenv (if you haven't already):

    virtualenv mypy  # doesn't have to be "mypy". Can be anything.
    . mypy/bin/activate
    

    If your machine has both Python 2 and 3 you may need run virtualenv-3.6 mypy or similar.

  3. Install selenium:

    pip install selenium
    
  4. Try a simple test, like this borrowed from the docs:

    from selenium import webdriver
    from selenium.webdriver.common.keys import Keys
    
    driver = webdriver.PhantomJS()
    driver.get("http://www.python.org")
    assert "Python" in driver.title
    elem = driver.find_element_by_name("q")
    elem.clear()
    elem.send_keys("pycon")
    elem.send_keys(Keys.RETURN)
    assert "No results found." not in driver.page_source
    driver.close()
    

如何在Windows上安装PhantomJS?使用pip命令似乎无法正常工作。 - MD. Khairul Basar
1
Pip是Python的软件包安装程序,因此它可以与作为Python软件包提供的Selenium一起使用。PhantomJS不是Python软件包,因此无法使用pip进行安装。我快速搜索了一下“PhantomJS在Windows上的安装”,有很好的结果。 - Andrew E

5
如果使用Anaconda,请使用以下方式安装:
conda install PhantomJS

在你的脚本中:

from selenium import webdriver
driver=webdriver.PhantomJS()

运行完美。


目前,默認渠道不包含Linux64版的PhantomJS。 - Eugene Pakhomov
该死,我爱conda <3 ,太容易了。我使用的是OSX操作系统。 - O.rka

5

我做的是 python3.3 相关的工作。我正在处理大量网站列表,所以在超时时失败对于任务能够完成整个列表是至关重要的。

command = "phantomjs --ignore-ssl-errors=true "+<your js file for phantom>
process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)

# make sure phantomjs has time to download/process the page
# but if we get nothing after 30 sec, just move on
try:
    output, errors = process.communicate(timeout=30)
except Exception as e:
    print("\t\tException: %s" % e)
    process.kill()

# output will be weird, decode to utf-8 to save heartache
phantom_output = ''
for out_line in output.splitlines():
    phantom_output += out_line.decode('utf-8')

谢谢,我能够根据我的目的进行修改。 - iChux

2

如果您正在使用Buildout,您可以使用gp.recipe.node食谱轻松自动化Pykler所描述的安装过程。

[nodejs]
recipe = gp.recipe.node
version = 0.10.32
npms = phantomjs
scripts = phantomjs

这部分将以二进制方式安装node.js(至少在我的系统上),然后使用npm安装PhantomJS。最后创建一个入口点bin/phantomjs,您可以使用它来调用PhantomJS webdriver。(要安装Selenium,您需要在您的egg requirements或Buildout配置中指定它。)

driver = webdriver.PhantomJS('bin/phantomjs')

1
使用Buildout自动化安装过程的另一种方法是使用gp.recipe.phantomjs,它配置了phantomjscasperjs - gakhov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接