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
相关产品推荐
相关产品推荐

