跳到内容

使用 C# 进行网页抓取时如何忽略非 HTML URL

介绍

网络爬行是以编程方式访问网页并提取其内容和传出链接以递归地爬行网站的过程。在构建网络爬虫时,重要的是仅获取和解析实际的 HTML 网页,而忽略其他类型的文件,如图像、视频、PDF 等。本文将介绍两种在 C# 网络中过滤掉非 HTML URL 的有效方法爬虫:

  1. 根据不需要的文件扩展名列表检查 URL 后缀
  2. 执行轻量级 HEAD 请求并检查 Content-Type 响应标头

通过实施这些技术,您可以提高爬虫程序的效率并避免不必要的请求和处理。让我们深入研究每种方法的细节,看看如何在实践中应用它们。

方法 1:检查 URL 后缀是否存在不需要的文件扩展名

忽略非 HTML URL 的一种简单方法是查看 URL 字符串末尾的文件扩展名。您可以维护用于图像、媒体文件、文档和其他非网页资产的常用扩展名列表。然后,在获取 URL 之前,提取其后缀,如果它与这些扩展名之一匹配,则跳过它。

下面的代码片段展示了如何在 C# 中使用此方法过滤 URL:

HashSet<string> UnwantedExtensions = new HashSet<string> { 
  "jpg", "jpeg", "png", "gif", "bmp", "tiff",  // Images
  "mp4", "avi", "mov", "wmv", "flv", "webm",   // Videos 
  "mp3", "wav", "aac", "flac", "ogg",          // Audio
  "pdf", "doc", "docx", "xls", "xlsx", "ppt",  // Documents
  "zip", "tar", "gz", "rar", "7z"              // Archives
}; 

Uri uri = new Uri("http://example.com/image.jpg");
string extension = Path.GetExtension(uri.AbsolutePath).ToLower().TrimStart(‘.‘);

if (UnwantedExtensions.Contains(extension))
{
   Console.WriteLine($"Skipping URL with extension ‘{extension}‘: {uri}");
}
else 
{
   Console.WriteLine($"Fetching URL: {uri}");
   // Crawl the HTML page...
}

这段代码定义了一个 HashSet 不需要的文件扩展名,然后对于给定的 URL,它使用提取扩展名 Path.GetExtension()。如果小写、点修剪的扩展名存在于 UnwantedExtensions 设置后,该 URL 将被跳过。否则,它将作为 HTML 页面进行获取和爬网。

这种方法的一大优点是速度非常快——只需对每个 URL 进行简单的字符串操作。缺点是它依赖于具有正确文件扩展名的 URL,但情况可能并非总是如此。也可以使用 HTML 页面 .asp or .php 我们想要抓取但可能会被过滤掉的扩展程序。

方法 2:执行 HEAD 请求并检查 Content-Type 标头

一种更强大但速度稍慢的方法是对每个 URL 执行轻量级 HEAD 请求并检查响应中的 Content-Type 标头。 HEAD 请求就像 GET 请求一样,只是它要求服务器仅返回响应标头而不返回实际内容。

Content-Type 标头指示所请求资源的媒体类型。对于 HTML 页面,内容类型通常为“text/html”。通过检查此标头值,您可以更可靠地确定 URL 是否指向 HTML 页面或某种其他类型的文件。

以下是在 C# 中实现此功能的方法:

HttpClient httpClient = new HttpClient();

Uri uri = new Uri("http://example.com/page");
HttpRequestMessage headRequest = new HttpRequestMessage(HttpMethod.Head, uri);
HttpResponseMessage response = await httpClient.SendAsync(headRequest);

string contentType = response.Content.Headers.ContentType?.MediaType;

if (contentType == "text/html")
{
   Console.WriteLine($"Fetching HTML page: {uri}");
   // Crawl the HTML page...
}  
else
{
   Console.WriteLine($"Skipping non-HTML URL with Content-Type ‘{contentType}‘: {uri}");
}

这会使用以下命令发送异步 HEAD 请求 HttpClient 并从响应中检索 Content-Type 标头。如果媒体类型是“text/html”,则将获取 URL 并将其解析为 HTML 页面。否则,它将被跳过并记录非 HTML 内容类型。

HEAD 请求的优点是它们可以直接从服务器为您提供内容类型的更明确的答案。潜在的缺点是到服务器的往返会产生额外的延迟,这会增加大量 URL。然而,HEAD 请求通常非常快,因为不返回任何内容。

结合两种方法以获得最大效果

为了获得最佳覆盖率和效率,我建议在 C# 网络爬虫中同时使用上述两种方法。通过首先根据拒绝列表检查 URL 扩展名,您可以快速过滤掉明显的非 HTML URL,而无需任何请求。然后,对于通过该检查的 URL,您可以执行 HEAD 请求来验证它实际上是一个 HTML 页面,然后再完全获取它。

将所有内容放在一起,核心爬行逻辑可能如下所示:

public async Task Crawl(Uri uri) 
{
  string extension = Path.GetExtension(uri.AbsolutePath).ToLower().TrimStart(‘.‘);

  if (UnwantedExtensions.Contains(extension))
  {
    Console.WriteLine($"Skipping URL with unwanted extension ‘{extension}‘: {uri}");
    return;
  }

  if (VisitedUrls.Contains(uri))
  {
    Console.WriteLine($"Skipping already visited URL: {uri}");
    return;
  }

  HttpRequestMessage headRequest = new HttpRequestMessage(HttpMethod.Head, uri);
  HttpResponseMessage headResponse = await _httpClient.SendAsync(headRequest);

  string contentType = headResponse.Content.Headers.ContentType?.MediaType;

  if (contentType != "text/html")
  {    
    Console.WriteLine($"Skipping non-HTML URL with Content-Type ‘{contentType}‘: {uri}");
    return;
  }

  VisitedUrls.Add(uri);

  HttpResponseMessage getResponse = await _httpClient.GetAsync(uri);
  string content = await getResponse.Content.ReadAsStringAsync();

  Console.WriteLine($"Crawled URL: {uri}");

  // Parse links from HTML and queue them for crawling
  CrawlQueue.Enqueue(ExtractLinks(uri, content));
}

本篇 Crawl 方法首先检查 URL 的文件扩展名,如果它位于不需要的扩展名哈希集中,则跳过它。然后它会检查该 URL 是否已被访问过,如果是,则跳过它。接下来,它执行 HEAD 请求并验证 Content-Type 是否为 HTML,然后再将 URL 添加到 VisitedUrls hashset,完全获取内容,并解析出链接以排队等待进一步抓取。

像这样一起使用,扩展过滤和 HEAD 请求提供了有效的一二打法,用于在爬行时忽略非 HTML 内容。扩展检查是一个快速的初步过滤器,而 HEAD 请求是提交全页获取之前的最终确认。

其他注意事项和最佳实践

除了过滤非 HTML URL 之外,在构建行为良好且高效的网络爬虫时,还需要记住其他一些重要事项:

  • 始终遵守 robots.txt 规则,不要抓取不允许的页面。您可以在抓取之前解析 robots.txt 文件并检查其 URL。

  • 限制抓取速度和并发请求数量,以避免服务器过载。一个好的准则是每个域每秒不超过一个请求。

  • 妥善处理 HTTP 状态代码、超时和错误。使用指数退避重试失败并知道何时放弃。

  • 使用哈希集、数据库或高效的数据结构跟踪已访问过的 URL,以避免重新抓取重复内容。布隆过滤器是一个很好的节省空间的选择。

通过遵循这些实践并实现纯 HTML 过滤,您将能够顺利地使用 C# 构建礼貌且专注的网络爬虫。本文中介绍的技术应该能够为您提供所需的一切,以避免出现不相关的内容并专注于您关心的 HTML 页面。

结论

网络爬虫是探索和分析网站内容的强大工具,但为了高效和礼貌,它们必须专注于实际的 HTML 页面并跳过其他类型的 URL。在本文中,我们学习了两种在 C# 爬虫中执行此操作的互补技术:

  1. 过滤掉不需要的 URL 扩展
  2. 使用 HEAD 请求检查 Content-Type 标头

我们详细介绍了如何实现这两种方法,然后了解如何将它们组合起来以获得最完整的覆盖范围。我们还讨论了其他一些爬虫最佳实践,例如尊重 robots.txt 和限制请求率。

希望您现在已经充分了解如何有效地忽略网络爬虫中的非 HTML URL。应用这些技术将有助于保持爬虫快速且专注,同时避免服务器上不必要的负载。

您可能需要查看以下一些其他资源以了解更多信息:

快乐(选择性)爬行!

加入谈话

您的电邮地址不会被公开。 必填带 *