钥匙要点
- >利用node.js和npm有效地为Web爬网和其他命令行任务设置自定义CLI缩影。
> >使用Phantomjs和Horseman软件包来模拟浏览器中的用户互动,从而增强了自动化的Web爬行功能。 - 结合了骑士方法的链接,以执行复杂的动作序列,从而在网页中进行动态交互。
- 利用骑士中的evaluate()方法直接从DOM中提取灵活的脚本和数据提取,可用于诸如污损检测之类的任务。
- >利用Horseman的屏幕截图功能在网上爬行期间捕获和保存屏幕截图,以帮助视觉QA测试等任务。
- >确保每次使用后都关闭骑士实例,以防止孤立的phantomjs过程,保持系统性能和稳定性。
- >
可以在GitHub上找到本教程的源代码。为了运行示例,您需要同时安装node.js和phantomjs。可以在此处找到用于下载和安装的说明:node.js,phantomjs。
>设置基本命令行框架任何CLI框架的核心是将命令转换为一个或多个可选或必需的参数,转换为具体操作的概念。在这方面非常有用的两个NPM软件包是指挥官和提示。
指挥官允许您定义支持哪些参数,同时提示允许您(足够适当地)提示用户在运行时输入。最终结果是一个句法甜蜜的界面,用于基于某些用户提供的数据,以动态行为执行各种动作。
>说,例如,我们希望我们的命令看起来像这样:
>$ <span>node run.js -x hello_world </span>
我们的入口点(run.js)定义了这样的参数:
>program <span>.version('1.0.0') </span> <span>.option('-x --action-to-perform [string]', 'The type of action to perform.') </span> <span>.option('-u --url [string]', 'Optional URL used by certain actions') </span> <span>.parse(process.argv); </span>
并定义了这样的各种用户输入案例:
><span>var performAction = require('./actions/' + program.actionToPerform) </span> <span>switch (program.actionToPerform) { </span> <span>case 'hello_world': </span> prompt<span>.get([{ </span> <span>// What the property name should be in the result object </span> <span>name: 'url', </span> <span>// The prompt message shown to the user </span> <span>description: 'Enter a URL', </span> <span>// Whether or not the user is required to enter a value </span> <span>required: true, </span> <span>// Validates the user input </span> <span>conform: function (value) { </span> <span>// In this case, the user must enter a valid URL </span> <span>return validUrl.isWebUri(value); </span> <span>} </span> <span>}], function (err<span>, result</span>) { </span> <span>// Perform some action following successful input </span> <span>performAction(phantomInstance, result.url); </span> <span>}); </span> <span>break; </span><span>} </span>在这一点上,我们已经定义了一个基本路径,可以通过该路径指定执行操作,并添加了一个提示以接受URL。我们只需要添加一个模块来处理该操作的逻辑即可。我们可以通过将一个名为hello_world.js的文件添加到操作目录中来做到这一点:
>
如您所见,该模块期望提供一个phantomjs对象(Phantominstance)和URL(URL)的实例。我们将暂时地定义Phantomjs实例的细节,但是目前足以看到我们为触发特定动作奠定了基础。既然我们已经制定了一定的惯例,我们可以轻松地以定义和理智的方式添加新的动作。<span>'use strict'; </span> <span>/** </span><span> * <span>@param Horseman phantomInstance </span></span><span> * <span>@param string url </span></span><span> */ </span>module<span>.exports = function (phantomInstance<span>, url</span>) { </span> <span>if (!url || typeof url !== 'string') { </span> <span>throw 'You must specify a url to ping'; </span> <span>} else { </span> <span>console.log('Pinging url: ', url); </span> <span>} </span> phantomInstance <span>.open(url) </span> <span>.status() </span> <span>.then(function (statusCode) { </span> <span>if (Number(statusCode) >= 400) { </span> <span>throw 'Page failed with status: ' + statusCode; </span> <span>} else { </span> <span>console.log('Hello world. Status code returned: ', statusCode); </span> <span>} </span> <span>}) </span> <span>.catch(function (err) { </span> <span>console.log('Error: ', err); </span> <span>}) </span> <span>// Always close the Horseman instance </span> <span>// Otherwise you might end up with orphaned phantom processes </span> <span>.close(); </span><span>}; </span>> 使用骑兵
爬行
>每次我们通过CLI框架触发操作时,我们的输入脚本(RUN.JS)实例化骑士实例并将其传递到指定的操作模块。在伪代码中,它看起来像这样:
>
现在,当我们运行命令时,骑手实例和输入URL将传递到Hello_world模块,导致Phantomjs请求URL,捕获其状态代码并将状态打印到控制台。我们刚刚使用骑马者进行了第一个真正的善意爬行。 giddyup!
<span>var phantomInstance = new Horseman({ </span> <span>phantomPath: '/usr/local/bin/phantomjs', </span> <span>loadImages: true, </span> <span>injectJquery: true, </span> <span>webSecurity: true, </span> <span>ignoreSSLErrors: true </span><span>}); </span> <span>performAction(phantomInstance, ...); </span>
复合互动的骑士方法
到目前为止,我们已经研究了非常简单的骑士用法,但是当我们将其方法链接在一起以在浏览器中执行一系列操作时,包装可以做得更多。为了演示其中一些功能,让我们定义一个动作,该操作模拟了通过GitHub导航以创建新存储库的用户。
请注意:此示例纯粹是出于演示目的,不应被视为创建GitHub存储库的可行方法。这仅仅是一个人如何使用骑手与Web应用程序进行交互的示例。如果您有兴趣以自动方式创建存储库,则应使用官方的GitHub API。
让我们假设新的爬网会像这样触发:>按照我们已经制定的CLI框架的约定,我们需要在名为create_repo.js的操作目录中添加一个新模块。与我们以前的“ Hello World”示例一样,create_repo模块导出一个包含该动作的所有逻辑的单个函数。
$ <span>node run.js -x hello_world </span>
请注意,在此操作中,我们将更多的参数传递给导出的函数,而不是以前。这些参数包括用户名,密码和存储库。一旦用户成功完成了及时挑战,我们将从run.js传递这些值。
program <span>.version('1.0.0') </span> <span>.option('-x --action-to-perform [string]', 'The type of action to perform.') </span> <span>.option('-u --url [string]', 'Optional URL used by certain actions') </span> <span>.parse(process.argv); </span>>在发生任何事情之前,我们必须添加逻辑。我们通过将案例添加到我们的主开关语句中来做到这一点:
>现在我们将此挂钩添加到run.js,当用户输入相关数据时,它将传递给操作,从而使我们可以继续进行爬网。
至于Create_repo爬网逻辑本身,我们使用骑手的方法来导航到GitHub登录页面,输入提供的用户名和密码,然后提交表单:<span>var performAction = require('./actions/' + program.actionToPerform) </span> <span>switch (program.actionToPerform) { </span> <span>case 'hello_world': </span> prompt<span>.get([{ </span> <span>// What the property name should be in the result object </span> <span>name: 'url', </span> <span>// The prompt message shown to the user </span> <span>description: 'Enter a URL', </span> <span>// Whether or not the user is required to enter a value </span> <span>required: true, </span> <span>// Validates the user input </span> <span>conform: function (value) { </span> <span>// In this case, the user must enter a valid URL </span> <span>return validUrl.isWebUri(value); </span> <span>} </span> <span>}], function (err<span>, result</span>) { </span> <span>// Perform some action following successful input </span> <span>performAction(phantomInstance, result.url); </span> <span>}); </span> <span>break; </span><span>} </span>
我们通过等待表单提交页面加载来继续链条:
之后,我们使用jQuery来确定登录是否成功:
<span>'use strict'; </span> <span>/** </span><span> * <span>@param Horseman phantomInstance </span></span><span> * <span>@param string url </span></span><span> */ </span>module<span>.exports = function (phantomInstance<span>, url</span>) { </span> <span>if (!url || typeof url !== 'string') { </span> <span>throw 'You must specify a url to ping'; </span> <span>} else { </span> <span>console.log('Pinging url: ', url); </span> <span>} </span> phantomInstance <span>.open(url) </span> <span>.status() </span> <span>.then(function (statusCode) { </span> <span>if (Number(statusCode) >= 400) { </span> <span>throw 'Page failed with status: ' + statusCode; </span> <span>} else { </span> <span>console.log('Hello world. Status code returned: ', statusCode); </span> <span>} </span> <span>}) </span> <span>.catch(function (err) { </span> <span>console.log('Error: ', err); </span> <span>}) </span> <span>// Always close the Horseman instance </span> <span>// Otherwise you might end up with orphaned phantom processes </span> <span>.close(); </span><span>}; </span>
>在我们的个人资料页面上,我们将导航到我们的存储库标签:
<span>var phantomInstance = new Horseman({ </span> <span>phantomPath: '/usr/local/bin/phantomjs', </span> <span>loadImages: true, </span> <span>injectJquery: true, </span> <span>webSecurity: true, </span> <span>ignoreSSLErrors: true </span><span>}); </span> <span>performAction(phantomInstance, ...); </span>
在我们的存储库选项卡时,我们检查是否已经存在带有指定名称的存储库。如果是这样,那么我们会丢下错误。如果不是,那么我们继续我们的顺序:
$ <span>node run.js -x create_repo </span>
假设没有错误,我们通过编程单击“新存储库”按钮并等待下一页:
module<span>.exports = function (phantomInstance<span>, username, password, repository</span>) { </span> <span>if (!username || !password || !repository) { </span> <span>throw 'You must specify login credentials and a repository name'; </span> <span>} </span> <span>... </span><span>} </span>
之后,我们输入提供的存储库名称并提交表格:
<span>switch (program.actionToPerform) { </span> <span>case 'create_repo': </span> prompt<span>.get([{ </span> <span>name: 'repository', </span> <span>description: 'Enter repository name', </span> <span>required: true </span> <span>}, { </span> <span>name: 'username', </span> <span>description: 'Enter GitHub username', </span> <span>required: true </span> <span>}, { </span> <span>name: 'password', </span> <span>description: 'Enter GitHub password', </span> <span>hidden: true, </span> <span>required: true </span> <span>}], function (err<span>, result</span>) { </span> <span>performAction( </span> phantomInstance<span>, </span> result<span>.username, </span> result<span>.password, </span> result<span>.repository </span> <span>); </span> <span>}); </span> <span>break; </span> <span>... </span>>一旦到达生成页面,我们就会知道存储库是创建的:
与任何骑马爬行一样,至关重要的是,我们结束了骑马的实例:
phantomInstance <span>.open('https://github.com/login') </span> <span>.type('input[name="login"]', username) </span> <span>.type('input[name="password"]', password) </span> <span>.click('input[name="commit"]') </span>
>未能关闭骑士实例可能会导致机器上的孤立phantomjs处理。
<span>.waitForNextPage() </span>>爬行以收集数据
在这一点上,我们已经组装了一系列静态序列,以编程方式在GitHub上创建一个新的存储库。为此,我们链接了一系列的骑手方法。
这种方法对于事先已知的特定结构和行为模式可能很有用,但是,您可能会发现您需要在某个时候实现更灵活的脚本。如果您的动作序列有可能根据上下文变化或产生多个不同的结果,则可能是这种情况。如果您需要从DOM中提取数据,也将是这种情况。
在这种情况下,您可以使用Horseman的evaliate()方法,它允许您通过注入内联或外部链接JavaScript来执行浏览器中的自由形式交互。>
>本节演示了从页面中提取基本数据的示例(在这种情况下,锚点链接)。可能需要这种情况的一种情况是构建一个污损检测轨,以击中域上的每个URL。与我们的最后一个示例一样,我们必须首先在操作目录中添加一个新模块:
,然后在run.js中为新操作添加一个钩子:
$ <span>node run.js -x hello_world </span>>
现在,此代码已经到位,我们可以通过运行以下命令来从任何给定的页面提取链接:
program <span>.version('1.0.0') </span> <span>.option('-x --action-to-perform [string]', 'The type of action to perform.') </span> <span>.option('-u --url [string]', 'Optional URL used by certain actions') </span> <span>.parse(process.argv); </span>
>此操作演示了从页面上提取数据,并且不会利用骑手内置的任何浏览器操作。它直接执行您在estuation()方法中放置的任何JavaScript,并且会像在浏览器环境中本地运行一样。
><span>var performAction = require('./actions/' + program.actionToPerform) </span> <span>switch (program.actionToPerform) { </span> <span>case 'hello_world': </span> prompt<span>.get([{ </span> <span>// What the property name should be in the result object </span> <span>name: 'url', </span> <span>// The prompt message shown to the user </span> <span>description: 'Enter a URL', </span> <span>// Whether or not the user is required to enter a value </span> <span>required: true, </span> <span>// Validates the user input </span> <span>conform: function (value) { </span> <span>// In this case, the user must enter a valid URL </span> <span>return validUrl.isWebUri(value); </span> <span>} </span> <span>}], function (err<span>, result</span>) { </span> <span>// Perform some action following successful input </span> <span>performAction(phantomInstance, result.url); </span> <span>}); </span> <span>break; </span><span>} </span>>在本节中应注意的最后一件事,该部分提到了较早的提及:不仅可以使用estaution()方法在浏览器中执行自定义JavaScript,而且还可以在运行之前将外部脚本注入运行时环境您的评估逻辑。可以这样做:
>通过扩展上面的逻辑,您几乎可以在任何网站上执行任何操作。
><span>'use strict'; </span> <span>/** </span><span> * <span>@param Horseman phantomInstance </span></span><span> * <span>@param string url </span></span><span> */ </span>module<span>.exports = function (phantomInstance<span>, url</span>) { </span> <span>if (!url || typeof url !== 'string') { </span> <span>throw 'You must specify a url to ping'; </span> <span>} else { </span> <span>console.log('Pinging url: ', url); </span> <span>} </span> phantomInstance <span>.open(url) </span> <span>.status() </span> <span>.then(function (statusCode) { </span> <span>if (Number(statusCode) >= 400) { </span> <span>throw 'Page failed with status: ' + statusCode; </span> <span>} else { </span> <span>console.log('Hello world. Status code returned: ', statusCode); </span> <span>} </span> <span>}) </span> <span>.catch(function (err) { </span> <span>console.log('Error: ', err); </span> <span>}) </span> <span>// Always close the Horseman instance </span> <span>// Otherwise you might end up with orphaned phantom processes </span> <span>.close(); </span><span>}; </span>使用骑手屏幕截图
>我想证明的最终用例是您将如何使用Horseman拍摄屏幕截图。我们可以使用Horseman的ScreenShotBase64()方法来完成此操作,该方法返回代表屏幕截图的base64编码字符串。
与我们上一个示例一样,我们必须首先在操作目录中添加一个新模块:
,然后在run.js中为新操作添加一个钩子:
>
<span>var phantomInstance = new Horseman({ </span> <span>phantomPath: '/usr/local/bin/phantomjs', </span> <span>loadImages: true, </span> <span>injectJquery: true, </span> <span>webSecurity: true, </span> <span>ignoreSSLErrors: true </span><span>}); </span> <span>performAction(phantomInstance, ...); </span>现在,您可以使用以下命令进行屏幕截图:
>
$ <span>node run.js -x create_repo </span>>使用base64编码字符串的原因(例如,保存实际图像)是它们是表示原始图像数据的便捷方法。这个堆叠式的答案更详细。
>
如果要保存实际映像,则使用屏幕截图()方法。module<span>.exports = function (phantomInstance<span>, username, password, repository</span>) { </span> <span>if (!username || !password || !repository) { </span> <span>throw 'You must specify login credentials and a repository name'; </span> <span>} </span> <span>... </span><span>} </span>>
结论
本教程试图展示自定义的CLI微框架和一些基本的逻辑,用于使用Horseman软件包来利用Phantomjs,以爬Node.js爬网。虽然使用CLI框架可能会使许多项目受益,但爬行通常仅限于非常特定的问题域。一个共同的领域是质量保证(QA),可以将爬网用于功能和用户界面测试。另一个领域是安全性,例如,您可能想定期爬网,以检测到它是否已被污损或折衷。
>无论您的项目可能是什么情况,请确保清楚地定义您的目标并尽可能不引人注目。在可能的情况下获得许可,请在最大程度上礼貌,并注意永远不要DDOS。如果您怀疑自己正在产生大量的自动流量,那么您可能会重新评估您的目标,实施或许可水平。
经常询问的问题(常见问题解答)有关网络爬行的节点和phantomjs骑手Web爬网和Web刮擦之间有什么区别?
Web爬网和Web刮擦是两个不同的过程,尽管它们通常可以互换使用。网络爬行是系统浏览网络的过程,通常由机器人或蜘蛛进行。它涉及索引网站的内容和以下链接到其他网页。另一方面,网络刮擦是从网站提取特定数据的过程。它涉及解析网页的HTML以删除所需的数据。虽然网络爬网是关于导航和索引的,但网络刮擦是关于数据提取的。
异步性质。它允许并发处理,这意味着您可以同时爬网多页。这使其比同步执行的其他语言要快得多。此外,Node.js拥有一个丰富的生态系统,具有许多可以帮助网络爬行的库和工具,例如Phantomjs Horseman。 > Phantomjs Horseman是一个Node.js软件包,可为使用Phantomjs自动化Web浏览器提供高级API。它允许您在网页上执行操作,例如单击链接,填写表单和屏幕截图。这使其成为网络爬网的强大工具,因为它使您可以像人类用户一样与网页进行交互。
> JavaScript渲染如何影响Web爬行?>>我可以使用Web爬网来监视网站上的更改吗? ,网络爬行可用于监视网站上的更改。通过定期爬行网站并将当前状态与以前的状态进行比较,您可以检测任何更改。这对于各种目的可能很有用,例如在电子商务网站上跟踪价格变化或监视新闻网站上的更新。
网络爬行法律?
>>网络爬行的合法性取决于在包括您所处的管辖权以及您爬行的特定网站上的几个因素上。一些网站明确允许Web在其robots.txt文件中爬行,而另一些网站则禁止Web爬网。重要的是要尊重网站的robots.txt文件,并且不要在短时间内用太多请求超载网站的服务器。>
>我如何优化我的网络爬行过程?是优化网络爬行过程的几种方法。一种方法是使用广度优先搜索(BFS)算法,该算法可确保您在进入下一个深度级别之前,在一定深度爬网。另一种方法是根据页面的相关性优先考虑爬网。例如,如果您要抓取电子商务网站,您可能想在博客文章之前爬网。 >是的,使用Phantomjs Horseman,您可以自动登录网站的过程。这使您可以在登录后访问仅访问的页面。但是,您应该意识到这可能违反网站的服务条款。我如何处理网络爬网中的动态内容?>处理动态内容在Web Crawling中可能具有挑战性,作为传统Web爬网仅解析网页的静态HTML。但是,使用Phantomjs Horseman之类的工具,您可以像人类用户一样渲染JavaScript并与动态内容进行交互。这使您可以从严重依赖JavaScript进行内容生成的网站上爬网和提取数据。>>如何阻止我的网络爬行者被阻塞?一种方法是尊重网站的robots.txt文件,该文件提供了有关您允许爬网的哪些部分的指南。另一种方法是限制您将请求发送到网站的速率,以避免服务器超载。您也可以旋转IP地址和用户代理以避免被检测为机器人。>
>我可以使用Web爬网来监视网站上的更改吗? ,网络爬行可用于监视网站上的更改。通过定期爬行网站并将当前状态与以前的状态进行比较,您可以检测任何更改。这对于各种目的可能很有用,例如在电子商务网站上跟踪价格变化或监视新闻网站上的更新。
网络爬行法律?
>>网络爬行的合法性取决于在包括您所处的管辖权以及您爬行的特定网站上的几个因素上。一些网站明确允许Web在其robots.txt文件中爬行,而另一些网站则禁止Web爬网。重要的是要尊重网站的robots.txt文件,并且不要在短时间内用太多请求超载网站的服务器。>
>我如何优化我的网络爬行过程?是优化网络爬行过程的几种方法。一种方法是使用广度优先搜索(BFS)算法,该算法可确保您在进入下一个深度级别之前,在一定深度爬网。另一种方法是根据页面的相关性优先考虑爬网。例如,如果您要抓取电子商务网站,您可能想在博客文章之前爬网。 >是的,使用Phantomjs Horseman,您可以自动登录网站的过程。这使您可以在登录后访问仅访问的页面。但是,您应该意识到这可能违反网站的服务条款。我如何处理网络爬网中的动态内容?>处理动态内容在Web Crawling中可能具有挑战性,作为传统Web爬网仅解析网页的静态HTML。但是,使用Phantomjs Horseman之类的工具,您可以像人类用户一样渲染JavaScript并与动态内容进行交互。这使您可以从严重依赖JavaScript进行内容生成的网站上爬网和提取数据。>>如何阻止我的网络爬行者被阻塞?一种方法是尊重网站的robots.txt文件,该文件提供了有关您允许爬网的哪些部分的指南。另一种方法是限制您将请求发送到网站的速率,以避免服务器超载。您也可以旋转IP地址和用户代理以避免被检测为机器人。>
>如何阻止我的网络爬行者被阻塞?一种方法是尊重网站的robots.txt文件,该文件提供了有关您允许爬网的哪些部分的指南。另一种方法是限制您将请求发送到网站的速率,以避免服务器超载。您也可以旋转IP地址和用户代理以避免被检测为机器人。>
以上是网络与节点,phantomjs和骑手一起爬行的详细内容。更多信息请关注PHP中文网其他相关文章!

JavaScript在网站、移动应用、桌面应用和服务器端编程中均有广泛应用。1)在网站开发中,JavaScript与HTML、CSS一起操作DOM,实现动态效果,并支持如jQuery、React等框架。2)通过ReactNative和Ionic,JavaScript用于开发跨平台移动应用。3)Electron框架使JavaScript能构建桌面应用。4)Node.js让JavaScript在服务器端运行,支持高并发请求。

Python更适合数据科学和自动化,JavaScript更适合前端和全栈开发。1.Python在数据科学和机器学习中表现出色,使用NumPy、Pandas等库进行数据处理和建模。2.Python在自动化和脚本编写方面简洁高效。3.JavaScript在前端开发中不可或缺,用于构建动态网页和单页面应用。4.JavaScript通过Node.js在后端开发中发挥作用,支持全栈开发。

C和C 在JavaScript引擎中扮演了至关重要的角色,主要用于实现解释器和JIT编译器。 1)C 用于解析JavaScript源码并生成抽象语法树。 2)C 负责生成和执行字节码。 3)C 实现JIT编译器,在运行时优化和编译热点代码,显着提高JavaScript的执行效率。

JavaScript在现实世界中的应用包括前端和后端开发。1)通过构建TODO列表应用展示前端应用,涉及DOM操作和事件处理。2)通过Node.js和Express构建RESTfulAPI展示后端应用。

JavaScript在Web开发中的主要用途包括客户端交互、表单验证和异步通信。1)通过DOM操作实现动态内容更新和用户交互;2)在用户提交数据前进行客户端验证,提高用户体验;3)通过AJAX技术实现与服务器的无刷新通信。

理解JavaScript引擎内部工作原理对开发者重要,因为它能帮助编写更高效的代码并理解性能瓶颈和优化策略。1)引擎的工作流程包括解析、编译和执行三个阶段;2)执行过程中,引擎会进行动态优化,如内联缓存和隐藏类;3)最佳实践包括避免全局变量、优化循环、使用const和let,以及避免过度使用闭包。

Python更适合初学者,学习曲线平缓,语法简洁;JavaScript适合前端开发,学习曲线较陡,语法灵活。1.Python语法直观,适用于数据科学和后端开发。2.JavaScript灵活,广泛用于前端和服务器端编程。

Python和JavaScript在社区、库和资源方面的对比各有优劣。1)Python社区友好,适合初学者,但前端开发资源不如JavaScript丰富。2)Python在数据科学和机器学习库方面强大,JavaScript则在前端开发库和框架上更胜一筹。3)两者的学习资源都丰富,但Python适合从官方文档开始,JavaScript则以MDNWebDocs为佳。选择应基于项目需求和个人兴趣。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

VSCode Windows 64位 下载
微软推出的免费、功能强大的一款IDE编辑器

DVWA
Damn Vulnerable Web App (DVWA) 是一个PHP/MySQL的Web应用程序,非常容易受到攻击。它的主要目标是成为安全专业人员在合法环境中测试自己的技能和工具的辅助工具,帮助Web开发人员更好地理解保护Web应用程序的过程,并帮助教师/学生在课堂环境中教授/学习Web应用程序安全。DVWA的目标是通过简单直接的界面练习一些最常见的Web漏洞,难度各不相同。请注意,该软件中

PhpStorm Mac 版本
最新(2018.2.1 )专业的PHP集成开发工具

SublimeText3 英文版
推荐:为Win版本,支持代码提示!

Atom编辑器mac版下载
最流行的的开源编辑器