以角度通用的方式检测网站页面中的网络爬虫

or1*_*456 1 web-crawler universal server-side-rendering angular

我想检测服务器端呈现的页面的当前请求 -ssr来自网络爬虫或普通用户。
我想在网络爬虫中做一些事情,而不是当它是用户时做。
我想ng-in-viewport在网络爬虫访问页面时运行以获取完整数据。
但不要在用户使用我的页面时运行。
如何检测这个东西?

小智 5

最近我遇到了和你一样的挑战。我的 Angular 应用程序有 SSR,我使用 StateTransfer,以避免在用户刚刚看到来自服务器的渲染内容后在浏览器中进行相同的 API 调用。

我有一个视图计数器,由于页面是在服务器端呈现的,我想避免计算爬虫产生的视图。

所以,我最终得到的是:

server.ts(这是 Angular SSR 的标准生成文件)确保您从 express 传递请求对象,我有这样的:

server.get('*', (req, res) => {
  res.render(indexHtml, {
    req, // Express request
    res, // Express response
    providers: [
      { provide: APP_BASE_HREF, useValue: req.baseUrl },
    ],
  });
});
Run Code Online (Sandbox Code Playgroud)

然后在constants.ts您希望保留常量的任何地方,添加VIEWER注入令牌和可能的爬虫列表:

export const VIEWER = new InjectionToken<string>('viewer');
export const CRAWLER_AGENTS = [
  'googlebot', 'yandexbot', 'yahoo', 'bingbot',
  'baiduspider', 'facebookexternalhit', 'twitterbot', 'rogerbot',
  'linkedinbot', 'embedly', 'quora link preview', 'showyoubot', 'outbrain',
  'pinterest/0.', 'developers.google.com/+/web/snippet',
  'slackbot', 'vkshare', 'w3c_validator', 'redditbot', 'applebot',
  'whatsapp', 'flipboard', 'tumblr', 'bitlybot', 'skypeuripreview',
  'nuzzel', 'discordbot', 'google page speed'
];
Run Code Online (Sandbox Code Playgroud)

然后在我app.module.ts的供应商中,我添加了新的供应商,如果这是机器人或用户,它将包含信息:

import { NgModule, Optional, PLATFORM_ID } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
import { REQUEST } from '@nguniversal/express-engine/tokens';
import { CRAWLER_AGENTS, VIEWER } from './constants';

@NgModule({
  imports: [ /* ... */ ],
  declarations: [ /* ... */ ],
  providers: [
    {
      provide: VIEWER,
      useFactory: viewerFactory,
      deps: [PLATFORM_ID, [new Optional(), REQUEST]],
    },
  ],
})
export class AppModule {}

export function viewerFactory(platformId, req: Request): string {
  if (isPlatformBrowser(platformId)) {
    return 'user';
  }
  const userAgent = (req.get('user-agent') || '').toLowerCase();
  const isCrawler = CRAWLER_AGENTS.some(crawlerAgent => userAgent.indexOf(crawlerAgent) !== -1);
  return isCrawler ? 'bot' : 'user';
}
Run Code Online (Sandbox Code Playgroud)

是的,根据Angular 文档,您可以将 provider 的依赖项作为数组传递。我们需要Optional防止应用程序在客户端崩溃。显然 Express 请求对象在那里不存在。

然后在您的页面组件中,您可以像这样检查查看器:

import { Component, Inject, Optional } from '@angular/core';

@Component({
  selector: 'app-article-page',
  templateUrl: './article-page.component.html',
  styleUrls: ['./article-page.component.scss'],
})
export class ArticlePageComponent {
  constructor(
    @Optional() @Inject(VIEWER) private viewer,
  ) {
    const countViews = this.viewer !== 'bot';
  }
}
Run Code Online (Sandbox Code Playgroud)

请,如果您发现我的回答有帮助,请不要忘记将其标记为已接受。