You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP结合PhantomJS执行页面JS并获取翻译后HTML的方案求助

解决方案

问题根源

你的代码返回未翻译HTML的核心原因是:PhantomJS在页面window.onload触发后就立即返回内容,但translateContent里的fetch是异步请求,此时翻译操作还没完成,DOM还没被修改。另外原HTML的文本替换逻辑存在缺陷,会导致翻译后的文本错乱。

步骤1:修正HTML中的翻译逻辑

修改HTML里的JavaScript,确保每个文本节点被正确翻译,并且添加翻译完成的标记,方便PhantomJS检测:

<!DOCTYPE html>
<html lang="en-US">
<head>
    <meta charset="UTF-8">
    <title>Translate Page</title>
</head>
<body>
    <div id="content">
        <p>This example displays a simple translate button, with no text.</p>
        <p>This example displays a simple translate button, with no text.</p>
        <div class="notranslate">
            <p>This is a paragraph.</p>
            <p>
                A particle is kept at rest at the top of a sphere of diameter \(42 m\). When disturbed slightly,
                it slides down. At what height \( h \) from the bottom, the particle will leave the sphere <br>
                (a) \( 14m \)<br>
                (b) \( 16m \)<br>
                (c) \( 35m \)<br>
                (d) \( 70m \)
            </p>
        </div>
    </div>

    <script>
        async function translateContent() {
            const textNodes = getAllTextNodes(document.body);
            // 过滤空文本和notranslate类下的节点
            const targetNodes = textNodes.filter(node => {
                const trimText = node.textContent.trim();
                if (!trimText) return false;
                let parent = node.parentElement;
                while (parent) {
                    if (parent.classList.contains('notranslate')) return false;
                    parent = parent.parentElement;
                }
                return true;
            });

            // 批量翻译文本,减少API请求次数
            const textsToTranslate = targetNodes.map(node => node.textContent.trim());
            const combinedText = textsToTranslate.join('\n');
            
            try {
                const response = await fetch(`https://translate.googleapis.com/translate_a/single?client=gtx&sl=en&tl=fr&dt=t&q=${encodeURIComponent(combinedText)}`);
                const data = await response.json();
                const translatedTexts = data[0].map(item => item[0]);
                
                // 对应替换每个节点
                targetNodes.forEach((node, index) => {
                    if (translatedTexts[index]) {
                        node.textContent = translatedTexts[index];
                    }
                });
                
                // 添加翻译完成标记
                document.body.classList.add('translation-complete');
            } catch (error) {
                console.error('Translation error:', error);
                document.body.classList.add('translation-failed');
            }
        }

        function getAllTextNodes(element) {
            const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT, null, false);
            const nodes = [];
            while (walker.nextNode()) {
                nodes.push(walker.currentNode);
            }
            return nodes;
        }

        window.onload = translateContent;
    </script>
</body>
</html>

步骤2:修改PHP代码,让PhantomJS等待翻译完成

使用JonnyW\PhantomJs库的自定义脚本功能,让PhantomJS等待body.translation-complete类出现:

<?php
require 'vendor/autoload.php';

use JonnyW\PhantomJs\Client;
use JonnyW\PhantomJs\DependencyInjection\ServiceContainer;

// 创建自定义容器,启用脚本模板
$container = ServiceContainer::getInstance();
$client = $container->get('client');

// 设置PhantomJS路径
$client->getEngine()->setPath('/usr/local/bin/phantomjs');

// 创建请求
$request = $client->getMessageFactory()->createRequest('translateHTMLUsingJs2.html', 'GET');

// 设置10秒超时,确保翻译有足够时间完成
$request->setTimeout(10000);

// 添加等待翻译完成的自定义脚本
$waitScript = <<<JS
function waitForCondition(condition, timeoutMs) {
    const start = Date.now();
    return new Promise((resolve, reject) => {
        const checkInterval = setInterval(() => {
            if (condition()) {
                clearInterval(checkInterval);
                resolve();
            } else if (Date.now() - start > timeoutMs) {
                clearInterval(checkInterval);
                reject(new Error('Wait timed out'));
            }
        }, 150);
    });
}

// 等待翻译完成标记出现
waitForCondition(() => document.body.classList.contains('translation-complete'), 8000)
    .then(() => phantom.exit())
    .catch(err => {
        console.error(err);
        phantom.exit(1);
    });
JS;

$request->setScript($waitScript);

// 发送请求并获取响应
$response = $client->getMessageFactory()->createResponse();
$client->send($request, $response);

// 输出翻译后的HTML
echo $response->getContent();
?>

备选方案:直接调用PhantomJS脚本文件

如果上述库的自定义脚本不好用,可以编写独立的PhantomJS脚本,再用PHP执行命令调用:

PhantomJS脚本(translate.js)

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

page.open(targetUrl, function(status) {
    if (status !== 'success') {
        console.log('Failed to load page');
        phantom.exit(1);
    }

    const timeout = 10000;
    const startTime = Date.now();
    const checkInterval = setInterval(() => {
        const isTranslated = page.evaluate(() => {
            return document.body.classList.contains('translation-complete');
        });

        if (isTranslated || Date.now() - startTime > timeout) {
            clearInterval(checkInterval);
            console.log(page.content);
            phantom.exit();
        }
    }, 200);
});

PHP调用代码

<?php
$htmlFile = 'translateHTMLUsingJs2.html';
phantomScript = 'translate.js';
$phantomPath = '/usr/local/bin/phantomjs';

// 执行PhantomJS命令
$command = escapeshellcmd("$phantomPath $phantomScript $htmlFile");
$translatedHtml = shell_exec($command);

echo $translatedHtml;
?>

关键注意事项

  • 超时设置:必须给足够的时间(建议5-10秒),避免因网络延迟导致翻译未完成
  • 文本过滤:修正后的代码会自动跳过.notranslate类下的内容,符合需求
  • PhantomJS兼容性:旧版本PhantomJS可能不支持fetch,可以替换为XMLHttpRequest兼容
  • API限制:谷歌免费翻译API有请求频率限制,生产环境建议使用官方付费接口

内容的提问来源于stack exchange,提问作者Richardson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 07:44:59