首页 >web前端 >js教程 >网络与节点,phantomjs和骑手一起爬行

网络与节点,phantomjs和骑手一起爬行

Jennifer Aniston
Jennifer Aniston原创
2025-02-18 11:57:10207浏览

网络与节点,phantomjs和骑手一起爬行

钥匙要点

  • >利用node.js和npm有效地为Web爬网和其他命令行任务设置自定义CLI缩影。>
  • >使用Phantomjs和Horseman软件包来模拟浏览器中的用户互动,从而增强了自动化的Web爬行功能。
  • 结合了骑士方法的链接,以执行复杂的动作序列,从而在网页中进行动态交互。
  • 利用骑士中的evaluate()方法直接从DOM中提取灵活的脚本和数据提取,可用于诸如污损检测之类的任务。
  • >利用Horseman的屏幕截图功能在网上爬行期间捕获和保存屏幕截图,以帮助视觉QA测试等任务。
  • >确保每次使用后都关闭骑士实例,以防止孤立的phantomjs过程,保持系统性能和稳定性。
  • >
>本文由卢卡斯·怀特(Lukas White)进行了同行评审。感谢SitePoint所有的同行评审员制作SitePoint内容的最佳功能! 在项目过程中,发现自己需要编写自定义脚本以执行各种操作是很普遍的。这种通常通过命令行(CLI)执行的一次性脚本几乎可用于任何类型的任务。这些年来编写了许多这样的脚本后,我已经成长为欣赏花费少量时间的价值,以实现定制的CLI微框架来促进这一过程。幸运的是,Node.js及其广泛的包装生态系统NPM使它很容易做到这一点。无论是解析文本文件还是运行ETL,都可以使用惯例,使以高效且结构化的方式添加新功能变得容易。> >不一定与命令行相关,但网络爬行通常用于某些问题域,例如自动化功能测试和污损检测。本教程演示了如何实施轻量级的CLI框架,其支持的行动围绕着网络爬行。希望这将使您的创意果汁流动,无论您的兴趣是爬行还是指挥专线。涵盖的技术包括node.js,phantomjs,以及与爬行和CLI有关的各种NPM软件包。

可以在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>
> 使用骑兵

爬行

Horseman是一个node.js软件包,提供了一个强大的接口,用于创建和与phantomjs进程进行交互。对骑士及其功能的全面解释将需要其自己的文章,但足以说,它使您可以轻松地模拟人类用户在浏览器中可能表现出的任何行为。 Horseman提供了广泛的配置选项,包括自动注入jQuery和忽略SSL证书警告之类的东西。它还为曲奇处理和拍摄屏幕截图提供了功能。

>每次我们通过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>

复合互动的骑士方法网络与节点,phantomjs和骑手一起爬行 到目前为止,我们已经研究了非常简单的骑士用法,但是当我们将其方法链接在一起以在浏览器中执行一系列操作时,包装可以做得更多。为了演示其中一些功能,让我们定义一个动作,该操作模拟了通过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进行网络爬行?

异步性质。它允许并发处理,这意味着您可以同时爬网多页。这使其比同步执行的其他语言要快得多。此外,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地址和用户代理以避免被检测为机器人。>

以上是网络与节点,phantomjs和骑手一起爬行的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn